【问题标题】:Finding Something lighter than Sprites!找到比 Sprites 更轻的东西!
【发布时间】:2010-01-01 04:36:10
【问题描述】:

我正在制作类似模拟城市的游戏。有很多瓷砖。我刚开始的时候。我只是在使用一个tilesheet。我正在从 tilesheet 中复制必要的部分。到一个空白的 bitMapData。然后我将 bitMapData 放入一个 bitMap 中,然后将它放入一个 DisplayObject 中。效果很好!

tileSheet:BitMapData  <----- data is already in
loop { loop through and tiled
bg:bitMapData= new bitMapData();
bg.copyPixel(tileSheet,rect,point);
}

canvas.BitMap(bg);
addChild(canvas);

唯一的问题是我需要让我的图块具有交互性。我需要突出显示它们并更改颜色和东西。所以我使用了 Sprite 对象。它效果很好,但我一次只能在舞台上拥有这么多。否则当我滚动时它移动缓慢。我需要比精灵更轻的东西,但我仍然可以变成一个对象来进行交互。谁有什么想法???

【问题讨论】:

    标签: actionscript-3 bitmap sprite


    【解决方案1】:

    如果您有很多图块,则会影响性能,因为 Flash 需要更新大量显示对象的转换(这在内部意味着大量矩阵计算,以及随后大屏幕区域的重绘。)

    还有另一种实现交互性的方法,如果您发现必须使用单个位图数据来提高性能。在内存中保留一个“抽象”(即非图形)数据模型,用于存储您的游戏状态。确保您能够从商店中读取某个元素在游戏世界中的位置。然后您可以使用平面位图数据来渲染游戏世界,因为各个位置都存储在其他位置。

    当用户单击包含位图数据(使用位图填充绘制位图或包装位图的 Sprite)的 DisplayObject 时,查看您的模型中的哪些游戏元素被该点击击中。

    // myTileSprite is a Sprite with a bitmap fill
    myTileSprite.addEventListener(MouseEvent.CLICK, handleWorldClick);
    
    function handleWorldClick(ev : MouseEvent) : void
    {
      var i : int;
    
      // Loop through all game element data models
      for (i=0; i<myGameElements.length; i++) {
        // Test the mouse position against the element model
        if (myGameElements[i].hitTest(myTileSprite.mouseX, myTileSprite.mouseY)) {
          trace('this was the element that was clicked: '+myGameElements[i].toString());
        }
      }
    }
    

    在这里,每当玩家点击世界图形时,循环都会尝试找到鼠标位置正下方的那个元素。当然,您需要在所有游戏元素数据模型上实现 hitTest() 方法。这种方法只是检查提供的世界空间位置与图块的区域:

    // GameElement.hitTest():
    /**
    * Tests a world position against the position and area of this game
    * element tile. Returns a boolean indicating whether this tile was hit.
    */
    public function hitTest(mouseX : Number, mouseY : Number) : void
    {
      var rect : Rectangle = new Rectangle(this.worldX, this.worldY, this.width, this.height);
    
      if (mouseX > rect.left && mouseX < rect.right
        && mouseY > rect.top && mouseY < rect.top) {
        return true;
      }
      else return false;
    }
    

    GameElement 类不是 一个显示对象,但具有worldXworldY 属性来指示它在世界中的位置。它的 widthheight 属性定义了它的尺寸。

    这里的技巧是确保渲染的位图和您的模型存储同步,以便位图上的图块位置真正对应于数据模型中的 worldX/worldY 属性。

    【讨论】:

    • 我领先你一步。请看我上面的回复。
    • 我有点明白你在说什么。 myTileSprite 是我的瓷砖支架,它将容纳我所有的瓷砖来创造世界。当我单击它时,它会检查我在地图上单击的位置。我猜 myGameElements[i] 代表我的瓷砖的每个单独的数据表示。对于我来说,这可能必须是一些不可见的显示对象才能进行 hittest();就像没有位图填充的精灵。我会按照我渲染位图图像的确切方式来渲染它。我不确定我的方向是否正确。
    • 您的数据模型不应该是显示对象。这就是将数据与视图(单个位图数据)分离的整个想法。想法是您将在模型上创建自己的 hitTest() 方法,其中包含适用于您的特定情况的逻辑。您可以随意调用它,例如 myHitTest() 或 isUnderPoint() 或其他任何名称。
    【解决方案2】:

    我比你领先一步。这是一个好主意。当瓷砖被平方时,它更容易保持世界的数据表示。因此,我可以使用 mouseX/tileWidth,这就是我从左到右移动了多少列。与 Y 轴相同。

    不仅如此,坐标还从左上角开始。

    但我的问题是我的瓷砖是等距的。所以不是 X 轴开始像...

      012345678
    0
    1
    2
    3
    4
    5
    6
    7
    8
    

    我的图块对齐...

                           00
                          1  1
                         2     2
                        3       3
                       4         4
                      5            6
    

    有点草率。但是右边代表y轴,左边代表x轴。并且中心原点在屏幕的中心。不在左上角。我试图弄清楚如何测量我的鼠标从中心到两侧的位置。这听起来极其困难。我不确定它是否可能。游戏应该是像模拟城市一样的游戏。第一个模拟城市是正方形而不是等距的。我不认为他们在开始使用 3d 之前是等距的。我想知道是否有可能在方形瓷砖上产生等距错觉。

    【讨论】:

      【解决方案3】:

      我一直在阅读这本关于等轴测图的好书。他们展示了在 3d 空间中计算图块。甚至还可以在 3d 空间中计算鼠标。这是代码。它很多,但我希望其他人比我更了解它。这本书是由 jobe makar 写的关于构建多人游戏世界的。我想分享它,因为就放入其中的代码量而言,它的代码非常简单。只需要 2 节课。我对三角学不太擅长。所以我无法真正解释数学是如何得出结果的。希望有人可以为我解释一下:D。

      没有给出 Y 坐标,因为宽度等于高度。坐标方法只是一个自定义的点类,它包含 x、y 和 z。

      package com.gamebook.grid {
          import com.gamebook.utils.geom.Coordinate;
          import com.gamebook.utils.Isometric;
          import flash.display.MovieClip;
          import flash.events.MouseEvent;
      
          /**
           * ...
           * @author Jobe Makar - jobe@electrotank.com
           */
          public class Map extends MovieClip{
      
              private var _grid:Array;
              private var _iso:Isometric;
              private var _tileWidthOnScreen:int;
              private var _tileHeightOnScreen:int;
              private var _tileWidth:Number;
              private var _tileHeight:Number;
              private var _cols:int;
              private var _rows:int;
      
              private var _lastTile:Tile;
      
              public function Map() {
                  initialize();
              }
      
              private function initialize():void{
                  _iso = new Isometric();
      
      
                  //when mapped to the screen the tile makes a diamond of these dimensions
                  _tileWidthOnScreen = 64;
                  _tileHeightOnScreen = 32;
      
                  //figure out the width of the tile in 3D space
                  _tileWidth = _iso.mapToIsoWorld(64, 0).x;
      
                  //the tile is a square in 3D space so the height matches the width
                  _tileHeight = _tileWidth;
      
                  buildGrid();
      
                  addEventListener(MouseEvent.MOUSE_MOVE, mouseMoved);
              }
      
              private function mouseMoved(e:MouseEvent):void {
                  if (_lastTile != null) {
                      _lastTile.alpha = 1;
                      _lastTile = null;
                  }
      
                  var coord:Coordinate = _iso.mapToIsoWorld(mouseX, mouseY);
                  var col:int = Math.floor(coord.x / _tileWidth);
                  var row:int = Math.floor(Math.abs(coord.z / _tileHeight));
      
                  if (col < _cols && row < _rows) {
                      var tile:Tile = getTile(col, row);
                      tile.alpha = .5;
                      _lastTile = tile;
                  }
              }
      
              private function buildGrid():void{
                  _grid = [];
                  _cols = 10;
                  _rows = 10;
                  for (var i:int = 0; i < _cols;++i) {
                      _grid[i] = [];
                      for (var j:int = 0; j < _rows;++j) {
                          var t:Tile = new Tile();
      
                          var tx:Number = i * _tileWidth;
                          var tz:Number = -j * _tileHeight;
      
                          var coord:Coordinate = _iso.mapToScreen(tx, 0, tz);
      
                          t.x = coord.x;
                          t.y = coord.y;
      
                          _grid[i][j] = t;
      
                          addChild(t);
                      }
                  }
              }
      
              private function getTile(col:int, row:int):Tile {
                  return _grid[col][row];
              }
      
          }
      
      }
      

      然后我们就有了计算 3d 空间的等距类。

      包 com.gamebook.utils { 导入 com.gamebook.utils.geom.Coordinate;

      /**
       * @author Jobe Makar - jobe@electrotank.com
       */
      public class Isometric {
      
          //trigonometric values stored for later use
          private var _sinTheta:Number;
          private var _cosTheta:Number;
          private var _sinAlpha:Number;
          private var _cosAlpha:Number;
      
          /**
           * Isometric class contrustor.
           * @param   declination value. Defaults to the most common value, which is 30.
           */
          public function Isometric() {
              var theta:Number = 30;//even though the tiles are already isometric, you still have to put the degrees the tiles will be turned.
              var alpha:Number = 45;//45 degrees on y axis, 30 dgrees on x axis
              theta *= Math.PI/180; // then you translate to radians
              alpha *= Math.PI/180;
              _sinTheta = Math.sin(theta);
              _cosTheta = Math.cos(theta);
              _sinAlpha = Math.sin(alpha);
              _cosAlpha = Math.cos(alpha);
          }
      
          /**
           * Maps 3D coordinates to the 2D screen
           * @param   x coordinate
           * @param   y coordinate
           * @param   z coordinate
           * @return  Coordinate instance containig screen x and screen y
           */
          public function mapToScreen(xpp:Number, ypp:Number, zpp:Number):Coordinate {
              var yp:Number = ypp;
              var xp:Number = xpp*_cosAlpha+zpp*_sinAlpha;
              var zp:Number = zpp*_cosAlpha-xpp*_sinAlpha;
              var x:Number = xp;
              var y:Number = yp*_cosTheta-zp*_sinTheta;
              return new Coordinate(x, y, 0);
          }
      
          /**
           * Maps 2D screen coordinates into 3D coordinates. It is assumed that the target 3D y coordinate is 0.
           * @param   screen x coordinate
           * @param   screen y coordinate
           * @return  Coordinate instance containig 3D x, y, and z
           */
          public function mapToIsoWorld(screenX:Number, screenY:Number):Coordinate {
              var z:Number = (screenX/_cosAlpha-screenY/(_sinAlpha*_sinTheta))*(1/(_cosAlpha/_sinAlpha+_sinAlpha/_cosAlpha));
              var x:Number = (1/_cosAlpha)*(screenX-z*_sinAlpha);
              return new Coordinate(x, 0, z);
          }
      
      }
      

      }

      【讨论】:

        猜你喜欢
        • 2010-11-24
        • 1970-01-01
        • 2010-10-05
        • 2012-04-15
        • 2015-07-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多