这是用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;
}
我的网格代码。如果是。
谢谢你们,
詹姆斯 -
答案 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
是一组基于网格的坐标,而不是基于像素的坐标。希望这会有所帮助。