我有代码可以找到从A点到B点的最短路径。为此,我使用的是A星变化。我使用二维数组来表示一个二维网格,但我的路径不采用对角线快捷方式,只有左,右,上和下。到目前为止一切正常,但它并不总能找到最短的路径。我想知道出了什么问题,为什么会出错,以及如何解决它。提前谢谢。
这是一张图片来说明究竟发生了什么:
这是我的代码(路径查找类首先,然后是它的助手类):
BTW:数学向量只不过是一个几何点类,而且playerTileLocation和enemyTileLocation都只是与网格上的起始节点和结束节点相对应的点。另外,我使用AStarNode类作为地图上所有图块的节点,而不是常规对象。package {
import src.Characters.Character;
import src.InGame.Map;
import src.Maths.MathVector;
public final class BaseAI {
// REPRESENTS UP, DOWN, RIGHT, AND LEFT OF ANY ONE NODE
private static const bordersOfNode:Array = new Array(
new MathVector( -1, 0), new MathVector(1, 0), new MathVector(0, -1), new MathVector(0, 1));
private var _player:Character;
private var map:Map;
private var playerTileLocation:MathVector;
private var openList:Array;
private var closedList:Array;
// 2D ARRAY OF MAP TILES (I DON'T USE HERE, BUT I PLAN TO IN FUTURE)
private var mapArray:Array;
private var originNode:AStarNode;
private var complete:Boolean;
public function BaseAI(_player:Character,map:Map):void {
this._player = _player;
this.map = map;
openList = new Array();
closedList = new Array();
mapArray = map.tiles;
}
public function get player():Character {
return this._player;
}
public function calculatePlayerTileLocation():void {
playerTileLocation = map.worldToTilePoint(player.groundPosition);
}
//WILL EVENTUAL RETURN A DIRECTION FOR THE ENEMY TO TAKE THAT ITERATION (EVERY 1-2 SECONDS)
public function getDirection(enemy:Character):String {
var enemyTileLocation:MathVector = map.worldToTilePoint(enemy.groundPosition);
originNode = new AStarNode(enemyTileLocation, playerTileLocation);
originNode.setAsOrigin();
openList = [originNode];
closedList = [];
complete = false;
var currentNode:AStarNode;
var examiningNode:AStarNode;
while (!complete) {
openList.sortOn("F", Array.NUMERIC);
currentNode = openList[0];
closedList.push(currentNode);
openList.splice(0, 1);
for (var i in bordersOfNode) {
examiningNode = new AStarNode(new MathVector(currentNode.X + bordersOfNode[i].x, currentNode.Y + bordersOfNode[i].y),playerTileLocation);
if (map.isOpenTile(map.getTile(examiningNode.X, examiningNode.Y)) && !examiningNode.isThisInArray(closedList)) {
if (!examiningNode.isThisInArray(openList)) {
openList.push(examiningNode);
examiningNode.parentNode = currentNode;
}else {
}
if (examiningNode.X == playerTileLocation.x && examiningNode.Y == playerTileLocation.y) {
complete = true;
var done:Boolean = false;
var thisNode:AStarNode;
thisNode = examiningNode;
while (!done) {
if (thisNode.checkIfOrigin()) {
done = true;
}else {
thisNode = thisNode.parentNode;
}
}
}
}
}
}
}
}
}
package {
import src.Maths.MathVector;
internal final class AStarNode {
private var _X:int;
private var _Y:int;
private var _G:int;
private var _H:int;
private var _F:int;
private var _parentNode:AStarNode;
private var _isOrigin:Boolean;
public static const VERTICAL:uint = 10;
public function AStarNode(thisNodeLocation:MathVector, targetNodeLocation:MathVector) {
X = thisNodeLocation.x;
Y = thisNodeLocation.y;
H = Math.abs(X - targetNodeLocation.x) + Math.abs(Y - targetNodeLocation.y);
G = 0;
F = H + G;
}
public function set X(newX:int):void {
this._X = newX;
}
public function get X():int {
return this._X;
}
public function set Y(newY:int):void {
this._Y = newY;
}
public function get Y():int {
return this._Y;
}
public function set G(newG:int):void {
this._G = newG;
}
public function get G():int {
return this._G;
}
public function set H(newH:int):void {
this._H = newH;
}
public function get H():int {
return this._H;
}
public function set F(newF:int):void {
this._F = newF;
}
public function get F():int {
return this._F;
}
public function set parentNode(newParentNode:AStarNode):void {
this._parentNode = newParentNode;
}
public function get parentNode():AStarNode {
return this._parentNode;
}
public function setAsOrigin():void {
_isOrigin = true;
}
public function checkIfOrigin():Boolean {
return _isOrigin;
}
public function isThisInArray(arrayToCheck:Array):Boolean {
for (var i in arrayToCheck) {
if (arrayToCheck[i].X == this.X && arrayToCheck[i].Y == this.Y) {
return true
}
}
return false
}
}
enter code here
}
答案 0 :(得分:1)
快速浏览一下代码会提出错误启发式的想法。您的G值在节点中始终为0,至少我看不到它可以更改的位置。但是,在A-star算法中,您的任务(找到有障碍物的最短路径)应该代表已经到达小区的步数。这将允许算法用较短的路径替换长路径。
答案 1 :(得分:0)
有一次我编写了一个A星'算法',我使用了一个二维数组作为网格(就像你一样)。在搜索开始时,每个网格位置的“搜索”属性都设置为false。每个网格位置也有一个连接方向阵列;玩家可以选择进入的选项 - 有些可能是开放的,有些可能被封锁且无法访问 我会通过检查起始网格位置来查看它有多少方向选项来开始搜索。对于每个选项,我会将'path'数组推入_paths数组。每个'path'数组最终都会包含一系列'move'(0表示up,1表示right,2表示down,3表示left)。因此,对于每个初始路径,我会推进相应的开始移动。我还将网格位置的“搜索”属性设置为true 然后我会遍历每条路径,运行这一系列的移动以到达最近添加的位置。我会检查该位置是否是目标位置。如果不是,我会将该位置标记为已搜索,然后检查可用的方向,忽略已搜索过的位置。如果非可用,则路径将被关闭并从路径数组中“拼接” 否则,为每个可用的移动选项制作当前路径数组的ByteArray“深拷贝”,超过第一个移动选项。在一个方向上的移动被添加到当前路径和新路径中,在它们各自的方向上 如果路径数达到0,则两个位置之间没有路径。 我认为这是关于它的。我希望这对你有所帮助 请注意,搜索不需要“定向”到目标;我建议搜索所有可能的路径,然后“发生”通过杀死尝试检查已经搜索过的位置的路径来找到最直接的路径(意味着其他路径首先到达那里,因此更短)。