对一个物体来说,移动很容易,而寻路很复杂。
为什么要寻找路径?考虑以下情况:
一个单位最初位于地图的底部,并希望到达顶部。
Movement - 它扫描的区域(肉色底)中没有任何阻挡表示该装置不应向上移动,因此它继续前进。在顶部附近,它会检测到障碍物并改变方向。然后它沿着(红色)路径绕过“U”形障碍物。
Pathfinding - 另一个想法是,探路者扫描更大的区域(浅蓝底),发现较短的路径(蓝色),从而避免走进凹形障碍物。
另外,您可以扩展移动算法以解决上面显示的陷阱问题。可以避免生成凹陷障碍物,也可以将它们的凸包标记为危险(只有在目的地位于内部时才进入):
寻路的搜索器希望能够提前计划,而不是等到最后一刻发现障碍。
我们需要在(Pathfinding)路径规划和(Movement)进行移动之间进行权衡。
规划通常较慢,但能给出更好的路径;运动通常更快,但可能会卡住。
如果游戏世界经常变化,那么提前规划就不那么有价值了。
我建议同时使用:在拥有大型、移动缓慢的障碍物,以及起点到目标之间有很长的路径时用 Pathfinding;在局部区域、有快速变化和较短路径时用 Movement。
算法
新页面
计科的教科书中,寻路算法,应用在图论中。
图在数学意义上,是一组具有连接它们的边缘的顶点。
平铺的游戏地图可以视为一张图。每个平铺块都是顶点,彼此相邻的图块之间有连接的边:
现在,假设我们正在使用二维网格。
如果您之前没有使用图表,请参阅此入门手册。稍后,我将讨论如何从游戏世界中构建其他类型的图形。
来自AI或算法研究的大多数寻路算法,都是针对任意图形,而不是基于网格的游戏而设计的。
我们想找到一些可以利用游戏地图性质的东西。
我们认为有些事情是常识,但算法并不理解。我们对距离有所了解:一般来说,当两个东西相距较远时,假设没有虫洞,则需要更长时间才能从一个移动到另一个。我们对方向有所了解:如果您的目的地位于东方,那么走向东方的路径比走向西方更容易找到最佳路径。在网格上,我们知道关于对称性的东西:大多数时候,向北移动然后向东移动与向东移动然后向北移动相同。这些附加信息可以帮助我们更快地运行寻路算法。
Dijkstra算法和最佳优先搜索
Dijkstra 算法通过从对象的起点开始访问图中的顶点来工作。
然后,它重复检查最近的尚未检查的顶点,将其顶点添加到要检查的顶点集。
它从起点向外扩展,直到达到目标。
Dijkstra 算法保证找到一条从起点到目标的最短路径,只要没有边缘具有负成本。(我写的是“一条最短路径”,因为通常存在多个等效短路径。)
在下图中,粉红色方块是起点,蓝色方块是目标,蓝绿色区域显示Dijkstra算法扫描的区域。最轻的蓝绿色区域距离起点最远,因此形成了探索的“前沿”:
贪心算法(Greedy Best-First-Search)以类似的方式工作,除了它有一些估计(称为启发式,任何顶点离目标有多远。它不是选择最接近起点的顶点,而是选择最接近目标的顶点)。
贪心算法不保证找到最短的路径。
然而,它比 Dijkstra算法运行得快得多,因为它用的启发式函数非常快速地引导它朝向目标。例如,如果目标位于起始位置的南侧,则贪心算法将倾向于关注向南的路径。
在下图中,黄色表示具有高启发式值(达到目标的高成本)的节点,黑色表示具有低启发式值的节点(达到目标的低成本)。它表明,与Dijkstra的算法相比,贪心算法可以非常快速地找到路径:
然而,这两个例子都说明了最简单的情况 - 当地图没有障碍物时,最短路径确实是一条直线。
让我们考虑上一节中描述的凹陷障碍。Dijkstra的算法更加努力,但保证找到最短的路径:
另一方面,贪心的Best-First-Search做的工作较少,但其路径显然不太好:
麻烦的是贪婪的Best-First-Search是“贪心的”,试图朝着目标前进,即使它不是正确的道路。
因为它只考虑到达目标的成本而忽略了到目前为止的路径成本,所以即使它会继续前进,即便所使用的路径会变得非常长。
将两者中最好的结合起来会不会很好?
A *是在1968年开发的,用于结合启发式方法(如贪心算法)和其他更庄重些的方法(如Dijsktra算法)。
这有点不寻常,因为启发式算法通常会为您提供一种解决问题的近似方法,而无法保证最优解。
而 A* 建立在启发式的基础之上,虽然启发式本身并不能保证,但 A* 可以保证最短的路径。
A* 算法
我将专注于A* 算法。A* 是寻路寻找最受欢迎的选择,因为它非常灵活,可以在各种环境中使用。
像 Dijkstra 算法一样,它可以用来找到最短的路径。像贪心算法一样,它可以使用启发式来指导自己。在简单的情况下,它与贪心算法一样快:
在具有凹陷障碍物的示例中,A* 可以找到与Dijkstra算法找到的路径一样好的路径:
它成功的秘诀在于它结合了Dijkstra算法使用的信息(支持接近起点的顶点)和贪心算法使用的信息(支持接近目标的顶点)。
在谈论A *时使用的标准术语,g(n)
表示从起点到任何顶点的路径的确切成本 n
,h(n)
表示从顶点到目标的启发式估计成本 n
。
在上图中,黄色点(h
)表示远离目标的顶点,蓝绿色点(g
)表示远离起点的顶点。
A* 在从起点移动到目标时平衡两者。每次通过主循环,它检查 n
具有最低的顶点 f(n) = g(n) + h(n)
。
本文的其余部分将探讨启发式设计,实现,地图表示以及与在游戏中使用寻路相关的各种其他主题。有些部分很充实,有些则相当不完整。