游戏中的AI算法总结与改进

本文探讨了游戏开发中人工智能角色的寻路算法,包括有限状态机、行为树、AStar算法及其优化、电势矩阵寻路算法等多种经典算法和技术。通过分析不同算法的特点,为游戏设计者提供了丰富的解决方案。

参考文章:

http://games.sina.com.cn/zl/duanpian/2014-03-11/105973.shtml

http://www.oschina.net/translate/understanding-steering-behaviors-collision-avoidance?cmp

http://blog.youkuaiyun.com/ityuany/article/details/5509750

 

 

一. 当前人工智能的定义思考

        人工智能(AI, Artificial Intelligent),指的是通过算法编程使计算机模仿人完成一些像人一样的任务,同时在执行任务时模仿人的思维和智慧,甚至通过大量学习训练积累学习经验,提高自身解决问题的智慧和效率。人工应用广泛,像智能交通,人工智能机器人,智能家电等,通过模仿人的智慧代替人类完成一些重复性工作。人工智能目前依旧在人工的阶段,即计算机的智能仍然在人类人工下可控可预见的范围内运行,人工智能实际上是在大量的逻辑运算和大量的数据输入处理基础上进行实现,人工智能需要大量的数据输入训练才能使其更加智能化。典型的近日谷歌的人工智能Alpha狗即进行了成千上万次的围棋棋局训练才得以打败世界围棋冠军李世石。与人类智能不同的是人工智能依赖自身的强大计算速度大量的学习而智能化,人类智能则可通过少量学习而理解更多相关的事物。在目前人类对自身智能了解仍旧不够充分的情况下,人工智能依旧依赖于人工处理上。

 

 

二. 游戏中的AI

 

        游戏中尤其是虚拟现实游戏追求创建一个尽可能真实的虚拟世界环境,虚拟世界中需要设置很多NPC(Non-Player Character)人物与玩家交互互动,这需要NPC人物具有智能与玩家更自然真实的交流,帮助玩家顺利进行游戏,提高游戏真实性体验。NPC的智能动作是一系列的有限状态集合,其连贯合理的状态的改变实现与玩家交互。NPC和玩家共同组成游戏中的角色群体。

        另一方面,游戏中AI技术的一个核心的内容是游戏中角色的智能寻路,人物能够像人一样避开障碍物选择合理的路径从起点到达目的地,或者引导玩家到达虚拟场景中的指定地点。游戏中的寻路算法主要分盲目式搜索和启发式搜索两种,同图论中的最短路径问题相联系,在图论的数据结构上进行实现。游戏寻路算法中最基本最成熟的是A Start启发式函数寻路算法,市面上有大量RPG角色游戏以及战略游戏等当中的智能寻路皆使用到基于A Star算法或者其变种优化算法以及与其他算法结合的混合算法。另外在应用中开发者们利用物理中的电势原理设计了基于电势矩阵的负电荷自动被吸引寻路算法,是一种新兴的创意性思路。图论中的深度优先搜索算法(DFS)和广度优先搜索算法以及Dijksrta单源最短路径贪心算法都是典型的盲目式搜索算法。除以上目的点明确的路径寻路以外游戏中还需要一种随机寻路算法,主要应用于怪物在某个区域毫无目的的盲目闲游,使怪物显得自然化、动态化。

 

2.1 有限状态机(FSM);行为树(Behavior Tree)、决策树

(1) 有限状态机:

 

        Unity中有限状态机(FSM, FiniteState Machine)的一个重要应用是控制一个角色的动画系统连续性切换:

 

        有限状态机动画是将一个游戏人物角色的活动分割为有限个状态的集合,通过条件触发状态的转换使角色产生一系列连续的动作,状态之间的方向箭头代表状态转换的方向和转换的条件,如图中展示一个最简单的有限状态机动画系统,通过条件触发人物休息、行走、跳跃等动作状态的连续变换。有限状态机动画在游戏中的NPC中应用最多,但有限状态机动画的AI性能较差,动作有限很容易被玩家预测而显得生硬,真实感被很大程度上限制。

 

(2) 行为树:

http://www.cnblogs.com/designyourdream/p/4459971.html

 

