Unity中目前提供的基于Navmesh的网格寻路,如果仅仅是单机游戏,其实功能还是能满足的,当然,如果你做的是大规模兵海流的 rts游戏,Unity的网格寻路还是会碰到多人寻路相互挤压的问题。
由于我们目前的工作主要集中在手游,而又以联网RPG游戏为主。由于Unity并未开源Navmesh寻路组件,而Navmesh其实上是开源寻路项目RecastNavigation的作者做的升级版本,自然而然,我们会尝试在服务器端集成RecastNavigation。进行此类工作的团队很多,大概思路都是根据RecastNavigation要求,定制客户端插件,导出客户端网格数据。
不过很可惜的是,虽然大部分情况,客户端和服务器能做到寻路路径统一,但是在一些特殊情况下,比如网格是一些特别细长的三角形,寻路路径却存在偏差,这几乎是不能接受的。但是如果抛弃客户端的寻路,把RecastNavigation导出到客户端,虽然能保障路径统一,但是实际中行路及碰撞等图形表现不是很好,毕竟Unity为寻路做了大量的工作。
之前的项目为了上线,大多采用了折中的方案:
方案1:在客户端寻路并发送到服务器,执行广播。服务器仅仅是验证路径是否合理。
方案2:客户端自己根据Navmesh生成标准寻路格子,将客户端寻路替换成基于格子的A*寻路, 去除单位碰撞。自己单独处理跳跃点等情况, 我曾经为此写过一个Unity寻路插件Navgrid。
上述2个方案其实上都不算完美,仅仅是可用而已。对大多数研发团队来说就一劳永逸的方案, 其实还是等待Unity能开放寻路算法源码,毕竟Unity已经慢慢开放了不少底层组件的源码 。不过由于项目需要(需要客户端服务器完全同步且要求碰撞处理),我一直在思考一种相对完善的方案,把格子寻路和网格寻路结合起来:
首先,基于Tile我们生成一份带行走权重的二维导航数据。把起始点和终点转换成Tile序号,我们让寻路单元在 Tile 之间寻路。由于Tile足够大,我们甚至不用做查询后路径的二次优化,而且这步寻路会足够快。
其次,在到达终点所在Tile后,寻路转换为精细寻路,服务器切换为RecastNavigation,客户端切换为Unity自带寻路。由于在Tile内寻路,网格寻路路径将极大简化,基本上能保障路径的一致性,就算是真的有偏差,由于整个寻路是在Tile内进行的,也不会偏差太多。下图为大概的寻路路径: