0

私はシムシティのようなゲームを作っています。タイルがたくさんあります。私が最初に始めたとき。タイルシートを使っていました。タイルシートから必要なピースをコピーしていました。空白の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をクリックすると、そのクリックによってヒットしたゲーム要素をモデルで確認します。

// 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プロパティがあります。高さのプロパティが寸法を定義します。

これ以降の秘訣は、レンダリングされたビットマップとモデルストレージが同期されていることを確認することです。これにより、ビットマップ上のタイルの位置が、データモデル内のworldX/worldYプロパティに実際に対応します。

于 2010-01-01T10:37:32.200 に答える
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 に答える
0

私は等尺性に関するこの素晴らしい本を読んでいます。それらは、3D空間でタイルを計算することを示しています。また、3D空間でマウスを計算することもできます。これがコードです。それはたくさんありますが、他の誰かが私よりもそれを理解してくれることを願っています。この本は、マルチプレイヤーの世界を構築することについて、jobemakarによって書かれました。コードの量が入る限り、コードは非常に単純なので、共有したいと思いました。必要なクラスは2つだけです。私は三角法が苦手です。だから私は数学がどのように結果を得ているかを本当に解釈することはできません。うまくいけば、誰かが私のためにそれを説明することができます:D。

幅が=から高さであるため、Y座標は指定されていません。座標メソッドは、x、y、zを保持するカスタムメイドのPointクラスです。

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{importcom.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 に答える