(3)决策树:

http://www.cnblogs.com/leoo2sk/archive/2010/09/19/decision-tree.html

 

 

2.2 寻路导航图

        游戏中进行寻路前需要将地形中的可行走区域与障碍不可行走区域分开,同要对可行走区域进行不同方法的分割,分割成结点从而可以转化成算法和数据结构可以处理的对象,行走区域的分割有以下几种类型:

 

 

 

1.删格化导航图

        类似于光栅图像,将地图用等间距的方格分割,表示成一个栅格矩阵,每个栅格代表一个位置点,同时这个点作为矩阵的一个值可以通过加权重来表示该点是否是障碍物,如果不是障碍物又是哪些不同的地形等等。栅格化导航图相对其他类型的导航图划分更精细准确,同时会占用大量内存。

2.多边形导航图

        多边形导航图是将可行走地形用凸多边形来分割填充,分割的原则是相邻的两个多边形之间可以无障碍的直接通过。针对不同的地形可以选择不同的多边形。

3.可视点导航图

        用一系列有代表性的关键点来全面覆盖可行走地形的核心框架,这样使地形大大简化,地图的搜索空间被大程度的瘦身,有利于提高搜索效率,但是在这种地图中生成的路径会出现使角色走“Z”字形的缺陷。WayPoint寻路法即基于此种导航图。

 

 

三. 游戏AI寻路算法初探

 

3.1 A Star寻路算法

        A Star算法又形象的称为A*算法,是一种启发式函数路径计算搜索算法,算法中通过设计合理的启发函数可以大大减少寻路过程中的计算量,提高计算效率,而估计不精确是启发式函数的特点,因此使用A*算法计算的路径可能不是人所理解的最优路径,但A*可以高效的提供一种在游戏中相对合理的路径,在游戏寻路中应用广泛。

 

1. A*中的结点(Node)

        结点是A*算法计算的基本单位。由于A*算法可应用于多种导航图,在不同的导航图中结点的表示各不相同,在多边形导航图中一个多边形为一个A*结点,可视点导航图中每一个可视点为一个A*结点,删格化导航图中每一个矩形格子为一个A*结点。

 

2. 估价函数

        估价函数用于评价一个结点被选做路径点的概率,其利用了结点自身与起始点位置关系的信息,启发算法搜索较合理的路径,路径即相邻结点的集合序列,估价函数表达式如下:

 F(N) = G(n) + H(n)

        公式中的F(n)表示第n个结点的估价值,G(n)表示结点按照某种距离规则到起点的距离值,H(n)表示结点按照某种距离规则到终点的距离值,因此估价值F(n)越小,代表路径行走消耗越少,则被选为路径点的概率越大。

        距离计算规则主要有曼哈顿距离、欧几里得距离和对角线距离三种。曼哈顿距离指的是两点之间水平距离与竖直距离之和,欧几里得距离指的是两点之间的几何距离,对角线距离指的是水平距离和竖直距离中的较大者。

在P1、P2两点之间构成的直角三角形中,假设水平直角边长度为A,竖直直角边长度为B,斜边距离为C,则:

曼哈顿距离: D1 = A + B

欧几里得距离:D2 = C

对角线距离: D3 = max{A,B}

在算法的实际应用中,根据[13]沈健的研究结论欧几里得距离在寻路计算效率上表现更佳,具体根据不同情形常常进行混合应用以更好提高计算效率和算法适应性。

 

3. A*算法的执行过程

算法维护Open表和Closed表两个表,前者存放可能的待访问的结点,后者不断加入估价计算后的结点。

(1) 算法初始将起点加入Closed表,其估价函数值:F(0) =H(0), 其中G(0) = 0,为其到自身的距离。

(2) 然后将所有与当前点(暂时是起点)相邻的结点加入Open表,如果已经加入则不操作。在当前结点估价函数值的基础上,累加计算所有相邻结点的F、G、H值,如果已在Closed表中的结点的新的估价值比之前的小,则更新为更小的值,将F值最小的结点选为新路径点,设置成当前结点的子节点,新路径点继续做为当前结点继续遍历相邻的结点。

