沙盒、无缝地图设计(个人想法,草稿)

目录

​一、简介​

​二、地图切分​

​三、寻路处理​

​四、补充​

​四、总结​


一、简介

MMO(大型多人在线游戏)无缝地图设计。主要目的解决目前手游通用的分线策略和地图安场景分割,提升单地图人数的承载量,实现资源消耗低动态分割 。主要针对服务器无缝地图处理及服务器搭建,涉及地图切分、线程模型分配,navmesh寻路处理,战斗设计,数据存储模型。待补充方案,服务器碰撞物理引擎,AI,网络通信,沙盒同步。 涉及技术:

1. 四叉树进行地图区域动态分割管理

2.九宫格进行空间对象同步管理

3.navmesh和A*算法进行寻路查找

4.netty的EventLoop线程模型实现地图区域消息顺序处理

二、地图切分

1.四叉树地图分割

地图(MapInfo)长度以米为单位,使整个长度为2的n次方(为使地图、区域和九宫格同步格子在唯一包含在某个对象内,区域最小单元为一个九宫格,最大单元则为整个地图)。如4096*4096的地图。一个地图对应多个区域(AreaInfo),一个区域分配一个线程队列(EventLoop,独占线程),即区域为地图管理执行的基本单元。区域长度为2的n次方,如512*512 地图同步九宫格为也为2的n次方,如32*32。大小关系如下图所示:

沙盒、无缝地图设计_四叉树沙盒、无缝地图设计_寻路_02

AreaInfo扩张:

a、首先使用四叉树将地图分割成等分的四个区域,假设以每个四叉树单元最大承载1000同步对象运算,左上区域超过为2000人,其他区域BCD都各自少于1000人,则将BCD区域分别设为AreaInfo和线程队列。 添加编号1、2、3、4。

b、将左上区域再进行四叉树分割,编号为5、6、7、8,如果EFG区域同步对象少于1000,则为之分配AreaInfo和现场队列。 如果左上仍然大于1000个同步对象,使用四叉树再进行分割,直到当前区域同步对象小于1000。假设9、10、11、12已是最后的分配区域

AreaInfo收缩:

a、当地图9、10、11、12内的总同步对象少于600人时(60%为阀值),则取EFG的共同父对象作为执行AreaInfo(绑定线程队列),9,10,11,12区域的消息全部放到父AreaInfo队列中执行

b、当9、10、11、12的父对象任然不到600人时,执行步骤A,直到最大值

2.边界数据同步处理

如下图所示,当玩家处于区域(AreaInfo)边界同步区域时,需要和其他区域的玩家互相看见并交换。如图中有四个区域,ABCD,当玩家所在格子1时需要分别看见再BCD区域的234格子中的对象,因此需要将234格子中的对象同步复制到A区域,反之亦然。

因为1,2,3,4所在区域在不同的线程处理,因此存在并发型问题,因此1和2中的对象处理逻辑需要实现线程安全处理,数据修改放在各自的线程中处理,1只能读取2中数据,不能修改其中的数据,反之亦然。

沙盒、无缝地图设计_四叉树_03沙盒、无缝地图设计_寻路_04

三、寻路处理

1.navmesh行走面处理

a、将客户端地图整个行走面navmesh导出为json数据放在服务器,服务器预计算所有凸多边形和相邻多边形的连接关系

b、将整个地图使用四叉树进行所在区域分割,如一个区域最大有20个凸多边形。分割目的快速定位获取一个坐标所在多边形和区域

c、按上面划分好的区域(AreaInfo)计算每个区域拥有那些凸多边形。目的用于A*寻路遍历消耗,减少遍历运算消耗。

2.寻路计算

获取A位置到B位置到移动路径

a、使用 1-b中方法获取A,B所在的区域

b、若A,B在同一凸多边形,直接返回AB坐标点为路径列表

c、若A,B不在同一凸多边形,而在不同区域,直接使用它们所在区域进行A*寻路

d、若A,B不在同一区域,首先使用向量移位运算计算所经历区域,然后合并遍历多边形列表,进行A*寻路计算

补充:d远距离寻路运算可能失败且耗性能,因此最好提前手动生成行走路线。当然服务器一般很少是有远距离寻路,客户端使用较多

四、补充

1.数据对象

a、存储数据对象Role和战斗场景计算对象Player分开,Role对象类似Netty的channel为之分配一个EventLoop(共享线程)线程进行逻辑处理,Player对象交给区域(AreaInfo)EventLoop线程队列(独占线程)执行。

b、用户数据和配置数据使用mongodb,日子数据使用mysql

2.服务器物理引擎

待研究,可参考libgdx移植物理引擎到服务器?

解决玩家对象重叠问题?

3.网络通信

使用netty,消息队列中间件?ZeroMQ或阿里的消息队列?

4.沙盒对象同步

如我的世界中自己组装的建筑物怎么同步?登陆地图时对比客户端和服务器的建筑列表标示位(为每个修改过的建筑建立唯一ID标示位),然后服务器推送建筑信息的具体信息(标示位,坐标,构造...),客户端缓存标示位,然后客户端更具具体信息下载资源构造地图面貌并进行缓存?

具体实现待研究

四、总结

使用此方式的优点可以动态分割地图处理单元(AreaInfo),避免地图人多时线程处理不过消息,或地图人少时浪费线程资源,最大化利用cpu,实现负载均衡;缺点地图分割的单位都限制在2点n次方。目前设计依然时一个服务器承载几千人在一个进程中实现。如果需要更大的地图,更多的在线人数,实现全区全服在一个地图上,理论上使用多进程消息通信实现是可以的。