开放大世界的全局寻路

        开放大世界的寻路一直是很困扰我的一个点,地图大、还是动态可变的,所以寻路会有很多要求。就我们项目来讲,有这几个要求:

  •  能满足极大范围的地图;
  •  地图寻路数据能实时构建,且重建代价很小;
  •  寻路的效率要极高,客户端服务器都要大量计算;
  •  寻路的路径客户端可预测;

        根据上面的需求,像 NavMesh、JPS+ 虽然效率高,但是重建代价大;用 A* 重建代价小但是效率也太差了;而 FlowField 又不支持多目标寻路。最后,我根据项目本身的需求,设计了一套适用于航海主题的海洋+岛屿的寻路解决方案。

        这个方案能够满足项目要求,且只有一个 O(1) 的复杂度,还可以分布寻路,地图的重建开销也很低。当然,这里对岛屿、地图设计做了一些限制,同时是针对航海特化的方案。

1、名词说明

        地图数据上,采用格子来构建地图数据,可以参考 开放大世界的数据管理-CSDN博客 ,对寻路来讲,较为核心的有以下几个:

  •  Cell : 寻路的最小单位(也就是一艘船的占地)。
  •  Chunk:最小的岛屿,也是一个Block的最小单位。
  •  Block :寻路块,等价于一个岛屿,会包含岛上的阻挡、寻路等信息。
  •  AOI Block : AOI 块,用于服务器、客户端的数据同步(对寻路本身作用不大,但是会影响地图设计)。

        在岛屿设计时,不允许任何一个岛屿跨越两个AOI Block,这样能客户端只需要加载有限的几个AOI块就能保证寻路正确。

2、寻路步骤

        以下面的地图举例:

        上图中最小的格子是一个Chunk (最小岛屿),其中橙黄色的部分是岛屿(一个寻路的Block),有大有小。玩家需要从A点(红色块)移动到B点(绿色块),其寻路部分如下:

2.1、两点直线并栅格化

        起点和终点直接做直线,作为初始的两个点。
        之后将直线进行栅格化,找出途经的所有Chunk点,然后将这些Chunk点所在的岛屿进行查询,看是否属于某个岛屿。

        如上图灰色块即为栅格化的Chunk路径,黄色块即为各个岛屿的入口、出口。
        之后计算直线与岛屿的交点,计算入口和出口。判断如果存在出口,即离开了这个岛屿,就可以采用流场寻路。

2.2、穿岛/出岛,流场寻路

        航海大世界的岛屿有一个强制规则:

        所有的岛屿最外面的一圈Cell都是可行走区域(海面)。

        这种设计,保证不会出现绕过岛屿的情况,且所有岛屿都可以穿越。在穿越岛屿时,采用流场(FlowField)进行处理,如下图所示:

        上图是从下方往上走时的流场 G 值表,表示到达目标点的代价。在寻路时,先往 G 值小的地方走,当走到 G 值为0的地方则表示已经到达边缘,然后将边缘出口点作为起点,继续向终点拉直线,寻找下一个穿过的岛屿。

        在实际的数据处理中,不会保存G值,而是会预处理出每个Cell附近G值最小的格子。因此在 rumtime 寻路的时候直接根据预生成的数据,依次行走即可(不需要再进行计算)。

        流场寻路输入出口方向以及当前起点,然后根据当前起点的父节点不断遍历,直到走到无父节点的边缘。

2.3、当终点在岛内时,JPS+

        当终点在岛屿内部时,采用JPS+的方法进行计算。
        由于A*寻路过程中会产生多余的节点被放入OpenList,导致OpenList过大,性能消耗过高。 JPS算法就是对A*的一个改进。JPS事先寻找到地图中可能的跳点,之后仅使用跳点进行A*运算。而JPS+算法则是先离线生成每个格子8方向到跳点的距离,运行时可以加速计算。

        关于算法,可以参考文章:KillerAery_JPS/JPS+ 寻路算法

3、方案特点

        此方案除了效率高之外,还有以下特点:

  • 可以分段寻路,即不用建立所有的路径点仍然可以行走

  • 迁城不影响大的路径:因为一个城只占用一个Chunk,玩家迁城不会影响栅格化的路径,服务器只需要部分重新计算而不需要全部重算。

  • 即便不知道完整数据,客户端仍然可以预测出路线。(因为第一段路线一定是起点到终点的直线,直到遇到第一个岛)局部寻路与整体寻路结果相同。

  • 容错率较高,只要服务器能正确同步动态岛屿(只需要目标船只附近的)的信息,即便是完全没有服务器的寻路数据,客户端依然可以模拟正确的完整路径。

4、通用开放世界寻路的思考

        其实在开发过程中,就是把整个大世界进行了分块,且确保了各个分块之间能互相联通。这样,在最上层的寻路就可以直接走直线而不必关心每一个格子的阻挡。

        抽象来看,即便是非航海主题的开放大世界,也可以用这个思路来设计寻路。

《霍格沃兹之遗》的世界地图(局部)

        现有主机游戏的开放世界 3A 大作,其地图可以明显看到设计过的痕迹。各个区块之间有明显的区分,这就给全局寻路创造了可能。只要在地图设计上,每个区域可以互相联通,且还有若干条大路贯穿整个地图,就能很方便地实现全局寻路。

        对于区域而言,其邻接的区域是有限的几个,可以提前算好连接路线。而在地图内部,可以直接引导寻路至道路上,然后沿着道路前进就行了。

  • 17
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值