(3) 重复(2)的操作当终点加入Closed表时,算法结束,根据父子结点的关系可得到最终路径,如果Open表为空时终点依旧不在Closed表中,则搜索失败。

(4) 以上算法执行过程中障碍物结点不加入Open表中计算。

 

        A*算法最简单的应用是在经典的砖块地图(Tile)中,每一个方格看做一个结点,从当前方格结点可以往上、下、左、右、左上、右上、左下、右下八个方向到下一个相邻结点,实际开发中需要考虑结点单元的大小,即贴图方格的密度。典型的《坦克大战》游戏即基于砖块地图。地图中的方格分为可行走(Moveable)和不可行走(Not Moveable)两种,不可行走的结点算法中会忽略跳过不加入计算。在砖块地图中,为了计算简便,的计算常采用欧几里得距离,的计算采用曼哈顿距离。

 

4. 拐点法优化A*路径

        在可视点导航图中可视关键点即算法的结点。这样设置结点的好处是结点的设置自由灵活,可以通过权衡减少A*结点的数量,减少计算量,也可以根据设计师的要求快速调整。问题是在大地图中,如果设置的结点比较稀疏,得到的路径会显得死板生硬,造成不自然的视觉体验。在导航网格(Navigation Mesh,又称Navmesh)也就是多边形导航图中可以很大程度上避免以上问题。

        在多边形导航图中,使用凸多边形作为结点,一方面可以大大减少结点的数量,另一方面可以更好的覆盖整个地形。此外,通过计算起点和终点之间直线与多边形导航网格相邻点的位置关系可以得出可否直接无障碍通过,基于此优化后,可避免像可视导航点搜索路径那样出现折返“Z”型路线,使角色产生多余的绕行。

        使用A*算法在NavMesh中搜索的路径是一系列相邻的多边形组成的通路,事实上在很多情况下多个多边形组成的行走区域是可以直接通过的,此时可将这些多边形合并,形成直线路径,只在必须拐弯的拐点处使路径转折,多边形的合并和拐点的寻找方法如下。

        按照多边形导航图的生成规格,相邻的两个多边形之间只有一条共同边,共同边上有两个可能作为拐点的端点,从一个多边形到另一个多边形两个端点可记为左端点、右端点,结点到两个端点的方向向量记为左向量Vleft、右向量Vright。根据多边形结点的代表点与两个端点的坐标可以计算出左右向量,另外根据目的地坐标可以计算一个目的方向向量Vd,因此一个结点数据结构可设计如下:

算法执行过程如下:

(1) 算法维护一个拐点表P,表示优化后路径的关键点,作为算法的运算结果;

(2) 算法初始将起点结点的代表点设置为多边形中心点,并加入拐点表P,然后计算到下一个结点的左右向量与目的方向向量的夹角,夹角较小方向上的端点设置为下一个结点的代表点;

(3) 根据下一个结点的代表点和左右端点计算左右向量,如果向量都不为零,执行和

起点结点相同操作;如果左向量为零,说明代表点和左端点重合,将左端点记为一个拐点加入拐点表P;

(4) 直到到达终点所在的结点时,将当前代表点和终点先后一起加入拐点表P,算法结束。

A*路径经拐点法优化后会出现沿导航图边界行走的情况,只要设置游戏角色的自身半径作为offset校正即可实现与导航图边界保持一定距离行进,避免与边界的碰撞卡顿。

 

3.2 电势矩阵寻路算法

        电势矩阵寻路算法将移动的物体也就是Unity中的NavAgent看做一个负电荷,模拟电势场中负电荷向电势高的地方移动的特点,通过改变电势场来引导负电荷沿着电势场线向目的地寻路移动。基于电势场的设置方法此算法最好应用在栅格化的导航图中,以更精确的描述电势场的细节,并且算法使用一个地图矩阵来存储地形每个点的电势整数值。

        设置目的点的方法即建立一个新的目的矩阵将目的点的电势设置成一个极大值,然后以圆形或者矩形向四周递减散播开来,离目的点越远电势值越小,直到0为止,然后将目的矩阵与原地图矩阵相加,改变电势分布,从而使负电荷沿着电势场分布向目的点移动。

        此算法本质上是一种贪心算法(GreedyAlgorithm),缺点是不保证一定能找到正确路径,可能计算无解。此算法可在一些比较规则的、简单的地形中完成寻路计算任务。

