【发布时间】:2015-04-03 17:49:53
【问题描述】:
问题已解决。
我在一个简单的基于网格的游戏中实现了一个 A* 搜索算法用于寻路。这是我第一次这样做,并且大多数时候实施效果很好。但是,有时(尽管很少)当有可用路径时它会卡住。当然,它被卡住的事实使它不适合目的。我假设我的实现中遗漏了一些东西。
我已经找了几天这个问题,但无济于事。我的最后期限快到了,还有很多事情要做,我不想再浪费时间来修复这个错误了。
编辑:我创建了a quick video 来演示这个问题,这样你就可以准确地看到发生了什么。它包括字幕。
编辑:getPath 方法:
/**
* @param currentPosition - the vector the avatar currently occupies.
* @param targetPosition - the vector the avatar is aiming to reach.
* @param levelMap - a clip map of the level.
*
* @return an {@code ArrayList} of {@link ACTIONS} that the avatar can follow to reach its destination.
**/
public static ActionPath getPath(Vector2d currentPosition, Vector2d targetPosition, LevelMap levelMap) {
openTiles = new ArrayList<AStarTile>();
closedTiles = new ArrayList<AStarTile>();
targetMet = false;
AStarTile originTile = AStarTile.fromVector(currentPosition, levelMap.getBlockSize()),
targetTile = AStarTile.fromVector(targetPosition, levelMap.getBlockSize()),
currentTile = null,
parentTile = null;
ActionPath actionPath = new ActionPath(targetTile);
if (originTile.equals(targetTile)) {
targetMet = true;
return null;
}
GVGLogger.logInfo("Creating path from tile " + originTile + " to tile " + targetTile + " (" + currentPosition + " to " + targetPosition + ").");
/*
* Start the search.
*/
openTile(originTile);
originTile.calculateGeneration();// The origin tile will always be generation 0.
closeTile(originTile);
parentTile = originTile;
while(!targetMet) {
for (int i = 0; i != 4; i++) {
currentTile = parentTile.move(i);// Checks an adjacent tile - up, down, left, and right respectively
if (levelMap.inBounds(currentTile) && levelMap.isAccessible(currentTile) && !isClosed(currentTile)) {
if (isOpen(currentTile)) {
// Check to see if this path to this tile is a better one.
currentTile = getOpen(currentTile);
if (currentTile.getGeneration() > parentTile.getGeneration() + 1) {
// The open version's generation is higher than this version's generation - it's a better path
currentTile.setParentTile(parentTile);
currentTile.calculateGeneration();
currentTile.calculateFinalScore();
}
}
else {
currentTile.setParentTile(parentTile);
currentTile.setHeuristic(currentTile.distanceSquared(targetTile));
currentTile.calculateGeneration();
currentTile.calculateFinalScore();
openTile(currentTile);
}
}
}
if (openTiles.size() > 0) {
parentTile = getBestOption();
closeTile(parentTile);
if (parentTile.equals(targetTile)) {
targetMet = true;
}
}
else {
GVGLogger.logWarning("Target unreachable!");
return null;
}
}
//Convert the path of tiles into ACTIONS that the avatar can take to reach it.
for (int i = 0; i != closedTiles.size(); i++) {
Vector2i difference = getDifference(closedTiles.get(i), (i != closedTiles.size() - 1 ? closedTiles.get(i + 1) : targetTile));
if (difference.equals(1, 0)) {
actionPath.add(ACTIONS.ACTION_LEFT);
}
else if (difference.equals(-1, 0)) {
actionPath.add(ACTIONS.ACTION_RIGHT);
}
else if (difference.equals(0, -1)) {
actionPath.add(ACTIONS.ACTION_DOWN);
}
else if (difference.equals(0, 1)) {
actionPath.add(ACTIONS.ACTION_UP);
}
else if (difference.equals(0, 0)) {
return actionPath;
}
else {
GVGLogger.logWarning("Error in path-finding - found a difference of " + difference + "!");
}
}
return null;
}
private static Vector2i getDifference(AStarTile tileA, AStarTile tileB) {
return new Vector2i(tileA.getX() - tileB.getX(), tileA.getY() - tileB.getY());
}
public static boolean targetMet() {
return targetMet;
}
private static void openTile(AStarTile toOpen) {
if (isClosed(toOpen)) {
closedTiles.remove(getOpen(toOpen));
}
if (!isOpen(toOpen)) {
openTiles.add(toOpen);
}
}
private static void closeTile(AStarTile toClose) {
if (isOpen(toClose)) {
openTiles.remove(getOpen(toClose));
}
if (!isClosed(toClose)) {
closedTiles.add(toClose);
}
}
private static boolean isClosed(AStarTile toCheck) {
return getClosed(toCheck) != null;
}
private static boolean isOpen(AStarTile toCheck) {
return getOpen(toCheck) != null;
}
/**
* @return the open tile with the lowest 'final' score.
**/
private static AStarTile getBestOption() {
try {
Collections.sort(openTiles);
return openTiles.get(0);
}
catch(Exception e) {
}
return null;
}
private static AStarTile getClosed(AStarTile t) {
for (AStarTile p : closedTiles) {
if (p.equals(t)) {
return t;
}
}
return null;
}
private static AStarTile getOpen(AStarTile t) {
for (AStarTile p : openTiles) {
if (p.equals(t)) {
return t;
}
}
return null;
}
}
此方法返回一个“动作”列表,化身可以用来丰富目标图块。如果您想查看任何其他方法,请询问。
我在阅读了在 policyalmanac.org 上找到的 Patrick Lester 的解释/教程后编写了这个实现(“A* Pathfinding for Beginners”)。
如果您能浏览一下我的实现并指出任何问题,我将不胜感激,尤其是如果您对 A* 搜索算法有经验。我认为代码是自我记录的,但如有必要,请随时要求我详细说明。
感谢您的宝贵时间。
【问题讨论】:
-
请不要在外部资源上发布您的代码。而是直接在此处发布与问题相关的内容。
-
@tnw 代码没有按预期工作,因此它不属于代码审查。
-
对,吸取教训。我只是认为这样会更整洁,以避免用代码填充问题。我还认为我最好将所有这些都添加到有问题的方法中,以防有人希望检查其他方法。
标签: java algorithm search a-star