A*寻路算法
原创:程序员小灰
比如像这个样子:
第一步:
把起点放入 OpenList
第二步:
找出 OpenList
中 F
值最小的方格,即唯一的方格 Node(1,2)
作为当前方格,并把当前格移出 OpenList
,放入 CloseList
。代表这个格子已到达并检查过了。
第三步:
找出当前格上下左右所有可到达的格子,看它们是否在 OpenList
当中。如果不在,加入 OpenList
,计算出相应的 G
、H
、F
值,并把当前格子作为它们的“父亲节点”。
图中,每个格子的左下方数字是
G
,右下方是H
,左上方是F
。
Round2 ~ 第二步:
找出当前格上下左右所有可到达的格子,看它们是否在 OpenList
当中。如果不在,加入 OpenList
,计算出相应的 G
、H
、F
值,并把当前格子作为它们的“父亲节点”。
为什么这一次
OpenList
只增加了两个新格子呢?因为Node(3,2)
是墙壁,自然不用考虑,而Node(1,2)
在CloseList
当中,说明已经检查过了,也不用考虑。
Round3 ~ 第一步:
找出 OpenList
中 F
值最小的方格。由于这时候多个方格的 F
值相等,任意选择一个即可,比如 Node(2,3)
作为当前方格,并把当前格移出 OpenList
,放入 CloseList
。代表这个格子已到达并检查过了。
Round3 ~ 第二步:
找出当前格上下左右所有可到达的格子,看它们是否在 OpenList
当中。如果不在,加入 OpenList
,计算出相应的 G
、H
、F
值,并把当前格子作为它们的“父亲节点”。
剩下的就是以前面的方式继续迭代,直到 OpenList
中出现终点方格为止。这里就仅用图片简单描述了,方格中数字表示 F
值:
public Node aStarSearch(Node start, Node end) {
// 把起点加入 open list
openList.add(start);
//主循环,每一轮检查一个当前方格节点
while (openList.size() > 0) {
// 在OpenList中查找 F值最小的节点作为当前方格节点
Node current = findMinNode();
// 当前方格节点从open list中移除
openList.remove(current);
// 当前方格节点进入 close list
closeList.add(current);
// 找到所有邻近节点
List<Node> neighbors = findNeighbors(current);
for (Node node : neighbors) {
if (!openList.contains(node)) {
//邻近节点不在OpenList中,标记父亲、G、H、F,并放入OpenList
markAndInvolve(current, end, node);
}
}
//如果终点在OpenList中,直接返回终点格子
if (find(openList, end) != null) {
return find(openList, end);
}
}
//OpenList用尽,仍然找不到终点,说明终点不可到达,返回空
return null;
}
这里对于
A*
寻路的描述做了很大的简化。实际场景中可能会遇到斜向移动、特殊地形等等因素,有些时候需要对OpenList
中的方格进行重新标记。