*图中的路径不是很准确,第二次到97后应该走向98;同时在搜索时要通过排除同电势之间节点重复经过的方法,避免在同电势节点之间进入死循环出现徘徊走不出去的情况;

 

3.3群体行为(Flocking Behavior)寻路

        有些游戏中会需要角色群体的共同寻路功能,如果对每一个个体都进行单独寻路计算,会造成计算量膨胀,造成大量不必要的重复。因此角色单位的移动可采用行为控制(SteeringBehavior)来实现,即选择群体中的一个角色单位作为群体的领导者(Leader),对齐使用寻路算法进行寻路计算,然后其他的群体成员按照一定的Flocking规则对Leader进行跟随移动。

Flocking规则的设计主要考虑以下三个方面:

(1)  一致性:

即群体成员的的移动方向要同整体的移动方向(此即Leader的移动方向)保持一致;

(2) 分离性:

即每个群体成员需要与其他成员保持一定距离,避免重合在一起,这个可参照SterringBehavior的碰撞避免(Collision Avoidance)算法来类似实现;

(3) 聚合性:

即群体的成员向群体成员整体的平均位置靠近,使群体的整体寻路前进效果更真实。

 

3.4碰撞避免(Collision Avoidance)

Collision Avoidance可用于简单地形的随机寻路,其性能很差,主要用于障碍物的躲避。实现的逻辑为维护两个向量:一个为代表角色对象当前的移动方向和移动速度的移动方向向量Vd;一个为表示离其最近的障碍物的方向和距离的碰撞检测向量Vc;

        如图中绿色方块为游戏角色,红色方块为目的地,移动方向向量Vd根据角色当前位置和目的地位置不断更新,使其总是趋向于指向目的地,碰撞检测向量为角色位置指向最近的障碍物的向量,向量的模为到障碍物的距离,当距离小于一定值时开始避让障碍物,避让的方法为将移动方向向量与碰撞检测向量的反向量Vc'相加得到校正的移动方向向量Vd':

  Vd' = Vd + Vc'

  Vd = Vd'

        校正的瞬间角色的移动方向向量设置为Vd',使其避开当前最近的障碍物,之后更新调整继续向目的地移动。

 

3.5深度优先搜索算法(DFS)与广度优先搜索算法(BFS)
 

        图论算法将地图结点和结点之间的通路信息用有向或者无向邻接矩阵来进行存储,邻接矩阵中相连的两点对应值为1,不相连的对应值为0,同一个图中可以有多种深度优先序列和广度优先序列。在路径搜寻中可以将相邻两点的对应值设置为两者的距离权重值,在算法搜索结束后选择距离最短的路径分支,从而确定一条算法上最优的路径序列。

        深度优先搜索(DFS, Depth First Search)和广度优先搜索(BFS, Breadth First Search)都是按照一定规则进行的盲目搜索。

 

深度优先:

        深度优先搜索的逻辑规则为从起点开始,寻找访问下一个连通的结点,直到没有未访问的连通结点后,回溯到起点并从其他的分支继续寻找深度连通路径,直到所有的结点都被访问到为止。

假设图3-9中无向图的起点为V1,则有以下几种深度优先序列:

V1, V3, V5, V4, V2;

V1, V4, V5, V3;

V1, V4, V2;

V1, V2, V4, V5, V3;

根据确定的目的结点以及连线的权值和可从序列中截取选择最短路径;

 

广度优先:

        广度优先搜索的搜索逻辑为从起点开始,遍历所有相连的结点并设置为起点的子结点,之后在子节点进行同样的递归操作,直到所有结点都加入以起点为根结点的树中。

假设图3-10中有向图的起点依旧为V1,其中一个广度优先搜索序列为:

V1, V3, V4, V2, V5

如图3-11中所示的两棵广度优先搜索树,从第二层开始,树的一层代表一次广度优先搜索。

 

双向广度优先:

