3

2D 正方グリッド システムで移動を行う最良の方法は何ですか? これは機能しますが、間違っている/醜いようです(以下を参照)。

x x x x x x x
x x x x x x x
x x x O x x x
x x x U x x x
x x x x x x x
x x x x x x x
x x x x x x x

たとえば、U は移動したいユニットで、O は別のユニットや山のような通行できないオブジェクトです。U が 3 タイル移動できる場合、可動領域 (M) は次のようになります。

x x x x x x x
x x M x M x x
x M M O M M x
M M M U M M M
x x M M M M x
x x M M M x x
x x x M x x x

これが私のコードです:

public function possibleMoves(range:uint, cords:Array):void {
var X:uint = cords[0];
var Y:uint = cords[1];

if (range > 0) {
    try {
        theGrid[X + 1][Y].moveable = true;
        if (theGrid[X + 1][Y].getOccupied == false) {
            possibleMoves(range - 1, [X + 1, Y], flag, mtype);
        }
    }   catch (err:Error) { }

    try {
        theGrid[X - 1][Y].moveable = true;
        if (theGrid[X - 1][Y].getOccupied == false) {
            possibleMoves(range - 1, [X - 1, Y], flag, mtype);
        }
    }   catch (err:Error) { }

    try {
        theGrid[X][Y + 1].moveable = true;
        if (theGrid[X][Y + 1].getOccupied == false) {
            possibleMoves(range - 1, [X, Y + 1], flag, mtype);
        }
    }   catch (err:Error) { }

    try {
        theGrid[X][Y - 1].moveable = true;
        if (theGrid[X][Y - 1].getOccupied == false) {
            possibleMoves(range - 1, [X, Y - 1], flag, mtype);
        }
    }   catch (err:Error) { }
}
4

3 に答える 3

6

タイルセットのデータ構造は、あまりにも多くのことを行う「タイル」クラスに強く結合されているようです。theGrid[X][Y].moveable、theGrid[X][Y].getOc​​cupied... + おそらくその他のメソッド。

おそらく、タイルセット データ構造はブール値 (walkable?true/false) のみを格納し、タイルが walkable かどうかを判断する単一のメソッドを持つ必要があります。この場合、ブール値のベクトルで十分です。4 (または対角線で 8) の naerby 値のテストは非常に高速であり、再帰ループを使用して新しく見つかった値にテストを広げることができます。

異なるタイプのタイル (壁、オブジェクト、キャラクターなど) がある場合は、 Booleans ではなく Vector.< int > を使用できます。0 は歩行可能なタイルで、それ以外は禁止エリアになります。これにより、ブール値のチェックが可能になります。0 = false およびその他の値 = true として。

ここでサンプルを作成しましたhttp://wonderfl.net/c/bRV8 ; コードを貼り付けるよりもわかりやすいかもしれません。マウスを動かすと、有効なセルを示す小指の形が表示されます。

  • l.53 は「接続性」です。可能な値は 4 と 8 です。
  • 4つの接続された

コネクティビティ 4

  • 接続された8

コネクティビティ 8

  • l.54 は最大再帰深度です

そのため、再帰は開始点に関係なく実行されます。それは時々予期しない方法でこぼれます。

特定の量の動きを与える必要がある場合、これでは十分ではなく、ある種のパスファインダーをセットアップする必要があります。

編集:提供されたコードは機能しているようですが、次の行で回避しようとする再帰終了のバグが含まれています。これは一部のケースでのみ機能し、キャラクターをマップの端に配置したり、5 以外の移動回数を与えたりすると、非常に奇妙な動作をします。

        var max:int = ( maxDepth * maxDepth );
        if( maxDepth % 2 == 0 )max--;
        recursiveCheck( valid, tilesetClone, 0, max, connexity );

さまざまな再帰の深さでチェックしたところ、バグはすぐに明らかになりました。この例のグリッドと複雑なマップ デザインの欠如により、バグがわかりにくくなっていますが、下のスクリーンショットは次のとおりです。マウスが図のように隅に配置されている場合、フィールドは上に 6 マス、左に 7 マス拡張されていることに注意してください。 5.

ここに画像の説明を入力

于 2011-02-07T13:47:55.747 に答える
2

コードは機能しますが、エレガントとはほど遠いものです。多くのタイルは複数回計算されます。各 gridTile の結果をキャッシュすることで、これを修正できます。

メモ化テクニックをご覧ください。

于 2011-02-07T07:57:12.063 に答える