让你的actor戒掉摇头丸
表误会,说的不是毒品。我说的是一种现象,这种现象在grid-based的pathfinder中相当常见。
是怎样的情况,且由我慢慢说来:pathfinder通常找到的是一条最优路径(如果你的实现是A*的话)。但是最优路径的“最优”二字定义是指两点间“代价”的最小化。这给我们想要的现实表现带来了困扰:最优路径不一定是我们想要的!举最明显的例子,grid-based pathfinder在绕开障碍物时,通常会生成一条曲折的(zigzag)路径。从而你的人物沿着这条路径走,就会不停的改换朝向以适应路径。即使你使用了平滑插值,你还是会看到你的人物不停的摇头,“挤”向该走的方向。
以上的解决方法可以通过一种小技巧来避免。A*算法中,next node和current node之间有一个代价值。这个值可由一个估值函数提供。如果我们在估值函数中加上了对“曲折蛇行”路径的一点小惩罚,也就是说,对每一次A*迭代比较上一次为止产生的路径,如果这个节点所产生的新路径和上一次为止产生的路径方向一致(或小于一个threshold),那么什么事都没有发生;如果这个方向和上一此为止产生的路径方向不一致(或大于一个threshold),那么我们对这个估值函数的返回值上加上一个很小的惩罚值,比如说0.0001f,这个“很小的值”取值应该小于两个节点间的最小距离。这样的话,虽然说这点惩罚值对最终形成“最优路径”的结果没有影响,但是会使A*避免去选择方向改变较多的路径,而选择方向较为稳定的路径。这也正是我们这样做的目的——消灭zigzag。
同样的效果可以通过对生成的路径做post processing达到。处理的基本思想跟上面一致。而我个人比较倾向于上面这种做法,简单易行。
现代3D游戏中真正在runtime时使用A*的似乎越来越少了,因为可以通过节点数据结构的优化进行预处理,直接存储所有的路径信息。比grid-based时代的东西要精致优雅得多。这个以后再讲。
Reference:
1. Game Programming Gems. The Basics of A* for Path Planning, by Bryan Stout
2. Game Programming Gems. A* Aesthetic Optimizations, by Steve Rabin