参考:https://www.bilibili.com/video/av23095766?from=search&seid=17012483131579025134
A*(也叫A star, A星)寻路算法Java版
A* 寻路算法 - christanxw的专栏 - C++博客
A*寻路算法(下面简称A星算法),就是在一个矩阵里,一个点到另一个点的最短路径的求解。这里面可能含有很多障碍物。所以,可以用于迷宫找到出口的路径,地图上的导航,游戏中的点到点的路径确定之类的场合当中。
要理解这个算法,感觉如果基础不太好的话,建议先看第一个视频,用1.5倍速观看,关键是对中间部分的那个图的演示过程有深入的理解。然后就能理解它是怎么样寻路的。 接着可以看第三个连接,这是一个相当于对视频的讲解,博主也很费心的画出了过程图。 最后是看第二个链接的代码,然后一步一步去理解就ok了。
我这里先针对算法里面的重点部分进行形象讲解,然后再对代码进行详细的展示。代码参考第二个链接。如下图:
![ba648d02a6168f64e1f10edbfa42b832.png](https://i-blog.csdnimg.cn/blog_migrate/618d4c1056dc92bab7771dffba6509d6.jpeg)
A星寻路算法解决的问题就是:我们如何走最短的路径从左边的绿点,不经过中间的红点,到达右边的绿点。
我们从视觉上很容易得出结果,但是我们需要使用算法来解决问题。所以,我们需要先用二维数组来描述上面这个输入信息,旁边的数字是二维数组的坐标。描述可走路径的值为0,不可走路径(即红色部分为1)
我们需要先冷静下来思考,我们关键是要解决什么东西?
1.最短路径
2.避开障碍物
然后互我们先来解决第一个问题:
如何得到最短路径:
公式 :F=G+H
含义:G:起点到当前点的距离 H :当前点到终点的距离。
F:等于前面两者之和,用于判定下一节点该往哪里走。如下图,此时,我们先不考虑障碍物先。
![cad8c2f32e47dc4ff1e072d26f981a9f.png](https://i-blog.csdnimg.cn/blog_migrate/7a4692b1975efb4b5bac170adb347cb3.jpeg)
一个方格内:左下角为G值,右下角为H值,左上角为F值。以横竖方向的距离为10,斜方向的为14,相当于根号2,即1.414x10。让人的视觉好处理。所以大家应该能看懂上面的三个格子吧?这里只考虑了G值得斜方向,没有考虑H值得斜方向。这里只是举个例子,让大家深入了解这个公式的意义。
然后,我们让下一步走在F值最小的格子上,如果是上图,那么就是F值为40的格子,然后依次类推,就可以找到去终点的最短路径。(这里只是进行了最简单的解释,也就是大概个原理,后面看代码才是最重要的)
然后我们来看第二个问题:怎么避开障碍物
这里是在前面的基础上,在寻找周围节点的时候,看看它的值是不是0,如果不是,就不把它放在下一步的考虑范围内就行了。
看完上面的感觉还不理解?没事,上面本来就是先打一层铺垫,后面看代码才是最完整的。
先上代码: 全部参考上面的第二个链接,但是感觉讲得不详细,所以我做的就是详尽的解释和理解。
import java.util.ArrayList;
import java.util.List;
//第一遍看懂了怎么找到最短路径,但是没看出它是怎么避过障碍物的,可是它却实现了避过障碍物
public class AStar {
public static final int[][] NODES = { { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { 0, 0, 0, 1, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0 }, };
public static final int STEP = 10;
private ArrayList<Node> openList = new ArrayList<Node>();
private ArrayList<Node> closeList = new ArrayList<Node>();
public Node findMinFNodeInOpenList() {
Node tempNode = openList.get(0); // 先以第一个元素的F为最小值,然后遍历openlist的所有值,找出最小值
for (Node node : openList) {
if (node.F < tempNode.F) {
tempNode = node;
}
}
return tempNode;
}
// 考虑周围节点的时候,就不把节点值为1的节点考虑在内,所以自然就直接避开了障碍物
public ArrayList<Node> findNeighborNodes(Node currentNode) {
ArrayList<Node> arrayList = new ArrayList<Node>();
// 只考虑上下左右,不考虑斜对角
int topX = currentNode.x;
int topY = currentNode.y - 1;
// canReach方法确保下标没有越界 exists方法确保此相邻节点不存在于closeList中,也就是之前没有遍历过
if (canReach(topX, topY) && !exists(closeList, topX, topY)) {
arrayList.add(new Node(topX, topY));
}
int bottomX = currentNode.x;
int bottomY = currentNode.y + 1;
if (canReach(bottomX, bottomY) && !exists(closeList, bottomX, bottomY)) {
arrayList.add(new Node(bottomX, bottomY));
}
int leftX = currentNode.x - 1;
int leftY = currentNode.y;
if (canReach(leftX, leftY) && !exists(closeList, leftX, leftY)) {
arrayList.add(new Node(leftX, leftY));
}
int rightX = currentNode.x