寻找比Sprite更轻的东西!

时间:2010-01-01 04:36:10

标签: actionscript-3 bitmap sprite

我正在制作一个类似游戏的模拟城市。有很多瓷砖。我刚开始的时候。我刚刚使用了瓷砖。我正在从瓷砖表中复制必要的馅饼。到一个空白的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对象。它运作得很好,但我现在只能在舞台上有这么多。或者滚动时它移动得很慢。我需要一些更轻松然后一个精灵,但我仍然可以变成一个对象来进行交互。任何人都有任何想法???

3 个答案:

答案 0 :(得分:1)

如果你有很多瓷砖,那会影响性能,因为Flash需要更新很多显示对象的转换(这在内部意味着大量的矩阵计算,以及随后重绘屏幕的大部分区域。)< / p>

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

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

// 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类不是显示对象,但具有 worldX worldY 属性,指示它在世界中的位置。 width height 属性定义了它的尺寸。

来自此处的技巧是确保渲染的位图和模型存储是同步的,这样位图上的位置实际上与数据模型中的worldX / worldY属性相对应。

答案 1 :(得分:0)

我比你领先一步。这是个好主意。当瓦片被平方时,它更容易保持世界的数据表示。因此,我可以使用我的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之前我不认为他们是等距的。我想知道是否有可能在方形瓷砖上创造出等长的幻觉。

答案 2 :(得分:0)

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

由于宽度为=到高度,因此未给出Y坐标。 coordinates方法只是一个定制的Point类,它包含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空间的等距类。

package com.gamebook.utils {     import 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);
    }

}

}