在瓷砖网格上转动基于运动,孤立的瓷砖

时间:2013-04-15 20:40:41

标签: actionscript-3 flash-cs5

这是用as3和FlashPunk编写的。

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

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

找到

我开始使用方形网格(图像上的灰色)并使用数组从方形网格中标出菱形图案(图像中的红色),这是坦克的所有可能的移动选择只能在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”表示作为乌鸦飞行的磁贴移动“成本”的属性。 但这些似乎会产生尽可能多的问题。

    //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;
    }

我的网格代码。如果是。

谢谢你们,

詹姆斯 -

1 个答案:

答案 0 :(得分: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是一组基于网格的坐标,而不是基于像素的坐标。希望这会有所帮助。