0

我正在制作类似模拟城市的游戏。有很多瓷砖。我刚开始的时候。我只是在使用一个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 对象。它效果很好,但我一次只能在舞台上拥有这么多。否则当我滚动时它移动缓慢。我需要比精灵更轻的东西,但我仍然可以变成一个对象来进行交互。有人有想法么 ???

4

3 回答 3

1

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

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

当用户单击包含位图数据的 DisplayObject(使用位图填充绘制位图或包装位图的 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 类不是显示对象,但具有worldXworldY属性,指示它在世界中的位置。它的宽度高度属性定义了它的尺寸。

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

于 2010-01-01T10:37:32.200 回答
0

我一直在读这本关于等轴测图的好书。他们展示了在 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-01-03T18:48:22.843 回答
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 之前是等距的。我想知道是否有可能在方形瓷砖上产生等距错觉。

于 2010-01-01T15:51:05.207 回答