《寻路算法第二篇》A*寻路的路径平滑、静态合并、生成格子工具自动化、
这些都是我之前写在蛮牛上的帖子,现在放到博客里来
之前写了一个A*算法和navmesh算法的混合使用,以及前端使用navmesh,后端使用A*验证的思路。
http://www.manew.com/thread-42766-1-1.html
这几种扩展其实是依赖关系。以下内容皆是原创,没有在网络上见过类似的思路,所以献丑一次,欢迎交流。
提纲: 1.平滑A型算法的路径 2.A*算法的格子静态合并、优化A*算法的寻路性能 3. A*寻路向navmesh寻路的演进(navmes设计思路) 4.A*工具化
平滑A型算法的路径
如图1
我使用一种简单的情况来说明,假设在地图上寻路,如果从A点(灰色格子)寻到X点,那么使用普通A*算法寻路出来可能是这样的
现在格子很不规则,我们想使路径平滑,一般采用的策略是数个角度差异较大的路径点之间,通过插点,替换路径点,来实现。
我们现在采用另一种方式,
步骤1:
先对所有路径点循环,如果两个顶点,比如B-C矢量为垂直/平行 于地图起始的 1-2顶点矢量,则 B-C顶点合并。
通过图片2
我们可以看到,B-C-D-E与1-2顶点矢量平行,所以可以合并为BCDE点,F-G点与1-2顶点矢量垂直,所以F-G合并为FG点。(这里要注意, ABCDE---F矢量 与ABCDE本身矢量不同,不能再合并。所以中断合并,从F点重新判断,F和G点合并了)
步骤2:
最后我们原本的路径点为: A-B-C-D.....-Y-X 一共10多个路径点, 合并后,为 ABCDE--FG---HOI---JKM---NOX 一共五个点,路径点大大减少
虽说对行走效率有一定优化,但人物按这个路径点来行走,路线并没有平滑。
步骤3:
其实我们可以将ABCDE当做一个大方块,同样的道理,所以这个寻路路径变成了5个大方块的寻路。
我们先将我们理想中的平滑路径画出来,现在看图3
其实我们可以看到黄色路径比较接近我们的想法。
但是黄色点,并不在我们的寻路结果内,所以我们要将黄色点纳入我们的五个大方块里去,
于是成了图3的样子,我们用绿色格子将黄色部分纳入。
我们可以发现,其实现在变成了3个更大的方块(红色圈内)的寻路。我们把三个圈命名为 a b c.
5个大方块朝3个更大方块的演进,实际上是将拐角磨平(比如FGH的拐角被纳入第二个红圈内了)
实际上,就是判断,当矢量FG与下一个点H有拐角时,判断FG与H点的斜上方所有点是否可走,如果可走,则FG与H点可以合并成一个大方块。
则 我们计算把 a- b - c 三个长方形的公共点(如果有公共边,则公共边的中点为公共点,如果只有相邻角,则角作为这个圈到下一个圈的路径点)作为必经点
则新的路径形成, a长方形终点 - b长方形起 ---- c起点---x(x属于C内部)
其实,到这里为止,这已经是一个简化版的动态navmesh寻路算法。
A*寻路向U3D自带navmesh寻路的演进
navmesh也是多个区域块行走。但不是使用矩形,而是使用三角形。
navmesh的三角形有一个严格规定,每个三角形的三个顶点所形成的圆形内不能包含其他三角形的顶点(delaunay算法 http://baike.baidu.com/link?url=m1uEA28GLx-NjrhXlozvcJ03-hmXTIUMo03D99bf-4_nEF7Rsrd2h6F-Pq9HpVatIWlQNSOWfMmZs6jlLP5KkK)
这样做有个好处,其实navmesh的实际路径不是从一个三角型寻路到另一个三角型,本质上是从一个圆到另一个圆,圆与圆之间有且只有一个交点,这样保证了在很多情况下路径比矩形寻路更短更平滑(长方形无法形成一个不包含其他长方形顶点的圆,所以相邻矩形的内部路径之间的夹角更大)
所以我们现在这个简化版的navmesh算法,比U3D自带的navmesh算法,少了一个三角型的生成算法。如果我们把矩形拆分成三角型,更接近。
U3D的navmesh烘焙,是读取网格数据后,使用该delaunay算法直接生成三角型,剩余步骤相同。
A*算法的格子静态合并
刚才是先进行寻路,再进行格子的动态合并,对效率影响很大,其实将上面的合并步骤拿出来,使用地图格子之前,先对所有地图格子进行合并,然后生成一个很多矩形的新地图格子。
即可达成格子的静态合并。 然后使用中,直接使用这些格子进行A*寻路,能大大提高效率。但是,静态合并后,如果不单独处理动态障碍,无法识别动态障碍,这也是NAVmesh的通病。
A*地图格子生成工具化
简单说,
1.将所有地图上可行走区域设置为(walk层级),障碍的层级设置为nowalk
2.用摄像机对地图循环扫描(每次扫描x坐标+1,下一次y+1,轮流加坐标),扫描到walk,xml上写0,扫描到nowalk,xml上写1.
(当然,还可以有减速行走的沼泽,则xml可以写2,以此类推,可以无限多地形。顺便提一句,草丛视野的实现,比如可以将草丛部分设置为3,人物中心点处于草丛格子,则判断人物进入草丛。)
最后说一下navmesh的A*的策略稍微有点不一样,一般不再是F=G+H, 有些版本navmesh的A*直接使用F=H,具体可以调整这个判断。