0

这是用 as3 和 FlashPunk 编写的。

我的问题?我有一个可以在 4 个方向上移动 4 个瓷砖的坦克;北、南、东、西。

图片可在http://www.aroderick.com/isolatedTiles.jpg找到

我从一个方形网格(图像上的 Lt 灰色)开始,并使用一个数组从方形网格中标记出菱形图案(图像上的红色),这是所有可能的移动选择,因为坦克只能移动4个方向4个空格。图像上带有数字的图块是您在游戏中看到的实际图块,数字是“col-row”数字。

更复杂的地方是,我还从有障碍物(水、树木、山脉)的钻石上移除了瓷砖,这反过来又增加了到达障碍物之外的瓷砖的移动成本。

在这一点上我应该提到这是基于 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”aa 属性表示乌鸦飞行时的瓷砖移动“成本”。但这些似乎产生的问题与解决的问题一样多。

    //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 回答