引言
寻路系统是当今众多游戏中不可或缺的功能模块。比如格子游戏中的格子寻路,塔防怪物的行进路径,捕鱼游戏中的鱼群路径,RPG游戏中的怪物AI等,不同的需求对应的寻路策略的选择也不尽相同。
正文
在Unity3D中我们一般常用的寻路策略有:
1. 路点寻路(WayPoint)
路点寻路是最简单,易理解,易操作的(如下图):需要预先设置好路径点坐标集合。然后对象按照规定的坐标集合运动。这种策略成熟的插件为Simple Waypoint System, 可在Asset Store获得。 使用较好的地方:塔防怪物行进路线,鱼群游动路径,AI的巡逻路径。
劣势:(1):如大量怪物在某区域漫游,为了使怪物的漫游看起来更逼真则需要放置更多的路径点。即便如此怪物仍会选择到一些曲曲折折的路径,除非添加更大量的点。这样则造成了更多的工作内容,且效率低下。(2):只能按照规定好的路线行进,如果突然出现一个障碍物,则无法躲避,因为它对路径点以外的东西一无所知(3):路径点不支持参数不同的单位。比如下图一个玩家和一个坦克,玩家完全可以按照红色箭头路线行进。但坦克却不得不与障碍物保持一定距离以避免碰撞如蓝色箭头。
2. U3D自带的导航网格寻路(NavMesh)
这种方法使用一系列算法(拐角点算法)将原始地图转换成三角形网格的集合,网格和网格之间构成连通关系用于寻路。
优点:能精确地表征世界。虽然也做不到百分百还原真实地图,但是它无疑比路点都更精确。
缺点:1:必须是在静态生成的,无法做到动态生成。 2:静态生成后的navmesh文件位置已固定,不会随着物体移动。3:由于工具集NavMesh算法,数据格式不开源,导致了游戏服务端无法使用,无法和客户端保持一致的导航寻路逻辑。4:不能随意的编辑
在Unity5.6以后版本有了新版NavMesh实现了动态烘焙,动态清除navmesh.asset文件,而且对效率做了极大的改善(可以选择只烘焙角色附近一定范围)。但仍然无法做到在服务器端使用。
3. 插件A* Pathfinding project
A* Pathfinding project 是一款在A*算法的基础上进行改进完善的寻路插件,因功能强大但容易使用被大多数对寻路需求较为复杂的游戏所采用。可在Asset Store中获得。
A星寻路算法基本思路:要实现A星算法,首先将地图抽象成寻路网格,最简单的方式是将游戏地图划分为多个正方形单元,网格越精细,寻路的效果越好,但计算量也越大。A星算法的基本思想就是借助这些网格实现寻路,从起点开始遍历四周的点,寻找最有可能在最短路径上的点,并以这个点为基准继续向四周遍历,直至遍历到终点,路径也就找到了。
A星寻路算法核心F=G+H:F可以理解为通过这个点的总代价,代价越低,这个点当然就更有可能在最短路径上。G是从起点到这个点的代价,H是从这个点到终点的代价,这两个代价加起来就是这个点的总代价。
我们还需要两个集合,一个是open集合,一个是close集合,open集合里存放的是还未计算代价的点,close集合里是已经计算过的点。开始时open集合里只有起点,close集合没有元素,每次迭代将open集合里F最小的点作为基点,对于基点周围的相邻点做如下处理:
(1)如果这个点是障碍,直接无视。
(2)如果这个点不在open表和close表中,则加入open表
(3)如果这个点已经在open表中,并且当前基点所在路径代价更低,则更新它的G值和父亲
(4)如果这个点在close表中,忽略。
处理完之后将基点加入close集合。
当终点出现在open表中的时候,迭代结束。
如果到达终点前open表空了,说明没有路径可以到达终点。
Grid Graph
这是最直接的一种Graph,和名字一样,他生成的是栅格类型的Graph。它在大多数的场景下表现都是良好的,并且如果你需要在运行时动态更新graph数据也十分的容易和方便。(比如RTS或者塔防游戏)
但它对于拥有巨量空间的大型世界表现乏力,因为栅格的特性,它会在所有的地方生成相同格式的数据,即使那些地方是大片的空白地区,因此它会消耗过多的内存和使用更长的寻路时间。
Navmesh Graph
这个寻路方式在大多数静态场景下(即不会在运行时动态调整障碍和阻挡点)是完美的。他通常来说性能要优于 grid graph,因为他搜索的节点少.(我们游戏中使用的就是这个)
Recast Graph
recast graph 的原理很简单,先收集你场景里所有的Mesh网格,然后进行体素化。(译注:体素可以理解为3D空间的基本单位,比如一个2D平面的绘制基本单位是像素,3D空间的基本单位叫体素)一个2D的模拟的体素化过程大概就是把一堆的三角形绘制到一张纹理里。然后再进行一些列的模拟设定,诸如角色的高,半径等得到一个可行走的导航网格。
这是目前为止最先进的graph生成器。他可以用几秒钟就自动生成一个,正常情况下可能几个小时才能手动生成的网格。
Layered Grid Graph
GridGraph的表现一般来说已经比较完美了。但是如果有一些场景有一些重叠的区域,比如移动建筑有很多层,他就不能很完美的处理这些情况了。所以这个graph就用来处理这种情况了。这里有点局限的地方就是目前只支持4方向的寻路,8方向的暂时不能支持。另外还有一些额外的内存开销,但是当你需要进行分层寻路的时候,你可能不得不去使用它。
A* Pathfinding project插件的功能十分强大复杂。具体功能学习可参考
总结
每种策略都有自己的优点和缺点,应该根据应用场景选择合适的方式。
如果开发时间有限,寻路线路相对固定(典型的如塔防游戏),不用考虑真实地形的影响,优先考虑路点寻路。
如果开发时间有限,寻路需求较为复杂但为单机游戏优先考虑新版NavMesh。
如果开发时间充裕,寻路需求较为复杂且为网络游戏优先考虑A* Pathfinding project。