双向广度优先算法是为了加快收敛速度,从起点和终点同时进行广度优先搜索设计的算法。

 

 

3.6 Dijkstra单源最短路径搜索算法

 

        Dijkstra算法是A start算法的无启发函数版,同时是一种典型的贪心算法。算法没有利用结点本身与起点和目的点的距离信息进行引导,在整个地图的所有结点中进行搜索,体现其盲目性,效率自然比A*算法低。算法的本质搜索思想是对于A和B两个结点,如果从整个地图中添加某些中间结点可以使A和B之间的加权路径长度更短,则加入中间结点构成A和B之间更短的加权路径,直到没有中间结点可以使A、B两点之间路径更短为止。

        算法初始化时计算各结点到其他结点的直接距离表,结点之间相连的距离为结点连线的权重值,不相连的距离设置为无穷大。构建一个S表,表示计算完成的结点的集合,算法开始时将起点加入S表,然后搜索与起点距离最近的点加入S表,并以新加入的结点为中间结点,计算起点到其他结点的相对更近距离,更新起点的距离表,直到所有的结点都加入S表。起点最终的距离表中的距离值即起点到其他各结点之间的最短路径距离。当终点确定时,记录在算法运行过程中起始点之间加入了那些中间结点,即可找出相应的最短路线。

假设图3-10有向图中的起点为V1,则Dijkstra算法初始化的距离表如表3-1所示:

 

        算法的执行过程可用表3-2表示如下,共六个结点执行五次循环将所有结点加入S表,w为新加入结点,D[Vi]表示起点到结点Vi的最短距离。

 

 

3.7随机寻路算法

 

        游戏中的怪物在玩家还未靠近时要有自己自然的随机动作,以一个随机的方向和随机的速率进行移动,使其看上去是活跃的。当玩家靠近进入怪物的“境界区域”时,怪物会主动寻路靠近玩家,当玩家与怪物足够近进入怪物的“攻击区域”时,怪物开始攻击玩家。

随机寻路算法的实现是设计一种随机移动规则,使游戏角色不断产生不规则、不可预见的行动,从而使角色在游戏中自行保持活跃状态,提高游戏真实感。寻路的随机主要是角色行进的方向和行进速度的随机。方向的表示可用一个随机目的地位置表示,或用一个单位方向向量表示。速度的改变可以通过控制更新的频率或者每次移动的距离实现。

        比如可以用一个向量的方向表示当前行进的方向,的模的大小来表示行进的速度,按照一定周期随机更新的方向和模的大小实现随机移动,同时使用碰撞避免算法来校正寻路,防止游戏角色出现在障碍物处长时间卡顿徘徊的现象。

