沙盒、无缝地图设计(个人想法,草稿)
目录
一、简介
二、地图切分
三、寻路处理
四、补充
四、总结
一、简介
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。大小关系如下图所示:
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中数据,不能修改其中的数据,反之亦然。
三、寻路处理
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次方。目前设计依然时一个服务器承载几千人在一个进程中实现。如果需要更大的地图,更多的在线人数,实现全区全服在一个地图上,理论上使用多进程消息通信实现是可以的。