違ったとしても責任はもちません
場所はorg.andengine.util.algorithm.path.astarの中のAStarPathFinder.java
findPath() メソッドの
visitedNodes.put(currentNodeID, currentNode);
のすぐ上に
openNodes.remove(currentNodeID);
を追加。
たぶんこれが無いと経路がない場合(袋小路状態のとき)にNULLが帰ってこない
あと最適経路じゃないところを返してくることがある・・・とおもう
修正後+日本語のコメント付きのfindPath()内全ソースを以下に
@Override
public Path findPath(final IPathFinderMap<T> pPathFinderMap, final int pXMin, final int pYMin, final int pXMax, final int pYMax, final T pEntity, final int pFromX, final int pFromY, final int pToX, final int pToY, final boolean pAllowDiagonal, final IAStarHeuristic<T> pAStarHeuristic, final ICostFunction<T> pCostFunction, final float pMaxCost, final IPathFinderListener<T> pPathFinderListener) {
if(((pFromX == pToX) && (pFromY == pToY)) || pPathFinderMap.isBlocked(pFromX, pFromY, pEntity) || pPathFinderMap.isBlocked(pToX, pToY, pEntity)) {
return null;
}
/* いくつかのフィールドをローカルに持ってくる */
/* Drag some fields to local variables. */
final Node fromNode = new Node(pFromX, pFromY, pAStarHeuristic.getExpectedRestCost(pPathFinderMap, pEntity, pFromX, pFromY, pToX, pToY));
final long fromNodeID = fromNode.mID;
final long toNodeID = Node.calculateID(pToX, pToY);
final LongSparseArray<Node> visitedNodes = new LongSparseArray<Node>();
final LongSparseArray<Node> openNodes = new LongSparseArray<Node>();
final IQueue<Node> sortedOpenNodes = new SortedQueue<Node>(new ShiftList<Node>());
final boolean allowDiagonalMovement = pAllowDiagonal;
/* アルゴリズムの初期化 */
/* Initialize algorithm. */
openNodes.put(fromNodeID, fromNode);
sortedOpenNodes.enter(fromNode);
Node currentNode = null;
while(openNodes.size() > 0) {
/* 現在のノードをオープンリストで一番コストが小さいものにする */
/* The first Node in the open list is the one with the lowest cost. */
currentNode = sortedOpenNodes.poll();
final long currentNodeID = currentNode.mID;
/* 現在のノードが目的地のノードなら探索終了 */
if(currentNodeID == toNodeID) {
break;
}
/* 現在のノードを訪問済みリストに追加 */
openNodes.remove(currentNodeID); // オープンリストから探索済みノードを削除する処理を追加
visitedNodes.put(currentNodeID, currentNode);
/* 近傍のすべての位置でループ */
/* Loop over all neighbors of this position. */
for(int dX = -1; dX <= 1; dX++) {
for(int dY = -1; dY <= 1; dY++) {
if((dX == 0) && (dY == 0)) {
continue;
}
if(!allowDiagonalMovement && (dX != 0) && (dY != 0)) {
continue;
}
final int neighborNodeX = dX + currentNode.mX;
final int neighborNodeY = dY + currentNode.mY;
final long neighborNodeID = Node.calculateID(neighborNodeX, neighborNodeY);
/* 範囲外か移動不能なノードの場合は飛ばす */
if(!IntBoundsUtils.contains(pXMin, pYMin, pXMax, pYMax, neighborNodeX, neighborNodeY) || pPathFinderMap.isBlocked(neighborNodeX, neighborNodeY, pEntity)) {
continue;
}
/* 訪問済みのノードの場合は飛ばす */
if(visitedNodes.indexOfKey(neighborNodeID) >= 0) {
continue;
}
Node neighborNode = openNodes.get(neighborNodeID);
final boolean neighborNodeIsNew;
/* 調査中のノードがオープンリストに存在しているかどうかのチェック */
/* Check if neighbor exists. */
if(neighborNode == null) {
/* 存在していない場合はノードを生成 */
neighborNodeIsNew = true;
neighborNode = new Node(neighborNodeX, neighborNodeY, pAStarHeuristic.getExpectedRestCost(pPathFinderMap, pEntity, neighborNodeX, neighborNodeY, pToX, pToY));
} else {
/* 存在している場合 */
neighborNodeIsNew = false;
}
/* コストを再計算 */
/* Update cost of neighbor as cost of current plus step from current to neighbor. */
final float costFromCurrentToNeigbor = pCostFunction.getCost(pPathFinderMap, currentNode.mX, currentNode.mY, neighborNodeX, neighborNodeY, pEntity);
final float neighborNodeCost = currentNode.mCost + costFromCurrentToNeigbor;
if(neighborNodeCost > pMaxCost) {
/* コストの最大値以上 -> 新しく追加したノードでない場合はオープンリストから削除 */
/* Too expensive -> remove if isn't a new node. */
if(!neighborNodeIsNew) {
openNodes.remove(neighborNodeID);
}
} else {
/* コストの最大値を超えていない */
neighborNode.setParent(currentNode, neighborNodeCost);
if(neighborNodeIsNew) {
/* 新しく追加したノードの場合はオープンリストに追加 */
openNodes.put(neighborNodeID, neighborNode);
} else {
/* 正しい位置に挿入するために一度キューから削除 */
/* Remove so that re-insertion puts it to the correct spot. */
sortedOpenNodes.remove(neighborNode);
}
/* キューを追加 */
sortedOpenNodes.enter(neighborNode);
if(pPathFinderListener != null) {
pPathFinderListener.onVisited(pEntity, neighborNodeX, neighborNodeY);
}
}
}
}
}
/* Cleanup. */
// TODO We could just let the GC do its work.
visitedNodes.clear();
openNodes.clear();
sortedOpenNodes.clear();
/* 経路が見つかったかチェック(無ければnullを返す) */
/* Check if a path was found. */
if(currentNode.mID != toNodeID) {
return null;
}
/* 経路の長さを計算 */
/* Calculate path length. */
int length = 1;
Node tmp = currentNode;
while(tmp.mID != fromNodeID) {
tmp = tmp.mParent;
length++;
}
/* 親タイルを辿って経路を形成する */
/* Traceback path. */
final Path path = new Path(length);
int index = length - 1;
tmp = currentNode;
while(tmp.mID != fromNodeID) {
path.set(index, tmp.mX, tmp.mY);
tmp = tmp.mParent;
index--;
}
path.set(0, pFromX, pFromY);
return path;
}
個人的に思うのは、
このアルゴリズムで使うpath(org.andengine.util.algorithm.path.Path)と
スプライトアニメーションのpath(org.andengine.entity.modifier.PathModifier.Path)の互換性を上げてほしい・・・名前も同じで面倒だし
まあ自分でクラス拡張すればいいのかもしれないですが

0 件のコメント:
コメントを投稿