0

これは as3 と FlashPunk で書かれています。

私の問題?4 方向に 4 タイルを移動できる戦車があります。北、南、東、西。

画像はhttp://www.aroderick.com/isolatedTiles.jpgにあります。

正方形のグリッド (画像では灰色) から始めて、配列を使用して正方形のグリッドから菱形のパターン (画像では赤) をマークしました。これは、タンクが移動できることを考えると、すべての可能な移動の選択肢です。 4方向に4スペース。画像に数字が付いているタイルは、ゲームで実際に表示されるタイルです。数字は「列の列」の数字です。

もう少し複雑なのは、障害物 (水、木、山) があるダイヤモンドからタイルを削除したことです。これにより、障害物を越えてタイルに到達するための移動コストが増加します。

この時点で、これは A* アルゴリズムに基づいており、移動に A* を使用していますが、これらは移動先のタイルを選択する前に確立する必要がある移動の選択肢です。

私の問題は、タンクの移動能力を超えており、タイルが結合されて A * の完全なパスを作成し、タンクをあるタイルから次のタイルに移動できる主な移動領域から独自に分離されている孤立したタイルです。

これらの不正なタイルに対処する (取り除く) シンプルでエレガントな方法はありますか?

私はルールのシステムを試しました。

    //same row going east           
    if(ob.row == co.row && ob.row == startNode.row && ob.col < co.col && ob.col > startNode.col && ob.c  <  co.c ) 
    {
        extraCost = co.c;
        reason = 1;
        break;
    }
    //same row going west
    else if(ob.row == co.row && ob.row == startNode.row && ob.col > co.col && ob.col < startNode.col && ob.c  <  co.c ) 
    {
        extraCost = co.c;
        reason = 2;
        break;
    }

ここで、「c」は、カラスが飛ぶときのタイルの動き「コスト」を表すプロパティです。しかし、これらは解決するのと同じくらい多くの問題を生み出すようです。

    //reusable tile grid
    public static function makeTileGrid(entityLoc:Point,moveGrid:Array,travelMax:int,tsize:int = 64):Array
    {
        //node list
        var nodeLst:Array = [];
        //counter
        var tileCount:int = 0;
        //for tile naming
        var co_ordX:String = "";
        var co_ordY:String = "";
        if(moveNode == null) var moveNode:Object;
        //subtract the tile range from the current location
        //tile range times two because you can go forewards 
        //or backwards tRange spaces
        for (var col:int = travelMax * 2; col >=0;col--)
        {
            //placeX is an x value so you must multiply both row and tRange by the tile width
            var placeX:Number = entityLoc.x - (travelMax*64 - col*64);
            //trace(placeX);
            for(var row:int = travelMax * 2; row >=0;row--)
            {
                var placeY:Number = entityLoc.y - (travelMax*64 - row*64);

                //trace(moveGrid[col]);

                //use tile grid map array
                if(moveGrid[tileCount] == 1)
                {
                    //use coordinates for the name value e.g. 
                    co_ordX = col.toString();
                    co_ordY = row.toString();
                    moveNode = {col:col,row:row,obst:false,node:co_ordX+"-"+co_ordY,nX:placeX,nY:placeY,ph:0,h:0,g:0,f:0,c:0};
                    nodeLst.push(moveNode);                                             
                }
                tileCount ++;               
            }   
        }
        return nodeLst;
    }

私のグリッドコード。万一に備えて。

みんなありがとう、

ジェームズ-

4

1 に答える 1

1

制限された (距離に関して) 幅優先の A* 検索をそのグリッドのすぐ上で使用し、アルゴリズムで障害物を壁として使用する必要があると思います。これにより、「孤立したタイル」がリストに表示されないように、distance_left 属性が利用可能な一連の到達可能なノードが生成されます。あなたのコードは、パス距離を実際にチェックせずに、開始位置と通過行列からダイヤモンド パターンを取得するように見えます。

public static function getReachableTiles(startTile:Point,distance:int):Array {
    var d:Dictionary=new Dictionary(); // will hold visited tiles point by point
    var o:Object={d:distance,px:startTile.x,py:startTile.y}; // a simple object info
    // add fields as necessary
    var a:Array=new Array(); // output array
    a.push(o);
    d[startTile.y*256+startTile.x]=o; // the simplest hash. You have to ensure 
    // these never overlap for different pairs of [x,y], and the same hash
    // function is used across this method
    while (distance>0) {
        for each (o in a) {
            if (o.d!=distance) continue; // already parsed
            var to:Object={d:distance-1,px:o.x-1,py:o.y};
            if (Game.isPassable(to.x,to.y)&&!d[to.y*256+to.x]) {
                // a new cell, and is valid for the tank to pass
                // "isPassable" returns true if (x,y) corresponds to a passable and 
                // valid position. For example, (-1,2) might return false as it's off borders
                d[to.y*256+to.x]=to; // add to dictionary - a parsed cell
                a.push(to); // and to output
            }
            // doing the same for 3 other possible moves
            to={d:distance-1,px:o.x,py:o.y-1};
            if (Game.isPassable(to.x,to.y)&&!d[to.y*256+to.x]) {
                d[to.y*256+to.x]=to;
                a.push(to);
            }
            to={d:distance-1,px:o.x+1,py:o.y};
            if (Game.isPassable(to.x,to.y)&&!d[to.y*256+to.x]) {
                d[to.y*256+to.x]=to;
                a.push(to);
            }
            to={d:distance-1,px:o.x,py:o.y+1};
            if (Game.isPassable(to.x,to.y)&&!d[to.y*256+to.x]) {
                d[to.y*256+to.x]=to;
                a.push(to);
            }
        } // okay, entire array was parsed for new cells
        distance--; // we've iterated A* once more, lessen the distance
    }
    // at this point, we've iterated A* "distance" times, return
    return a;
}

変数構造に合わせてこのスニペットを調整する必要があります。これGame.isPassable()により、有効な呼び出しが行われ、描画されたマップの下に実際のグリッドが表示されます。startTileはピクセルベースではなく、グリッドベースの座標セットであることに注意してください。お役に立てれば。

于 2013-04-16T13:23:33.447 に答える