A*算法 一级棒
转载:https://www.gamedev.net/reference/articles/article2003.asp
简介:搜索区域
让我们假设有人想要从A点到达B点。让我们假设一堵墙将两个点分开。如下图所示,绿色为起点A,红色为终点B,蓝色填充的正方形为中间的墙。
您应该注意的第一件事是,我们已经将搜索区域划分为一个正方形网格。正如我们在此处所做的那样,简化搜索区域是寻路的第一步。这种特殊的方法将我们的搜索区域缩小为一个简单的二维数组。数组中的每个项目代表网格上的一个正方形,其状态记录为可步行或不可步行。通过确定从A到B应该走哪个正方形来找到路径。找到路径后,我们的人将从一个正方形的中心移至下一个正方形的中心,直到达到目标。
这些中心点称为“节点”。当您在其他地方阅读有关寻路的信息时,经常会看到人们在讨论节点。为什么不叫它们正方形呢?因为可以将寻路区域划分为正方形以外的区域。实际上,它们可以是矩形,六边形,三角形或任何形状。节点可以放置在形状内的任何位置-中心,沿边缘或其他任何位置。但是,我们正在使用此系统,因为它是最简单的。
开始搜寻
正如我们对上面的网格布局所做的那样,一旦将搜索区域简化为可管理的节点数,下一步就是进行搜索以找到最短路径。为此,我们从A点开始,检查相邻的正方形,然后大体向外搜索,直到找到目标。
我们通过执行以下操作开始搜索:
从起点A开始,并将其添加到要考虑的正方形“开放列表”中。打开清单有点像购物清单。现在,列表中只有一项,但以后还会有更多。它包含可能沿着您想走的路径掉落的正方形,但也许不是。基本上,这是需要检查的正方形列表。
查看靠近起点的所有可到达或可步行的正方形,而忽略带有墙壁,水或其他非法地形的正方形。也将它们添加到打开的列表中。对于每个这些正方形,将点A保存为其“父正方形”。当我们想追踪我们的路径时,这个父正方形的东西很重要。稍后将进行解释。
从打开的列表中删除起始正方形A,然后将其添加到正方形的“封闭列表”中,您现在无需再次查看。
此时,您应该具有下图所示的内容。在此图中,中间的深绿色方块是您的起始方块。它以浅蓝色勾勒出轮廓,表示该正方形已添加到关闭列表中。现在,所有相邻的正方形都在要检查的正方形的打开列表中,并以浅绿色勾勒出轮廓。每个对象都有一个灰色指针,该指针指向其父对象,即起始正方形。
接下来,如下所述,我们在打开的列表中选择一个相邻的正方形,并或多或少重复前面的过程。但是我们选择哪个广场呢?F成本最低的那个。
路径计分
确定路径时使用哪个正方形的关键是以下公式:
F = G + H
其中
G =从起点A到网格上给定正方形的移动成本,遵循到达那里的路径。
H =从网格上的给定正方形移至最终目的地B点的估计移动成本。这通常称为启发式,可能会造成混淆。之所以称为它,是因为这是一个猜测。在找到路径之前,我们真的不知道实际距离,因为各种各样的东西都可能挡住道路(墙壁,水等)。在本教程中,您将获得一种计算H的方法,但在Web上的其他文章中可以找到许多其他方法。通过反复浏览打开的列表并选择F得分最低的正方形来生成我们的路径。本文将对此过程进行更详细的描述。首先,让我们更仔细地看一下我们如何计算方程式。
如上所述,G是使用起点到起点从起点移动到给定正方形的移动成本。在此示例中,我们将为每个水平或垂直正方形移动分配成本10,对角线移动分配成本14。
我们使用这些数字是因为对角移动的实际距离是2的平方根(请不要害怕),大约是水平或垂直移动成本的1.414倍。为了简单起见,我们使用10和14。该比率大约是正确的,我们避免了必须计算平方根并且避免了小数。这不仅是因为我们愚蠢而且不喜欢数学。
对于计算机而言,使用这样的整数也快得多。您很快就会发现,如果不使用此类捷径,寻路可能会非常缓慢。
由于我们是沿着到给定正方形的特定路径计算G成本,因此找出该正方形的G成本的方法是取其父级的G成本,然后根据对角线还是对角线将其相加10或14。与该父正方形正交(非对角线)。在此示例中,对这种方法的需求将变得更加明显,因为我们与起始正方形之间的距离超过一个正方形。
H可以通过多种方式估算。我们在此使用的方法称为“曼哈顿方法”,您可以在其中计算水平和垂直移动的正方形总数,以从当前正方形到达目标正方形,而忽略对角线移动,并忽略可能遇到的任何障碍。然后,将总数乘以10,即水平或垂直移动一个正方形的成本。这(可能)称为“曼哈顿方法”,因为它就像计算从一个地方到另一个地方的城市街区数,而您不能对角地跨过城市街区。
阅读此描述,您可能会猜测,启发式方法只是“当乌鸦飞翔时”当前方块与目标之间剩余距离的粗略估计。事实并非如此。我们实际上是在尝试估算沿路径的剩余距离(通常更远)。我们的估计值与实际剩余距离越接近,算法将越快。但是,如果我们高估了这个距离,则不能保证给出最短的路径。在这种情况下,我们有所谓的“不允许的启发式”。
从技术上讲,在此示例中,曼哈顿方法是不可接受的,因为它会稍微高估剩余距离。但是无论如何我们都会使用它,因为对于我们的目的而言,它更容易理解,并且因为它只是一个高估。在极少数情况下,如果生成的路径不是最短的路径,它将几乎一样短。想知道更多?您可以在此处找到有关启发式的方程式和其他注释。
F是通过将G和H相加得出的。我们搜索的第一步结果可以在下图中看到。F,G和H分数写在每个方块中。如起始方块最右边的方块所示,F印刷在左上方,G印刷在左下方,H印刷在右下方。
[图3]
因此,让我们看一下其中一些正方形。在其中带有字母的正方形中,G =10。这是因为它在水平方向上距离起始正方形仅一个正方形。起始正方形正上方,下方和左侧的正方形均具有相同的G得分10。对角线正方形的G得分均为14。H
得分是通过估算曼哈顿到红色目标正方形的距离(移动)来计算的仅在水平和垂直方向上忽略了挡墙。使用此方法,起始点最右边的正方形是红色正方形的3个正方形,其H得分为30。该正方形正上方的正方形与H的距离为4个正方形(请记住,只能水平和垂直移动)得分40。您可能会看到如何计算其他正方形的H得分。
同样,通过将G和H加在一起即可简单地计算出每个正方形的F得分。
继续搜索
要继续搜索,我们只需从打开列表中的所有F得分中选择最低的F得分平方。然后,对选定的正方形执行以下操作:
好的,让我们看看它是如何工作的。在我们最初的9个方格中,当起始方格切换到封闭方列表后,在打开的列表中还剩下8个。其中,F成本最低的那个是起始正方形的最右边一个,F得分为40。因此,我们选择该正方形作为下一个正方形。下图以蓝色突出显示。
首先,我们将其从打开的列表中删除,并将其添加到关闭的列表中(这就是为什么现在将其突出显示为蓝色的原因)。然后我们检查相邻的正方形。好吧,这个正方形最右边的是墙正方形,因此我们将其忽略。最左边的那个是起始方块。那是在封闭清单上,所以我们也忽略了这一点。
其他四个正方形已经在开放列表中,因此我们需要使用G得分作为参考点,使用该正方形到达这些正方形的路径是否更好。让我们看一下所选正方形上方的正方形。它的当前G得分是14。如果我们改为通过当前广场到达那里,则G得分等于20(10,即到达当前广场的G得分,再加上10垂直进入该广场。上方的一个)。AG得分20高于14,因此这不是更好的方法。如果看一下图,那应该很有意义。通过简单地对角移动一个正方形到达起始位置,而不是水平移动一个正方形然后垂直移动一个正方形,可以更直接地从起始正方形到达该正方形。
当我们对已在开放列表中的所有四个相邻正方形重复此过程时,我们发现通过当前正方形不会改善任何路径,因此我们不会进行任何更改。因此,既然我们查看了所有相邻的正方形,就完成了这个正方形,并准备移至下一个正方形。
因此,我们在打开的列表中浏览了一个正方形列表,该列表现在已降至7个正方形,并且我们选择了F成本最低的那个。有趣的是,在这种情况下,有两个得分为54的正方形。那么我们选择哪个呢?没关系。为了提高速度,选择最后一个可以更快您添加到打开列表中的一个。当您离目标较近时,这会偏向于搜索的正方形,而正方形会在搜索的后期找到。但这并不重要。(对关系的处理方式不同,就是为什么两个版本的A *可能会找到长度相等的不同路径。)
因此,让我们选择位于正方格下方和右方的路径,如下图所示。
这次,当我们检查相邻的正方形时,我们发现最右边的一个是墙正方形,因此我们将其忽略。上面的那个也是如此。我们也忽略了墙下的正方形。为什么?因为您不能直接从当前广场直达那个广场,而不必跨过附近墙的一角。您确实确实需要先走下然后移到那个广场,然后在此转弯。(注意:此拐角规则是可选的。它的使用取决于节点的放置方式。)
剩下另外五个方块。当前正方形下面的其他两个正方形尚未在打开列表中,因此我们将其添加,当前正方形成为其父对象。在其他三个正方形中,有两个已经在封闭列表中(起始正方形和当前正方形上方的一个,在图中均以蓝色突出显示),因此我们将其忽略。然后检查当前正方形最左边的最后一个正方形,以查看如果您通过当前正方形到达那里,G分数是否更低。没有骰子。至此,我们已经准备好检查打开清单中的下一个方块。
我们重复此过程,直到将目标正方形添加到封闭列表中为止,此时看起来类似于下图。
请注意,起始正方形下方两个正方形的正方形的父正方形与上一个插图已更改。在它的G得分为28之前,它指向其上方的正方形和右侧。现在它的分数为20,并指向其正上方的正方形。这发生在我们搜索过程中的某处,在该处检查了G得分,结果发现它使用新路径降低了-因此切换了父级,并重新计算了G和F得分。尽管此更改在此示例中似乎不太重要,但在很多可能的情况下,这种持续检查将为确定到达目标的最佳路径带来很大的不同。
那么我们如何确定路径?简单,只需从红色目标正方形开始,然后按照箭头从一个正方形向其父对象向后移动即可。最终,这将带您回到起点,这就是您的道路。它应如下图所示。从起始正方形A移至目标正方形B只是从路径中每个正方形(节点)的中心移至下一个正方形的中心,直至到达目标的问题。
A *方法摘要
好的,现在您已经完成了解释,让我们在一个地方列出逐步方法:
d)在以下情况下停止:
从打开的列表中删除它,并将其添加到关闭的列表中。
检查所有相邻的正方形。忽略那些已关闭列表或不可步行(有墙壁,水或其他非法地形的地形)的列表,如果尚未将其添加到打开列表中,则将其添加到打开列表中。使选定的正方形成为新正方形的“父”。
如果相邻的正方形已经在打开的列表中,请检查此通往该正方形的路径是否更好。换句话说,如果我们使用当前正方形到达该正方形,请检查该正方形的G得分是否较低。如果没有,则什么也不要做。
另一方面,如果新路径的G成本较低,则将相邻正方形的父对象更改为所选正方形(在上图中,将指针的方向更改为指向所选正方形)。最后,重新计算该正方形的F和G分数。如果这看起来令人困惑,您将在下面看到它。
将起始正方形(或节点)添加到打开列表中。
重复以下操作:
a)在打开的列表中查找最低的F成本平方。我们将此称为当前正方形。
b)将其切换到关闭列表。
c)对于当前正方形附近的8个正方形中的每个正方形…
如果它不适合步行或在关闭列表中,请忽略它。否则,请执行以下操作。
如果不在打开列表中,请将其添加到打开列表中。将当前正方形作为该正方形的父对象。记录正方形的F,G和H成本。
如果它已经在打开的列表中,则使用G成本作为度量,检查到该正方形的路径是否更好。较低的G成本意味着这是一条更好的途径。如果是这样,请将正方形的父级更改为当前正方形,然后重新计算该正方形的G和F分数。如果您要按照F分数对打开的列表进行排序,则可能需要诉诸列表以应对更改。
将目标正方形添加到已关闭列表中,在这种情况下,已找到路径(请参见下面的注释),或者
找不到目标正方形,打开的列表为空。在这种情况下,没有路径。
保存路径。从目标方块向后移动,从每个方块到其父方块,直到到达起始方块。那是你的路。注意:在本文的早期版本中,建议您在将目标正方形(或节点)添加到打开列表(而不是关闭列表)后停止。这样做会更快,并且几乎总会给您最短的路径,但并非总是如此。这样做可能会有所不同的情况是,从第二个节点到最后一个节点再到最后一个(目标)节点的移动成本可能发生显着变化-例如,在两个节点之间过河的情况下。
小乱
请原谅我的题外话,但值得指出的是,当您在网络上和各种论坛中阅读有关A *寻路的各种讨论时,您偶尔会看到有人将某些代码称为A *,而并非如此。对于要使用的A *方法,您需要包括上面刚刚讨论的元素-特别是打开和关闭列表以及使用F,G和H进行路径评分。还有很多其他寻路算法,但是这些其他方法并没有A *,通常被认为是最好的。Bryan Stout在本文结尾处引用的文章中讨论了其中的许多内容,包括它们的优缺点。有时在某些情况下替代方法会更好,但您应该了解所学内容。好吧,足够的咆哮。回到文章。
实施注意事项
既然您已经了解了基本方法,那么在编写自己的程序时,还需要考虑一些其他事项。以下某些材料引用了我用C ++和Blitz Basic编写的程序,但是这些要点在其他语言中同样有效。
1.其他单位(避免冲突):如果您碰巧仔细查看我的示例代码,您会发现它完全忽略了屏幕上的其他单位。各个单元彼此直通。根据游戏的不同,这是否可以接受。如果要在寻路算法中考虑其他单位并使它们彼此移动,我建议您仅考虑在计算路径时停止或与寻路单位相邻的单位,将其当前位置视为不可行走。对于正在移动的相邻单元,可以通过惩罚沿其各自路径放置的节点来阻止冲突,从而鼓励寻路单元找到一条替代路线(在#2下有更多介绍)。
如果选择考虑其他正在移动但与寻路单元不相邻的单元,则需要开发一种方法来预测它们在任何给定时间点的位置,以便可以正确避开它们。否则,您可能最终会遇到奇怪的路径,在这些路径中单位Zig-zag可以避免不再存在的其他单位。
当然,您还需要开发一些碰撞检测代码,因为无论路径在计算时有多好,事情都会随着时间变化。当发生碰撞时,一个单元必须计算一条新路径,或者,如果另一个单元正在移动并且不是正面碰撞,则在继续当前路径之前,请等待另一个单元退出。
这些技巧可能足以让您入门。如果您想了解更多信息,以下一些链接可能会有所帮助:
自主角色的转向行为:Craig Reynold在转向方面的工作与寻路有所不同,但可以与寻路集成在一起,以形成更完整的运动和防撞系统。
计算机游戏指导的长与短:对指导和寻路文献的有趣调查。这是一个pdf文件。
单位协调行动:《帝国时代》设计师Dave Pottinger撰写的关于编队和基于团体的运动分为两部分,其中第一部分。
实施协调运动:Dave Pottinger的两部分系列文章中的第二篇。
2.可变的地形成本:在本教程和我的随附程序中,地形只是两件事之一-可步行或不可步行。但是,如果您拥有可步行但移动成本较高的地形,该怎么办?沼泽,丘陵,地牢中的楼梯等-这些都是可步行地形的示例,但其成本比平坦的开阔地面高。同样,道路的移动成本可能比周围的地形低。
在计算任何给定节点的G成本时,可以通过添加Terrain成本轻松解决此问题。只需向此类节点添加额外费用。已经编写了A *寻路算法,以找到成本最低的路径,并且应该可以轻松应对。在我描述的简单示例中,当地形仅可步行或不可步行时,A *将寻找最短,最直接的路径。但是,在可变成本的地形环境中,成本最低的路径可能需要走更长的距离-就像绕着沼泽走一条路,而不是直行穿过沼泽。
另一个有趣的考虑因素是专业人员称为“影响映射”的东西。就像上述可变的地形成本一样,您可以创建一个附加的点系统并将其应用于AI路径。想象一下,您有一幅地图,上面有一堆守卫山区的通行证的单位。每次计算机在通过该通行证的路径上派人时,都会遭到重击。如果需要,可以创建一个影响图,对发生大量屠杀的节点进行惩罚。这将教会计算机采用更安全的路径,并有助于避免由于只是更短(但也更危险)而不断通过特定路径派兵的愚蠢情况。
另一个可能的用途是惩罚沿着附近移动单元的路径放置的节点。A *的缺点之一是,当一组单位都尝试寻找到相似位置的路径时,通常会有大量重叠,因为一个或多个单位试图沿相同或相似的路线到达目的地。向其他单元已经“声明”的节点增加惩罚将有助于确保一定程度的分离并减少冲突。但是,不要将此类节点视为不可移动的,因为如果需要,您仍然希望多个单元能够挤入单个文件中的狭窄通道。此外,您应该只惩罚靠近寻路单位的单位的路径,而不是所有路径,否则会得到奇怪的躲避行为,因为单位会避免当时没有位置的单位的路径。也,
3.处理未开发区域:您是否曾经玩过PC游戏,即使尚未浏览过地图,计算机也始终确切知道要走什么路?取决于游戏,太好的寻路可能是不现实的。幸运的是,这是一个很容易解决的问题。
答案是为各个玩家和计算机对手(每个玩家,而不是每个单位,这将需要更多的计算机内存)创建一个单独的“ knownWalkability”数组。每个阵列都将包含有关玩家已探索区域的信息,而地图的其余部分则假定是步行的,除非另行证明。使用这种方法,单位将徘徊在死胡同上,并做出类似的错误选择,直到他们学会了解决方法。但是,一旦浏览了地图,寻路将正常进行。
4.更平滑的路径:尽管A *会自动为您提供最短,成本最低的路径,但不会自动为您提供最平滑的路径。看一下在我们的示例中计算出的最终路径(图7)。在那条路径上,第一步是在开始的正方形的下面,并且在右边。如果第一步是直接在起始正方形下面的正方形,我们的路径会不会更平滑?
有几种方法可以解决此问题。在计算路径时,您可能会对方向发生变化的节点进行惩罚,从而对它们的G得分增加惩罚。或者,您可以在计算完路径后遍历路径,寻找可以选择一条相邻节点的路径以使其看起来更好的位置。有关整个问题的更多信息,请查看走向更现实的寻路,是Marco Pinter在Gamasutra.com上的(免费的,但需要注册)文章。
5.非正方形搜索区域:在我们的示例中,我们使用了简单的2D正方形布局。您无需使用此方法。您可以使用形状不规则的区域。想想棋盘游戏风险和游戏中的国家。您可以为这样的游戏设计寻路方案。为此,您需要创建一个表来存储与哪个国家/地区相邻的国家/地区,以及与从一个国家/地区迁移到另一个国家/地区相关的G成本。您还需要提出一种估计H的方法。其他所有操作都将与上述示例相同。在将新项目添加到打开的列表中时,只需使用表格中的相邻国家/地区,而不是使用相邻的正方形。
同样,您可以为固定地形图上的路径创建一个航点系统。航路点通常是路径上的遍历点,可能在地牢中的道路或关键隧道上。作为游戏设计师,您可以预先分配这些路标。如果两个航路点之间的直线路径上没有障碍物,则它们将被视为彼此“相邻”。就像在“风险”示例中一样,您可以将此邻接信息保存在某种形式的查找表中,并在生成新的未清列表项时使用它。然后,您将记录关联的G成本(可能使用节点之间的直线距离)和H成本(可能使用从节点到目标的直线距离)。其他一切将照常进行。
阿米特·帕特尔(Amit Patel)写了一篇简短的文章钻研一些替代方案。有关使用非正方形搜索区域在等距RPG地图上进行搜索的另一个示例,请参阅我的文章“两层A *寻路”。
6.一些速度提示:在开发自己的A *程序或改编我编写的程序时,最终会发现寻路使用了大量的CPU时间,特别是如果您的寻路单元上有相当数量的寻路单元时板和一张相当大的地图。如果您在网上阅读这些内容,即使对于设计诸如《星际争霸》或《帝国时代》等游戏的专业人士,也是如此。如果您发现由于寻路而开始放慢速度,那么以下一些想法可能会加快速度:
考虑较小的地图或较少的单位。
一次不要找到超过几个单位的路径。而是将它们排在队列中,并在多个游戏周期中分散它们。如果您的游戏以每秒40个周期的速度运行,那么没人会注意到。但是他们会注意到,当一群单位同时计算路径时,游戏是否似乎偶尔会变慢。
考虑为地图使用更大的正方形(或您使用的任何形状)。这减少了搜索以找到路径的节点总数。如果您有雄心壮志,则可以设计两个或多个在不同情况下使用的寻路系统,具体取决于路径的长度。这就是专业人员的工作,使用大面积的长距离路径,然后在接近目标时使用较小的正方形/面积切换到更精细的搜索。如果您对此概念感兴趣,请查看我的文章“两层A *寻路”。
对于更长的路径,请考虑设计硬连接到游戏中的预先计算的路径。
考虑对地图进行预处理,以找出地图其余部分无法访问的区域。我称这些地区为“岛屿”。实际上,它们可以是孤岛或其他任何无法围墙的区域。A *的缺点之一是,如果告诉它寻找到此类区域的路径,它将搜索整个地图,仅在通过打开和关闭列表处理了所有可访问的正方形/节点后才停止。那会浪费很多CPU时间。通过预先确定哪些区域不可访问(通过洪水填充或类似的例程),将该信息记录在某种类型的数组中,然后在开始路径搜索之前对其进行检查,可以防止这种情况发生。
在拥挤,迷宫般的环境中,请考虑标记不会导致死角的节点。可以在地图编辑器中手动指定这些区域,或者,如果您雄心勃勃,则可以开发一种算法来自动识别这些区域。给定死胡同区域中的任何节点集合都可以被赋予唯一的标识号。然后,您可以在寻路时安全地忽略所有死角,如果起始位置或目的地恰好在所讨论的特定死角区域中,则只需暂停考虑死角区域中的节点。
7.维护开放列表:这实际上是A *寻路算法中最耗时的元素之一。每次访问打开的列表时,都需要找到F成本最低的正方形。您可以通过几种方法来执行此操作。您可以根据需要保存路径项,并且每次需要查找最低F成本平方时都只需遍历整个列表。这很简单,但是对于长距离来说确实很慢。可以通过维护排序列表并在每次需要最低F成本平方时简单地从列表中获取第一项来改进此功能。当我编写程序时,这是我使用的第一种方法。
这对于小型地图将相当有效,但它不是最快的解决方案。想要真正速度的认真的A *程序员使用一种称为二进制堆的东西,这就是我在代码中使用的东西。以我的经验,在大多数情况下,这种方法的速度至少要快2-3倍,而在更长的路径上,这种方法的几何速度至少要快10倍。如果您有兴趣查找有关二进制堆的更多信息,请查看我的文章“在A * Pathfinding中使用二进制堆”。
另一个可能的瓶颈是在寻路调用之间清除和维护数据结构的方式。我个人更喜欢将所有内容存储在数组中。尽管可以以动态的,面向对象的方式生成,记录和维护节点,但是我发现创建和删除此类对象所需的时间增加了额外的,不必要的开销,从而降低了运行速度。但是,如果使用数组,则需要在两次调用之间进行清理。在这种情况下,您要做的最后一件事是花时间在寻路调用之后将所有内容清零,尤其是当您有大型地图时。
我通过创建一个名为whichList(x,y)的2d数组来避免这种开销,该数组将地图上的每个节点指定为打开列表还是关闭列表。在尝试寻路之后,我没有将这个数组清零。取而代之的是,我在每个寻路调用中重置onClosedList和onOpenList的值,在每次寻路尝试中都增加+5或类似的值。这样,该算法就可以安全地忽略从先前的路径查找尝试中遗留下来的任何数据作为垃圾。我还将F,G和H成本之类的值存储在数组中。在这种情况下,我只需写出任何预先存在的值,而不必在完成后清除数组。
但是,将数据存储在多个阵列中会消耗更多的内存,因此需要权衡取舍。最终,您应该使用最适合的任何方法。
- Dijkstra的算法:虽然A *通常被认为是最好的寻路算法(请参见上面的rant),但至少还有其他一种算法可以使用-Dijkstra的算法。Dijkstra与A *基本相同,除了没有启发式(H始终为0)。因为它没有启发式功能,所以它会在各个方向上均等地展开搜索。您可能会想到,因此,Dijkstra通常最终会在发现目标之前先探索更大的区域。通常这使它比A *慢。
那么为什么要使用它呢?有时我们不知道目标目的地在哪里。假设您有一个资源收集部门,需要去获取某种资源。它可能知道几个资源区域在哪里,但是它想转到最接近的区域。在这里,Dijkstra比A *好,因为我们不知道哪一个最接近。我们唯一的选择是重复使用A *查找到每个距离,然后选择该路径。可能有无数类似的情况,我们知道我们可能要搜索的位置,想找到最接近的位置,却不知道它在哪里或哪个位置最接近。
进一步阅读
好的,现在您已经掌握了基础知识和一些高级概念。在这一点上,我建议涉足我的源代码。该软件包包含两个版本,一个版本为C ++,另一个版本为Blitz Basic。相对而言,这两个版本都受到严重评论,并且应该相当容易遵循。链接在这里。
示例代码:A * Pathfinder(2D)版本1.9如果您无法访问C ++或Blitz Basic,则在C ++版本中可以找到两个小的exe文件。可以通过从Blitz Basic网站下载免费的Blitz Basic 3D演示版(不是Blitz Plus)来运行Blitz Basic版本。
您还应该考虑通读以下网页。阅读完本教程后,它们应该更容易理解。
Amit的A *页面:这是Amit Patel广泛引用的页面,但是如果您没有先阅读这篇文章,可能会有些困惑。非常值得一试。特别是请参阅阿米特(Amit)关于该主题的想法。
Smart Moves:智能路径查找:Gamasutra.com的Bryan Stout撰写的这篇文章需要注册才能阅读。该注册是免费的,值得阅读,仅适用于本文,而这里的其他资源则少得多。Bryan用Delphi编写的程序帮助我学习了A *,这是我A *程序背后的灵感。它还描述了A *的一些替代方法。
地形分析:这是Ensemble Studios专业人士Dave Pottinger的高级文章,但很有趣。这个家伙协调了帝国时代和帝王时代的发展。不要指望这里的所有内容,但这是一篇有趣的文章,可能会给您一些自己的想法。它包括对mip映射,影响映射以及其他一些高级AI /寻路概念的讨论。其他一些值得检查的站点: