A *路径搜索入门php
帕特里克·莱斯特发表于2003年10月8日下午8点33人工智能html
若是您发现文中有错误或问题(丢失的影像或文件,受损代码,不正确的文本格式等),致使没法阅读它时,请联系编辑,以便能更正。感谢您帮助咱们改善这个资源。程序员
更新于2005年7月18日算法
这篇文章已被翻译成阿尔巴尼亚语,中文,法语,德语,葡萄牙语,俄语和西班牙语。欢迎其余的翻译。在这篇文章的末尾有联系的电子邮件地址。数组
对于初学者, A *(读A-星,译者注:老外读A-star)算法可能有些复杂。虽然在网上有不少解释A *算法的文章,大多数写给有基础的。这篇是给纯新手的。(译者记:各位新手若是有看不懂的,对不起是翻译的错。)安全
本文并不试图成为这个主题的权威著做。相反,是阐述原理并准备让你能去阅读全部其余的材料及明白他们在说什么。在本文的末尾提供一些较好,能进一步阅读的资料的连接。数据结构
最后,这篇文章不是具体的方案。你应该可以接受在文中出现的任何计算机语言。就如同你所指望的那样,无论怎样, 在本文的末尾,有一个演示程序的连接。演示包中有两个版本:一个是C++,一个是Blitz Basic(http://www.blitzbasic.com/Home/_index_.php)。若是想运行A *的程序,也有可执行文件的。app
但是咱们正在超越本身。从头开始吧...编辑器
■简介:搜索区域布局
假设要想从A点到达B点。中间有一堵墙把AB两点隔开。如面所示,用绿色表示起点A,用红色表示终点B,并用蓝色表示中间的那堵墙。
[图1]
首先,把搜索区域分割成由方格组成的网格。这叫简化搜索区域,是路径搜索的第一步。这种方法把搜索区域简化成一个二维数组。数组中的每个元素表明了网格里的一个方格,方格被记录为能走和不能走。从A点到B点所通过的方格叫路径。一旦路径被找到,就能够从一个方格的中心移到下一个的中心,直到到达目标。
这些中心点被称为“节点”。在看别的路径搜索资料时,常常会看到讨论节点。为何不叫它们方格呢?由于真的有可能不把路径搜索区域分割成方格。能够是矩形,六边形,三角形或任何形状。节点能够用任何形状表示- 在中心或者沿着边缘,或其余任何地方。不过,由于方格是最简单的,咱们使用方格。
■开始搜索
一旦把搜索区域简化成可管理数量的节点,就像上面所说的网格布局,下一步就是进行搜索来找到最短路径。从A点开始,检查相邻的方格并向外普及搜索,直到找到目标。
执行如下操做开始搜索:
1.从起点A开始,并将它添加到 “开启列表”。开启列表有点像一张购物单。尽管如今列表里只有一个项目,但之后会多起来。它包含了多是你想要的,也可能不是。基本上,这是须要被检查的方格的列表。
2.寻找起点相邻的全部可到达或能走的方格,忽略有墙,水或其余非法的地形。把它们添加到开启列表。对于每一个方格,保存A点做为它们的“父”。当要追溯路径时,父是很重要的。稍后会解释它。
3.从开启列表删除起点A,并将它添加到不须要再次查找的“关闭列表”。
在这一点上,你应该有相似下面插图的印象。在该图中,位于中心的深绿色方格就是开始方格。它是轮廓为浅蓝色,以指示它已被添加到关闭列表。对在开启列表的全部与它相邻的方格进行检查,而且用浅绿色来框记它们。每一个方格都有一个灰色的指针指回它们的父,也就是开始方格。
[图2]
下一步,咱们选择了开启列表上的一个相邻方格,并或多或少地重复前面的过程,以下所述。可是,咱们选择哪方格呢?一个具备最小F值的。
■路径评分
在算出的路径时,下面的公式是肯定要使用的方格的关键:
F = G + H
这里
G =从起点A沿着生成的路径移动到一个给定方格上的运行成本。
H =从给定方格移动到终点B的估计运行成本。这一般称为启发式,这可能有点混乱。由于是一个估测的因此这样称呼。在找到路径以前,咱们真的不知道实际的距离,由于各类各样的事情都在途中(墙,水等)。在本教程中给出一个计算H的方法,但在网上的其余文章里能找到许多计算H方法。
经过反复遍历开启列表,选择具备最小F值的方格来生成咱们的路径。在本文中这个过程将有进一步更详细的说明。首先来仔细看看如何用公式计算。
如上所述,G是从起始点移动到给定点所生成路径的运动成本。在这个例子中,咱们将指定每一个水平或垂直移动方格成本为10,对角线移动的成本为14。咱们使用这些数字是由于沿斜边移动是2的平方根(不要惧怕),是水平或垂直移动的大约1.414倍。咱们使用10和14是为了简单起见。比例大体是正确的,又能避免计算平方根和小数。这不仅是由于咱们是愚笨的,不喜欢数学。采用这些数字是让计算更快,太快了。你很快就会发现,若是你不使用这些捷径,路径搜索可能会很缓慢的。
因为咱们计算的G值是沿特定的路径到给定的方格,这个办法是找出那个方格的父的G值,而后加10或14取决于它从父的移动是正交(非对角线)仍是对角线。在这个例子中这个方法的须要将进一步变得明显一点,由于咱们从开始方格开始获得一个以上的方格。
H能够用各类方式估计。在这里使用曼哈顿方法,计算从当前方格到目标方格水平和垂直方向移动方格的总数,忽略对角运动,忽略用这种方式可能的任何障碍。而后,将总数乘以10,水平或垂直移动一格的成本。这是(可能)被称为曼哈顿方法,由于它像计算城市街区的数量从一个地方到另外一个地方,并不能沿对角穿过。
阅读本说明,您可能已经猜到了启发式仅仅是当前方格与目标之间的剩余距离的一个“像乌鸦飞似的”(译者注:直线距离)粗略的估计。不是这样的。咱们实际上试图估计沿路径的剩余距离(一般是更远)。估计越是接近实际剩余距离,就是越快的算法。若是高估了这个距离,那么,它不能保证给初的最短路径。在这样的状况下,咱们有所谓的“不可接受启发式”。
从技术上讲,在这个例子中,曼哈顿方法是不可接受的,由于它稍稍高估了剩下的距离。可是咱们会用也无妨,由于它是一个更容易理解咱们意图的,由于它只是一个轻微的高估。在极少的状况下,获得的路径不是最短的,这将是逼近最短。想了解更多?你能够在这里(http://www.policyalmanac.org/games/heuristics.htm)找到关于启发式相同的或附加说明。
F是G加H的和。搜索的第一个步骤的结果能够从下面的说明中看出。在F,G和H的值被写入在每一个方格。正如在紧挨着开始方格右侧的方格上,F被打印在左上角,G被打印在左下角,而H被打印在右下角。
[图3]
那么,来看看其中一些方格。在有字母的方格上,G = 10,这是由于它是在一个水平方向的距离起始方格仅有一个方格。紧邻在起始方格的上方,下方,以及左边的方格有相同的G值10,对角线方格G值为14。
H值是经过估计到红色目标方格的曼哈顿距离,计算方式是仅有水平和垂直方向移动,并忽略墙上的。使用这种方法,从这个方格开始直接向右3个格就是红格,H为30。(译者注:直线距离)那么高于这个方格的方格的H值是4格距离(记住,只能水平或垂直移动)的一个H值为40。你也许能够看到了为其余方格计算H值的方法。
每一个方格的F值,再次,只是简单地把G和H加在一块儿的计算结果。
■继续搜索
要继续搜索,咱们简单地选择在开启列表中具备最小F值的方格。而后,咱们用选定方格做如下事情:
1.把它从开启列表取出,并添加到关闭列表。
2.检查全部的相邻方格。忽略那些在关闭列表里或不能走的(墙,水或其余非法地形),若是它们还不在开启列表中,添加到开启列表。将选定方格做为新方格的“父”。
3.若是相邻的方格已经在开启列表,查看沿这条路径到那个方格是不是好的。换句话说,检查看看若是咱们使用当前方格到那里,方格的G值是不是较低,。若是不是,什么也不作。
另外一方面,若是新路径的G值较低,改变相邻方格的父到选定方格(图中上方,改变指针的方向指向在所选择的方格)。最后,从新计算那个方格的F值和G值。若是这彷佛使人困惑,在后面你会看到它的说明。
好吧,看看这是如何工做的。最初的9个方格,在起始方格被放到关闭列表后还有8个在开启列表。其中,具备最低F值的是一个紧邻起点右侧的方格,其F值为40。所以,选择这个方格做为下一个方格。以下图所示高亮的蓝色的部分。
[图4]
首先,从开启列表中删除它,并把它添加到关闭列表(这就是它以高亮蓝色显示的缘由)。而后检查相邻的方格。好了,这个方格的相邻右边的是墙上的方格,忽略它。紧挨着左边的是开始方格。在关闭列表上,因此也忽略它。
其他4个方格已经在开启列表中,因此须要检查若是使用那些方格做为路径是否比使用这个方格到那里更好,将G值做为参照点。来看看在选择方块右上的这个方格吧。它的G值是14,若是咱们经由当前方格到达那里,G值将等于20(10,如今方格的G值,再加上10来垂直移到它的上面)。G值20比14高,因此这不是一个更好的路径。若是你看一下图能更好的理解这些。从开始方格方格沿对角线移动一个方格到那里更直接些,而不是水平移动一个方格,再垂直移动一个方格。
当对在开启列表中的4个相邻方格重复做这个过程,会发现没有路径比当前的方格有提升,所以不改变任何东西。因此,如今,看了全部的相邻方格,用这个方格做完检查了,并准备移动到下一个方格。
那么,经过开启列表,如今减到7个方格的列表,咱们再选择一个具备最小F值。有趣的是,在这种状况下,有两个方格的F值是54,那么咱们选择哪个呢?这其实并不重要。为了快速的目的,选择您最后一个添加到开启列表中的方格能够更快些。这种偏向的搜索比慢慢找搜索到更有同意,当你更接近目标时。但它其实并不重要。 (不一样的处理形成了两个版本的A *可能找到不一样的等长路径。)
所以,咱们选择开始方格右下的方格,以下图所示。
[图5]
这一次,检查相邻的方格,会发现,一到右边当即是一堵墙上的方格,因此忽略。一样运用刚才上面的。还忽略墙下方的方格。为何呢?由于你不能让方格直接从当前方格切割穿越附近的墙角。在这个过程当中你真的须要往下走,而后再挪动那个方格,绕着墙角移动。 (注:切割墙角的规则是可选的依赖于你的节点如何放置。)
那剩下5个方格。另外两个方格低于当前方格还没有在开启列表中,因此将它们添加并把当前方格变成它们的父。其余3个方格,有2个已经在关闭列表(开始方格,和一个略高于目前的方格上,在蓝色突出两个图中),因此忽略它们。而最后的方格,眼前的当前方格左侧,进行检查,若是你去经过当前方格到那里看是否有低的G值。没有方格了。因此,就大功告成了,已经检查完开启列表中的下一个方格。
重复这个过程,直到添加目标方格到关闭列表,此时它看起来像下面的插图。
[图6]
在上图中,须要注意的是开始方格下两格方格的父已经改变。以前,它的G值为28,指回它右上的方格。如今它有一个值为20,并指向它上面方格。这发生在沿路径搜索,对G值被检查,并采用了值小一些的做为新的路径- 这样父被切换,G值和F值也从新计算。在这个例子中虽然这种变化彷佛并不过重要,有不少可能的状况,在肯定到达目标的最佳路径时,持续的检查将会产生很大的差别。
那么,如何肯定路径呢?简单,刚开始在红色的目标方格,并努力向父方格后移,下面的箭头。这最终会把你带回到开始方格,这就是你的路径。它应该看起来像下面的插图。移动从开始方格A到目标方格B就是从路径上每个方格(节点)的中心移动到下一个方格的中心的问题,直到到达目标。
[图7]
■A *方法总结
好了,如今经过解释,在一个地方,展现一步一步的方法(译者注:在这儿,把每一个步骤整理一下):
添加开始方格(或节点)到开启列表。
重复如下操做:
a) 寻找开启列表上最小F值的方格。将它做为当前方格。
b) 切换到关闭列表。
c) 对于当前方格临近的8个方格的每个....(For Each)
若是不能走,或者若是它在关闭列表上,忽略它。不然,执行如下操做。
若是不在开启列表中,把它添加到开启列表。使当前方格成为这个方格的父。记录的方格F值,G值和H值。
若是在开启列表了,检查看看采用G值来衡量这个路径到那个方格是不是更好的。更低的G值意味着这是一个更好的路径。若是是这样,把方格的父改成当前方格,并从新计算方格的G值和F值。若是你保持开启列表按F值排序,因为这个变化你可能需重存列表。
d)当你中止:
在目标方格添加到关闭列表的状况下,路径已经被发现(见下面的注),或没法找到目标方格,而且开启列表是空的。在这种状况下,不存在路径。
保存路径。从目标方格往回走,从每一个方格移到其父,直到到达开始方格。这是想要的路径。
注:在早期版本的文章中,有人建议,当目标方格(或节点)已经添加到开启列表,而不是关闭的列表,你就能够停下来。这样作会更快,它几乎老是会给你的最短路径,但并不是老是如此。有些状况下,当从第二移动到最后一个节点到最后的(目标)节点的运动成本可能有明显变化时,这样作可能产生影响--例如,若是河流在两个节点之间交叉的状况下。
■小“愤”
请原谅题外话,但值得指出的是,当在网上阅读的A *路径搜索,并在各种论坛上的各类讨论时,偶尔会看到有人提到某些代码不是A *。对于A *使用方法,须要包含上面讨论到的元素 -- 特别是开放列表和关闭列表和路径采用F值,G值和H值。有不少其余的路径搜索算法,一般被认为是最好的方法但不是A *。在本文的末尾有布莱恩斯托特的讨论,包括他们的不少一些利弊引用的文章。有时替代品在某些状况下更好,但你应该明白你是正在进入的。(译者注:别被误导熏心)好了,爽了。回到话题。
■实施上的注意事项
如今您了解了基本的方法,当你编写本身的程序时,有一些额外的事情要考虑。下面给出我用C ++和Blitz Basic编写的程序,用其余语言也一样有效。
1.其余单元(防止碰撞):若是你碰巧仔细看个人演示代码,你会注意到它彻底忽略了屏幕上的其余单元。这些单元彼此穿过。根据游戏,这多是能够的,多是不能够的。若是在路径搜索算法里想考虑其余单元,并让它们彼此走动,我建议你只考虑中止的单元或路径搜索附近计算路径的单元,用不能走来处理他们的当前位置。对于正在移动的相邻单元,能够经过处罚沿着各自路径的节点阻止碰撞,从而促使路径寻找单元找到替代路径。(在#2有更多的描述)。
若是选择考虑正在移动的单元和路径寻找上不相邻的其余单元,将须要开发一种方法来预测他们会在任何给定的时间点,使他们可以获得适当的回避。不然,你极可能会有用曲折来避免什么也没有的其余单元的奇怪的路径。
你还会,固然,须要开发一些碰撞检测代码,由于不管多么好的路径在它的计算时,事情可能随时间而改变。当发生碰撞时的单位必需要么计算新的路径,或者若是其余单元是移动且不是一个迎面碰撞,在当前路径继续以前等待其余单位经过。
这些技巧多是足以让你开始。若是您想了解更多,这里有一些你可能会发现有用的连接:
角色的转向行为:
http://www.red3d.com/cwr/steer/
克雷格雷诺的方向盘上的工做是从路径搜索有点不一样,但它能够与路径搜索集成,以作出更完整的移动和防撞系统。
计算机游戏中的长短转向:
http://ducati.doc.ntu.ac.uk/uksim/uksim%2704/Papers/Simon%20Tomlinson-%2004-20/paper04-20%20CR.pdf
在转向和路径搜索的一个有趣的调查。这是一个PDF文件。
协调机组运行:
http://www.gamasutra.com/features/game_design/19990122/movement_01.htm
由帝国时代的设计师戴夫·乍的两部分组成的第一系列在造成和基于组的运动。
实现协调运动:
http://www.gamasutra.com/view/feature/3314/implementing_coordinated_movement.php
戴夫·乍的两部分组成的第二系列。
2.多样的地造成本:在本教程和我附随的程序中,地形仅仅是两件事情之一 – 能走和不能走。可是,若是虽然有能走的地形,可是须要更高的移动成本?沼泽,丘陵,地下城的楼梯,等等 - 这些都是能走的地形的例子,但成本比平坦的开阔地要高。相似地,道路可能具备较低的运行成本比周围的地形。
这个问题很容易经过任何给定节点的G值加地造成本的计算处理来实现。简单地添加一个额外的成本到这样的节点。A *路径搜索算法是用来寻找最低成本路径,应该很容易地处理这个问题。在我描述的简单的例子中,当地形只有能走和不能走,A *将查找最短,最直接的路径。可是,在可变成本的地形环境中,以最少的成本路径可能行走了较长的距离 - 就像绕过的沼泽道路,而不是直接经过它。
一个有趣的附加考虑是专业人士称之为“影响映射” 。正如上述的可变成本的地形,你能够建立一个额外的积分系统,并将其应用到AI的路径。试想一下,你有一些穿过山区的单元的地图。每当计算机发送通某人经过路径时,它被重击。若是你愿意,你能够建立一个发生大量屠杀来处罚节点的影响地图。这会教电脑偏袒安全的路径,并帮助它避免愚蠢的状况下,它经过一个特定的路径不断派遣军队,只是由于它是短(但更危险)。
另外一种可能的用法是惩罚沿着路径附近移动中的节点。A *的其中一个缺点是,当一组的单元全都尝试找到的相似位置的路径,一般有一个显著程度的重叠,与一个或多个单元试图利用相同或相似的路线到它们的目的地。添加一个已经被其余单元“叫停”点球节点将有助于确保必定程度的分离,并减小碰撞。不要把这样的节点视为不能走,然而由于你还愿意多个单元可以依次挤过狭窄的通道,若是有必要的。此外,你应该只处罚路径搜索附近的单元,不是全部的路径,不然你会获得避免单元的单元的奇怪躲避行为,都远不及他们当时的路径。此外,你应该只惩罚节点沿着一条当前或将来的路径的一部分,而不是已经访问过并留下之前的路径节点。
3.处理未探索区域:你曾经玩过一款PC游戏,计算机老是准确的知道路该如何走,即便地图尚未被探索?根据不一样的游戏,总获得那样好的路径搜索是不现实的。幸运的是,这是很容易处理的问题。
答案是建立一个独立的“已知的经过性”数组为每一个各类各样的玩家以及电脑对手的(每一个玩家,不是每个单元 - 那将须要大量的计算机内存)。每一个数组将包含有关该玩家已探索区域的信息,与地图的其余部分直到证实假设为是可行的。使用这种方法,单元将漫步死角,使相似的错误选择,直到他们发现周围的路。一旦地图被探索,然而,路径搜索会正常工做。
4.更平滑的路径:虽然A *会自动给出最短,成本最低的路径,它不会自动给出看起来最平滑的路径。看一看例子(图7)计算的最终路径。在该路径中,第一个步骤以后是到开始方格的右侧。若是第一步是从起点的正下方,咱们的路径不更更平滑了些吗?
有几种方法来解决这个问题。当你正在计算路径,你能够处罚那里些方向有变化的节点,增长了处罚他们的G值扣分。或者,你能够在计算后浏览你的路径,寻找在选择相邻节点的地方会给你一个看起来更好的路径。欲了解更多关于整个问题,看看向更加逼真路径搜索(Toward More Realistic Pathfinding),一个(免费的,但须要注册)在Gamasutra.com上Macro Pinter的文章。
5.非方格搜索区域:在咱们的例子中,咱们使用了一个简单的二维方格布局。你并不须要使用这种方法。你可使用不规则的形状区域。想一想风险的棋盘游戏,以及在游戏中的国家。你能够设计一个路径搜索方案给像那样的游戏。要作到这一点,你须要建立一个表,用于存储毗邻的国家,并与移动从一个国家到下一个相关的G值。你还须要拿出用于估计H.其余一切会被处理同样在上面的例子中的方法。而不是使用相邻的方格,在增长新的项目到开启列表时在表中你会简单地查找到相邻国家。
一样,你能够为一个固定的地形图建立路径的路标系统。路标一般走过的路径上的点,也许在一个地牢的道路或关键的隧道上。做为游戏设计者,你能预先指定这些路点。两个路标会被认为是“相邻”彼此是否有它们之间的直线路径上没有障碍。因为在风险的例子,您将节省在某种类型的查找表这个邻接信息,并用它生成新的开启列表项目时。那么你会记录相关的G值(可能经过使用节点间的直线距离)和H成本(可能使用从节点到目标的直线距离)。一切将继续如常。
阿米特·帕特尔还写了一个简短的文章钻研一些替代品。对于使用非方形的搜索区域上等距RPG地图搜索的另外一个例子,看看个人文章两层的A *路径搜索(http://www.policyalmanac.org/games/twoTiered.htm)。
6.一些超速提示:当你开发本身的A *程序,或者改编我写的,你最终会发现路径搜索使用你的CPU时间大幅大块,特别是若是你对至关大数量的路径搜索单元的板和一个至关大的地图。若是你在网上读过的东西了,你会发现,这是真实的,即便设计像星际争霸或帝国时代游戏的专业人士。若是你看到的东西开始放缓,因为路径搜索,这里有一些想法,可能会加快速度:
■考虑一个小地图或更少的单位。
永远不要作一次几个单元的路径搜索。相反,把它们放在一个队列,它们分布在几个游戏循环。若是你的游戏在运行时,好比说,每秒40个周期运行,没有人会注意到。但他们会发现,当在同一时间一群单元都在计算路径时游戏彷佛在一段时间放慢每一次。
请考虑使用更大的方格(或者任何你正在使用的形状)为您的地图。这减小了搜索以找到的路径的节点的总数。若是你有雄心,能够设计出了用于在不一样的状况下,这取决于路径的长度的两个或更多个路径搜索系统。这是专业人士作的,使用大面积的长路径,而后切换到更精细的使用较小的方格/地区搜索,当你接近目标。若是你有兴趣在这个概念,看看个人文章两个层次的A *路径搜索。
对于更长的路径,考虑修订是硬链接到游戏预先计算好的路径。
考虑预处理地图找出哪些领域是从地图的其他部分没法访问。我把这些领域的“孤岛”。在现实中,他们能够是岛屿或者其余任何地区,是另有围墙关闭,没法访问。其中A *的缺点之一是,若是你告诉它来寻找路径等方面,它会搜索整个地图,停车,只有当每平方访问/节点已经过打开和关闭名单处理。这会浪费大量的CPU时间。它能够经过预先肯定哪些地区是不可访问(经过洪水填充或相似的程序),记录在某种类型的阵列信息,而后在开始路径搜索前检查它来预防。
在拥挤的,迷宫似的环境中,考虑节点标记不随地致使的死角。这些区域能够手动预先指定的地图编辑器,或者若是你有雄心的,你能够开发一个算法,自动识别等领域。在给定的死胡同区域节点的任何集合能够赋予一个惟一的识别号码。而后路径搜索时,只停下来考虑一个死胡同区域节点,若是起始位置或目的地刚好是在特定的死胡同区问题,你能够放心地忽略全部的死角。
7.维护开启列表:这其实是A *路径搜索算法中最耗费时间的元素之一。您能够访问开启列表时,都须要找到具备最小F值的方格。有几种方法能够作到这一点。根据须要,你能够保存路径项目,每次当你须要找到最小F值的方格时,简单的遍历整个列表。这是简单的,但对于长路径很慢。这能够经过维护一个排序的列表,每次须要最小F-成本方形时间只需抓住了第一个项目从名单获得改善。当我写个人程序,这是我用第一种方法。
这将工做得至关好为小地图,但它不是最快答案。严重的A *程序员谁想要真正的速度使用一种叫作二进制堆,这是我在个人代码中使用。在个人经验,这种方法将是至少2-3倍的速度在大多数状况下,而且在几何形状更快(快10+次)上较长的路径。若是你主动去寻找更多关于二叉堆,看看个人文章,在A *路径搜索使用二进制堆(http://www.policyalmanac.org/games/binaryHeaps.htm)。
另外一种可能的瓶颈是你的方式明确和维护路径搜索调用之间的数据结构。我我的更喜欢存储全部阵列。虽然节点能够生成,记录并保存在一个动态的,面向对象的方式,我发现,建立和删除这些对象所需的时间量增长了额外的开销,没必要要的水平会减慢速度。若是你使用数组,不过,你须要调用之间干净的东西了。你会想在这种状况下的最后一件事就是花零时间作完一切了在调用路径搜索后,特别是若是你有一个大的地图。
我避免这种开销经过建立一个二维数组称为whichList(X,Y),其指定在每一个节点上个人地图做为任一开启列表或关闭列表上。路径搜索的尝试以后,我不归零数组。相反,我在每个路径搜索呼叫复位onClosedList和onOpenList的价值观,每一个路径尝试寻找相似+5什么都递增。经过这种方式,算法能够放心地忽略垃圾从之前的路径搜索的尝试遗留任何数据。我也喜欢存放F,G和H阵列的成本值。在这种状况下,我只是写在任何预先存在的价值和不打扰清除阵列时,我作的。
在多个阵列存储数据占用更多的内存,虽然如此,有一个权衡。最终,你应该使用什么方法,你是最舒服的。
8. Dijkstra的算法:当A *一般被认为是最好的路径搜索算法(见上面的小愤),存在至少一个其它的算法有其用途 - Dijkstra算法。 Dijkstra的是基本相同的A *,除了没有启发式(H始终为0)。由于它没有启发式,它经过在每个方向一样扩大了搜索。正如你可能想象的,由于这Dijkstra算法一般是结束了探索一个更大的区域以前目标被发现。这一般使得它比A *慢。
那么,为何使用它?有时候,咱们不知道咱们的目标位置是。假设你有一个须要去得到某种资源的一些资源收集装置。它可能知道几个资源区域,但它但愿去最近的一个。在这里,Dijkstra的比A *更好,由于咱们不知道哪个是最接近的。咱们惟一的选择是重复使用A *查找到每个的距离,而后选择这条道路。可能有无数相似的状况,咱们知道那种位置,咱们可能会寻找的,想找到最近的一个,但不知道它在哪里或哪个多是最接近的。
■延伸阅读
好了,如今你已具有了基础知识和一些先进的概念。在这一点上,我建议你到涉水个人源代码。该软件包里有两个版本,一个是C ++的,一个是Blitz Basic的。两个版本都有大量注释,相对来讲应该是至关容易跟上理解。这里是连接。
http://www.blitzcoder.com/cgi-bin/showcase/showcase_showentry.pl?id=turtle177604062002002208&comments=no"
(译者注:这个连接如今已经不能用了,请用:http://www.policyalmanac.org/games/AStar.zip)
演示代码:A *探路者(2维)1.9版
若是您没有接触到C ++或Blitz Basic,两个小的EXE文件能够在C ++版本中找到。Blitz Basic版本能够经过在Blitz Basic网站下载Blitz Basic 3D(不加Blitz Plus)的免费试用版原本运行。
你也应该考虑经过如下网页阅读。若是你已经阅读本教程,如今他们要容易明白得多。
Amit的A *页:
http://www-cs-students.stanford.edu/~amitp/gameprog.html#Paths
这是一个由阿米特帕特尔写的有很是普遍引用的页面,若是你尚未看过本文,就看它可能有点混乱。很是值得一试。尤为是Amit本身的想法的话题。
智能移动:智能路径查找:
http://www.gamasutra.com/view/feature/3215/myths_and_facts_in_avoiding_.php
本文由布赖恩·斯托特在须要注册阅读的Gamasutra.com发布的。注册是免费的,很值得去看看,更不用说那些可用的资源。由布莱恩用Delphi编写的帮助我学习A *程序,它是个人A *程序背后的灵感。它也介绍了一些A *替代品。
地形分析:
http://www.gamasutra.com/features/gdcarchive/2000/pottinger.doc
这是一种先进的,且颇有趣,文章由涉猎全面的工做室的专家Dave Pottinger撰写。这家伙协调过帝国时代和世纪国王的开发。不要期望在这里明白了一切,但它是一个有趣的文章,可能会给你一些本身的想法。它包括Mipmapping(译者注:三维计算机图形的贴图渲染中有一个经常使用的技术),影响映射,还有其它一些高级AI /路径搜索的概念进行了。
其余一些关于路径搜索的网站值得一试(译者注:基本已不能访问):
aiGuru: Pathfinding
Game AI Resource:Pathfinding
GameDev.net:Pathfinding
好了,就是这样。我很想到你使用这些概念编写程序。我能够经过邮箱收到。
pwlester@policyalmanac.org
在置笔以前,祝你好运!