A*搜索算法--游戏寻路
发布日期:2021-07-01 03:40:24 浏览次数:2 分类:技术文章

本文共 2205 字,大约阅读时间需要 7 分钟。

文章目录

仙剑奇侠传这类MMRPG游戏中,有人物角色
自动寻路功能。当人物处于游戏地图中某位置时,点击另一个相对较远的位置,人物就会自动地绕过障碍物走过去。这个功能是怎么实现的呢?

1. 算法解析

这是一个非常典型的搜索问题。起点是当下位置,终点是鼠标点击位置。找一条路径。路径要绕过地图中所有障碍,并且走的路不能太绕。最短路径显然是最聪明的走法,是最优解。

但是如果图非常大,那Dijkstra最短路径算法的执行耗时会很多。在真实的软件开发中,面对的是超级大的地图和海量的寻路请求,算法的执行效率太低,是无法接受的。

一般情况下,我们都不需要非得求最优解(最短路径)。在权衡路线规划质量和执行效率的情况下,只需要寻求一个次优解就足够了

  • A* 算法是对Dijkstra算法的优化和改造。

Dijkstra 算法有点类似BFS算法,它每次找到跟起点最近的顶点,往外扩展。这种往外扩展有些盲目。举一个例子。下图对应一个真实地图,每个点在地图中的位置,用一个坐标(x,y)来表示,x横坐标,y纵坐标。

在这里插入图片描述
在Dijkstra算法中,用一个优先队列,记录已经遍历的顶点以及这个顶点与起点的路径长度。顶点与起点路径长度越小,优先从优先级队列中取出来扩展,从图中举例可以看出,尽管找的是从s到t的路线,但是最先被搜索到的顶点依次是1,2,3。这个搜索方向明显“跑偏"了。

之所以“跑偏”,是因为没有考虑这个顶点到终点的距离,尽管1,2,3三个顶点离起始顶点最近,但离终点却越来越远。

如果综合更多因素,把这个顶点到终点可能还要走多远,考虑进去,综合判断哪个顶点先出队列,是不是就可以避免“跑偏”呢?

当遍历到某个顶点时,从起点走到这个顶点的路径长度是确定的,我们记作g(i)。通过这个顶点跟终点之间的直线距离,也就是欧几里得距离,来近似估计这个顶点跟终点的路径长度。我们把这个距离记作h(i),专业叫法是启发函数(heuristic function)。因为欧几里得距离公式,会涉及比较耗时的开根号计算,所以一般计算曼哈顿距离(Manhattan distance)。曼哈顿距离是两点之间横纵坐标的距离之和。只涉及加减法、符号位反转,所以更加高效。

int hManhattan(Vertex v1, Vertex v2) { // Vertex 表示顶点	return Math.abs(v1.x - v2.x) + Math.abs(v1.y - v2.y);}

通过两者之和 f(i)= g(i)+ h(i),来判断哪个顶点最先出队。能有效避免“跑偏"。这里f(i)的专业叫法是估价函数(evaluation function)。

A* 算法就是对Djkstra算法的简单改造。在A*算法的代码实现中,顶点Vertex类的定义,多了x,y坐标,f(i)值。

A* 算法跟Djkstra 算法主要有3点区别:

  • 优先级队列构建的方式不同。A*算法是根据 f 值 f(i)=g(i)+h(i)来构建优先级队列,而Dijkstra 算法是根据dist值 g(i)来构建优先级队列;
  • A*算法在更新顶点dist值的时候,同步更新 f 值;
  • 循环结束的条件不一样。Dijkstra 算法是在终点出队列的时候才结束,A*算法是一旦遍历到终点就结束。

尽管A* 算法可以快速找到从起点到终点的路线,但是它并不能像Dijkstra算法那样,找到最短路线

在这里插入图片描述
Dijkstra 算法在回溯基础上,利用动态规划思想,对回溯进行剪枝,只保留起点到某个顶点的最短路径,继续往外扩展搜索。动态规划相较于回溯搜索,只是换了一个实现思路,但它实际上也考察到了所有从起点到终点的路线,所以能得到最优解。
在这里插入图片描述
A* 算法之所以不能像Dijkstra 算法那样,找到最短路径,主要原因是两者的while 循环结束条件不一样。

  • Dijkstra 算法是在终点出队列的时候才结束
  • A*算法是一旦遍历到终点就结束。

对于Dijkstra 算法来说,当终点出队列的时候,终点的 dist 值是优先级队列中所有顶点的最小值,即便再运行下去,终点的dist值也不会再被更新了。

对于A* 算法来说,一旦遍历到终点,我们就结束 while循环,这个时候,终点的dist值未必是最小值。

A* 算法利用贪心算法的思路,每次都找 f 值最小的顶点出队列,一旦搜到终点就不继续考察其他顶点和路线。所以,它没有考察所有路线,也就不能找出最短路径。

如何借助A* 算法解决游戏寻路?

游戏地图并不像现实生活中那样,存在规划非常清晰的道路,更多的是宽阔的荒野、草坪等。换一种抽象的思路,把地图分割成一个一个的小方块。在某个方块上的人物,只能往上下左右四个方向移动。把每个方块看作一个顶点。方块相邻,它们之间连两条有向边,权值都是1。套用A* 算法。

2. 总结

A* 算法属于一种启发式搜索算法(Heuristically Search Algorithm)。启发式搜索算法还有很多其他算法,比如 IDA* 算法、蚁群算法、遗传算法、模拟退火算法等。

  • 启发式搜索算法利用估价函数,避免“跑偏”,贪心地朝着最有可能到达终点的方向前进。
  • 算法找出的路线,并不是最短路线。
  • 实际软件开发中的路线规划问题,并不需要非得找最短路线。鉴于启发式搜索算法能很好地平衡路线质量和执行效率,它应用更加广泛。

转载地址:https://michael.blog.csdn.net/article/details/98985098 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:索引 Index -- 快速查找数据
下一篇:B+树 -- MySQL数据库索引

发表评论

最新留言

网站不错 人气很旺了 加油
[***.192.178.218]2024年04月14日 22时47分17秒