A star算法优化二

       本文目的是对A*寻路算法所生成的路径进行一些人性化的调整,使其看起来不至于太机械化。关于A*算法的原理与实现,读者可以阅读其他资料,这里不再详细阐述。

如何写估价函数

        A*寻路算法本质上是一个有方向性的广度优先搜索算法,它使用一个估价函数,来估测可能的最短路径,在每一次搜索迭代完成后,选取其邻接点中最优的一个(即,距离终点最近的一个点),作为下一次迭代的起点。如此反复,直到找到终点。下面先列出估价函数的常规写法:

        设i点到起点的价值为S,到终点的估价为E,i点的总估价G等于S+E。S的值是确定的:

[cpp]  view plain  copy
  1. S = parent.S + 1(i点是其父节点的水平或垂直方向上的邻接点)  
  2. 或  
  3. S = parent.S + sqrt(2))(i点是其父节点斜方向上的邻接点)  

E点的值需要估算。精确一点的写法:

[cpp]  view plain  copy
  1. 水平距离:dx = abs(ix - ex)  
  2. 垂直距离:dy = abs(iy - ey)  
  3. 需要斜着走过的距离:v1 = min(dx, dy) * sqrt(2)  
  4. 需要直线走过的距离:v2 = max(dx, dy) - min(dx, dy)  
  5. E =  v1 + v2  

粗略的写法:

[cpp]  view plain  copy
  1. E = abs(ix - ex) + abs(iy - ey)  

如何避免转向抖动

        A*寻路得到的结果是最优的,但不是唯一的,这源于两点之间最近的路线可能不只一条。那么问题就产生了,两条最佳路线距离都相等的情况下,哪一条会更好?

    

(红色是障碍,白色可通行,黑色是搜索路径)

        如上图所示,是A* 8方向搜索得到的两条距离相等的路线,但是左图的路线在中间位置发生了“拐弯”,要比右图的路线多一个“拐弯”。如果路线上拐弯太多,人物行走的过程中,会出现频繁转向,从而出现“抖动”现象。所以,我们判定右图路线优于左图路线。针对这一问题,我们可以通过修改估价函数,来选择“拐弯”更少的路线。

        拐弯的问题,可以简化成先尽可能的向一个方向走,然后再考虑转向。进一步简化成,点越接近起点或是终点,越优先考虑。我们给E加上一个干扰值factor,

[cpp]  view plain  copy
  1. factor = min(abs(ix - sx), abs(ix - ex)) + min(abs(iy - sy), abs(iy - ey))  
  2. factor *= 0.01  

factor的值不能过大,否则会造成搜索结果不是最短距离,因此适当的给factor乘上一个缩放系数。

如何远离障碍物

        A*寻路的效果是抄近道,走捷径。但对于游戏体验来说,这并不完全是件好事,放着宽阔的马路不走,非得走悬崖峭壁,一不小心就跌落万丈深渊,或者卡在岩石边上。那么,我们该如何避免这些现象呢?同样,我们可以通过修改估计函数做到。

        我们给每一块可走区域都加上一个干扰值,越靠近障碍的可走区域,其干扰值越大。干扰值计算方法:

[cpp]  view plain  copy
  1. factor = 0  
  2. for(x = -n; x <= n; ++x)  
  3. {  
  4.       for(y = -n; y <= n; ++y)  
  5.      {  
  6.         if(isObstacle(ix + x, iy + y))  
  7.         {  
  8.             factor += n - min(abs(x), abs(y))  
  9.         }  
  10.      }  
  11. }  

        我们甚至可以根据地表的材质来增加干扰值,比如山路和沼泽地带明显比马路的干扰值大。

后记

        总之,我们可以调节估价函数来达到不同的效果。但是,也不能随意修改,不良的估价函数,会增加搜索成本。

猜你喜欢

转载自blog.csdn.net/zgaoq/article/details/79605662