算法一:A*寻路初探 From GameDev.net 译者序:很久以前就知道了A*算法,但是从未认真读过相关的文章,也没有看过代码,只是脑子里有个模糊的概念。这次决定从头开始,研究一下这个被人推崇备至的简单方法,作为学习人工智能的开始。 这 篇文章非常知名,国内应该有不少人翻译过它,我没有查找,觉得翻译本身也是对自身英文水平的锻炼。经过努力,终于完成了文档,也明白的A*算法的原理。毫 无疑问,作者用形象的描述,简洁诙谐的语言由浅入深的讲述了这一神奇的算法,相信每个读过的人都会对此有所认识(如果没有,那就是偶的翻译太差了-- b)。 原文链接:http://www.gamedev.net/reference/articles/article2003.asp 以下是翻译的正文。(由于本人使用ultraedit编辑,所以没有对原文中的各种链接加以处理(除了图表),也是为了避免未经许可链接的嫌疑,有兴趣的读者可以参考原文。 会者不难,A*(念作A星)算法对初学者来说的确有些难度。 这篇文章并不试图对这个话题作权威的陈述。取而代之的是,它只是描述算法的原理,使你可以在进一步的阅读中理解其他相关的资料。 最后,这篇文章没有程序细节。你尽可以用任意的计算机程序语言实现它。如你所愿,我在文章的末尾包含了一个指向例子程序的链接。 压缩包包括C++和Blitz Basic两个语言的版本,如果你只是想看看它的运行效果,里面还包含了可执行文件。 我们正在提高自己。让我们从头开始。。。 序:搜索区域 假设有人想从A点移动到一墙之隔的B点,如下图,绿色的是起点A,红色是终点B,蓝色方块是中间的墙。 [图1] 你 首先注意到,搜索区域被我们划分成了方形网格。像这样,简化搜索区域,是寻路的第一步。这一方法把搜索区域简化成了一个二维数组。数组的每一个元素是网格 的一个方块,方块被标记为可通过的和不可通过的。路径被描述为从A到B我们经过的方块的集合。一旦路径被找到,我们的人就从一个方格的中心走向另一个,直 到到达目的地。 这些中点被称为“节点”。当你阅读其他的寻路资料时,你将经常会看到人们讨论节点。为什么不把他们描述为方格呢?因为有可 能你的路径被分割成其他不是方格的结构。他们完全可以是矩形,六角形,或者其他任意形状。节点能够被放置在形状的任意位置-可以在中心,或者沿着边界,或 其他什么地方。我们使用这种系统,无论如何,因为它是最简单的。 开始搜索 正如我们处理上图网格的方法,一旦搜索区域被转化为容易处理的节点,下一步就是去引导一次找到最短路径的搜索。在A*寻路算法中,我们通过从点A开始,检查相邻方格的方式,向外扩展直到找到目标。 我们做如下操作开始搜索: 1,从点A开始,并且把它作为待处理点存入一个“开启列表”。开启列表就像一张购物清单。尽管现在列表里只有一个元素,但以后就会多起来。你的路径可能会通过它包含的方格,也可能不会。基本上,这是一个待检查方格的列表。 2,寻找起点周围所有可到达或者可通过的方格,跳过有墙,水,或其他无法通过地形的方格。也把他们加入开启列表。为所有这些方格保存点A作为“父方格”。当我们想描述路径的时候,父方格的资料是十分重要的。后面会解释它的具体用途。 3,从开启列表中删除点A,把它加入到一个“关闭列表”,列表中保存所有不需要再次检查的方格。 在这一点,你应该形成如图的结构。在图中,暗绿色方格是你起始方格的中心。它被用浅蓝色描边,以表示它被加入到关闭列表中了。所有的相邻格现在都在开启列表中,它们被用浅绿色描边。每个方格都有一个灰色指针反指他们的父方格,也就是开始的方格。 [图2] 接着,我们选择开启列表中的临近方格,大致重复前面的过程,如下。但是,哪个方格是我们要选择的呢?是那个F值最低的。 路径评分 选择路径中经过哪个方格的关键是下面这个等式: F = G + H 这里: * G = 从起点A,沿着产生的路径,移动到网格上指定方格的移动耗费。 * H = 从网格上那个方格移动到终点B的预估移动耗费。这经常被称为启发式的,可能会让你有点迷惑。这样叫的原因是因为它只是个猜测。我们没办法事先知道路径的长 度,因为路上可能存在各种障碍(墙,水,等等)。虽然本文只提供了一种计算H的方法,但是你可以在网上找到很多其他的方法。 我们的路径是通过反复遍历开启列表并且选择具有最低F值的方格来生成的。文章将对这个过程做更详细的描述。首先,我们更深入的看看如何计算这个方程。 正 如上面所说,G表示沿路径从起点到当前点的移动耗费。在这个例子里,我们令水平或者垂直移动的耗费为10,对角线方向耗费为14。我们取这些值是因为沿对 角线的距离是沿水平或垂直移动耗费的的根号2(别怕),或者约1.414倍。为了简化,我们用10和14近似。比例基本正确,同时我们避免了求根运算和小 数。这不是只因为我们怕麻烦或者不喜欢数学。使用这样的整数对计算机来说也更快捷。你不就就会发现,如果你不使用这些简化方法,寻路会变得很慢。 既然我们在计算沿特定路径通往某个方格的G值,求值的方法就是取它父节点的G值,然后依照它相对父节点是对角线方向或者直角方向(非对角线),分别增加14和10。例子中这个方法的需求会变得更多,因为我们从起点方格以外获取了不止一个方格。 H 值可以用不同的方法估算。我们这里使用的方法被称为曼哈顿方法,它计算从当前格到目的格之间水平和垂直的方格的数量总和,忽略对角线方向。然后把结果乘以 10。这被成为曼哈顿方法是因为它看起来像计算城市中从一个地方到另外一个地方的街区数,在那里你不能沿对角线方向穿过街区。很重要的一点,我们忽略了一 切障碍物。这是对剩余距离的一个估算,而非实际值,这也是这一方法被称为启发式的原因。想知道更多?你可以在这里找到方程和额外的注解。 F的值是G和H的和。第一步搜索的结果可以在下面的图表中看到。F,G和H的评分被写在每个方格里。正如在紧挨起始格右侧的方格所表示的,F被打印在左上角,G在左下角,H则在右下角。 [图3] 现在我们来看看这些方格。写字母的方格里,G = 10。这是因为它只在水平方向偏离起始格一个格距。紧邻起始格的上方,下方和左边的方格的G值都等于10。对角线方向的G值是14。 H 值通过求解到红色目标格的曼哈顿距离得到,其中只在水平和垂直方向移动,并且忽略中间的墙。用这种方法,起点右侧紧邻的方格离红色方格有3格距离,H值就 是30。这块方格上方的方格有4格距离(记住,只能在水平和垂直方向移动),H值是40。你大致应该知道如何计算其他方格的H值了~。 每个格子的F值,还是简单的由G和H相加得到 继续搜索 为了继续搜索,我们简单的从开启列表中选择F值最低的方格。然后,对选中的方格做如下处理: 4,把它从开启列表中删除,然后添加到关闭列表中。 5,检查所有相邻格子。跳过那些已经在关闭列表中的或者不可通过的(有墙,水的地形,或者其他无法通过的地形),把他们添加进开启列表,如果他们还不在里面的话。把选中的方格作为新的方格的父节点。 6,如果某个相邻格已经在开启列表里了,检查现在的这条路径是否更好。换句话说,检查如果我们用新的路径到达它的话,G值是否会更低一些。如果不是,那就什么都不做。 另一方面,如果新的G值更低,那就把相邻方格的父节点改为目前选中的方格(在上面的图表中,把箭头的方向改为指向这个方格)。最后,重新计算F和G的值。如果这看起来不够清晰,你可以看下面的图示。 好了,让我们看看它是怎么运作的。我们最初的9格方格中,在起点被切换到关闭列表中后,还剩8格留在开启列表中。这里面,F值最低的那个是起始格右侧紧邻的格子,它的F值是40。因此我们选择这一格作为下一个要处理的方格。在紧随的图中,它被用蓝色突出显示。 [图4] 首先,我们把它从开启列表中取出,放入关闭列表(这就是他被蓝色突出显示的原因)。然后我们检查相邻的格子。哦,右侧的格子是墙,所以我们略过。左侧的格子是起始格。它在关闭列表里,所以我们也跳过它。 其 他4格已经在开启列表里了,于是我们检查G值来判定,如果通过这一格到达那里,路径是否更好。我们来看选中格子下面的方格。它的G值是14。如果我们从当 前格移动到那里,G值就会等于20(到达当前格的G值是10,移动到上面的格子将使得G值增加10)。因为G值20大于14,所以这不是更好的路径。如果 你看图,就能理解。其通过先水平移动一格,再垂直移动一格,还不如直接沿对角线方向移动一格来得简单。 当我们对已经存在于开启列表中的4个临近格重复这一过程的时候,我们发现没有一条路径可以通过使用当前格子得到改善,所以我们不做任何改变。既然我们已经检查过了所有邻近格,那么就可以移动到下一格了。 于 是我们检索开启列表,现在里面只有7格了,我们仍然选择其中F值最低的。有趣的是,这次,有两个格子的数值都是54。我们如何选择?这并不麻烦。从速度上 考虑,选择最后添加进列表的格子会更快捷。这种导致了寻路过程中,在靠近目标的时候,优先使用新找到的格子的偏好。但这无关紧要。(对相同数值的不同对 待,导致不同版本的A*算法找到等长的不同路径。) 那我们就选择起始格右下方的格子,如图。 [图5]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Mr_厚厚

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值