在寻路专题中我们讲到了A
     
     *
     
     算法,这一节是对A
     
     *
     
     的优化,适合对A
     
     *
     
     已经了解的读者,如果还不了解就建议去学习A
     
     *
     
     再来进行优化的学习。优化前我们先来大概回顾一下A
     
     *
     
     算法,A
     
     *
     
     算法使用了启发函数来对迪杰斯特拉算法进行一些剪枝优化,去除那些在寻路过程中不可能经过的点。★启发函数
     
     F
     
     (
     
     n
     
     )
     
     =
     
     G
     
     (
     
     n
     
     )
     
     +
     
     H
     
     (
     
     n
     
     )
     
     就相当于A
     
     *
     
     的大脑☆,直接影响了A
     
     *
     
     的寻路决策。我们从开始节点开始,维护一个openList和closeList来分别存放 待搜索和 已经搜索过 的点,每次循环★从openList找出一个F值最小的点☆,然后★找出其后继节点☆,★判断是否在closeList中☆,在就跳过,不在就加入openList中,直到目标点在openList中。



相信大家都注意到了上面“★.........☆”语句,对了,那些带星的语句就是可优化的地方。我们一个一个来看。



①从启发函数来优化A ,相信大家都玩过一些大型游戏,游戏里面的地图不会是单一的地形,而是山川,河流,平底等地形夹杂在一起。假设你的游戏有两种地形,平原和山地,在平原中的移动代价是1而在山地则是3。这时如果使用普通的启发函数就效果不好,这时就需要动态衡量启发函数:F(n)=G(n)+W(n) H(n),这里的W(n)代表权值可以影响评估值。 [W(n)越小,G(n)发挥作用越大,趋近于Dijkstra算法,能搜索到最短路径,但搜索的节点会越多,时间越长,W(n)越大,H(n)发挥作用越大,趋近于GBFS(贪婪最优搜索),搜索的节点越少,效率越高但不保证找到的路径最优。]这使得我们可以在游戏里根据情况改变寻路策略,这十分有用。例如:在NPC安全时,可以采用效率优先,而在NPC遇到危险时,就得寻找一条最短路径来逃跑,这时就强调最短路径。



②从openList来优化A*,我们需要从openList寻找F值最小的点,在最开始我们是使用遍历openList来寻找




unity3d 方框内寻路是怎样编程的_搜索

时间复杂度为O(n),我们只需要找出最小F的点,正好使用优先队列(小根堆)来实现,但由于C#没有自带的模板(注意C++和Java虽然自带了优先队列,但自带的那个没有自调整功能不能用),我们就自己来实现一个。优先队列主要操作就两种heapInsert和heapify,对应节点向上冒和向下冒。然后最主要的就是要能在更新F值后仍然维持小根堆(见下图UpdateHeap方法),然后在添加和删除(Push和Pop)。


unity3d 方框内寻路是怎样编程的_搜索_02


unity3d 方框内寻路是怎样编程的_优先队列_03


unity3d 方框内寻路是怎样编程的_寻路_04


unity3d 方框内寻路是怎样编程的_优先队列_05


unity3d 方框内寻路是怎样编程的_优先队列_06

现在我们要得到F值最小的点就很简单了。只需要O(1)的复杂度,每次取完调整也只需要O(logn)。比优化前快很多


unity3d 方框内寻路是怎样编程的_搜索_07

③从找后继节点来优化A ,在原项目中获取周围点时,会把获取邻居的顺序写死,比如我们获取周围四个邻居(上下左右),那么A 就会优先向上试探,这样就导致无意中把向上走这个策略定为优先级最高的策略。现在可以让其每次获取周围点都变为随机事件。


④从closeList来优化A*,我们在找后继节点时需要判断其是否已经在closeList中,最开始我们仍然通过遍历来判断,时间复杂度为O(n)。我们只需要判断一个点是否在closeList中,不难想到HashSet,这种集合可以快速判断是否包含某个值。这里我们要判断某个点是否在里面,所以使用HashSeT.Contains(Point Temp)即可判断Temp是否在里面。时间复杂度为O(1)。


感谢大家有耐心读到这,希望大家一起进步,实现自己的理想。有什么不懂的可以下载源码学习或者评论提出问题,发现错误也可以留言。https://github.com/highplayer3/NavgationForUnity(项目默认为A 寻路,可按键更换寻路方式,A——A ,D——DFS,B——BFS,F——DBFS,I——Dijkstra)