深入广播算法

          对于MMORPG游戏来说,每个场景的人数可能会以千计,为了服务器性能考量.每个玩家的视野必然要有所限制。广播算法主要是用来解决如何高效让每个玩家感知周围物件.本人重点讨论各种广播算法和优化

.常用算法说明

概念说明:

实体需要服务器管理状态的各种object.比如玩家/NPC/宠物等

 

广播算法最原始的做法,每个实体保存一个周围实体列表,再定时检测整个场景内实体之间的距离.据此派发出现/消失,算法复杂度是0(n^2).对于稍大些的场景,实体个数可能会上万,这部分的消耗会非常可观,采用的人也很少.

现有游戏的广播一般会基于格子来计算,常用的有3*3, 5*5广播.通常的流程是:

玩家进入场景时,根据坐标添加到对应的格子,每次移动时检测是否跨格子,如果跨越,计算出消失/出现的格子.对其中的实体派发事件.玩家退出场景,再对周围格子内实体发送消失事件.

这个算法最大的好处是把距离检测的消耗均摊.总体的消耗也非常少.缺点是视野的不对称,玩家不可能总是居于格子的中心点,大部分的情况是玩家某个方向上能看到50M,另外一个方向可能看到100M.这些冗余的视野会显著的增加服务器的流量.一个理想的状态是玩家无论在那个方向上,视野都是一致的.即圆形视野.

假定策划要求的最小视野是R,我们可以计算出各种算法的视野面积

3*3广播,玩家的视野面积是 (3*R)^2 = 9*R^2

5*5广播,视野面积是 (5*R/2)^2 = 6.25*R^2

圆形广播, PI*R^2

视野面积与广播流量是成正比的,从这里的计算可以看出,圆形算法能显著的减少广播流量.

.圆形广播算法

上节总结了圆形算法所能带来的好处.这节重点说下实现.

考虑实现,首先我们针对问题做更细的分析

1.既然是优化广播,实际中我们做的处理只需要针对 玩家到 玩家/NPC/宠物等可能产生大流量的实体类型 即可。其他所有出现/消失逻辑都用格子算法

2.在副本内,广播量不大,可以不用做圆形广播.

我们综合原始算法和格子算法的优缺点.保证场景的格子大小为最小视野R的前提下,确定如下圆形广播算法流程(假定玩家/NPC/宠物等需要检测的类型是实体A):

      1.玩家进入场景,取九宫格范围内实体A.判断距离,视野内的派发出现事件

      2.玩家退出场景,对于之前保存的广播实体派发消失事件.

      3.玩家在场景中移动产生的出现/消失通过定时判断距离来触发.

这里步骤3是重点.又分成以下三步:

                  1.玩家的周围实体列表保存一个标记位.每个定时轮回开始,置为0

                   2.场景内的每个玩家以他所在格子C为中心的九宫格内.总是检索 格子索引不C小的格子内的实体A.视野内的标记置为1.如果是周围列表内是第一次出现的,派发 出现事件.

                    3.检查每个玩家周围实体的标记位.依然为0的派发消失事件.

出于效率的考虑,还需要注意一些细节:

  1.为了更方便快捷的取格子内的指定实体,格子内实体按照类型存储

  2.定时检查的步骤1,可以合并到步骤3.

  3.周围实体也按照类型存储.减少定时检查步骤3的消耗.

  4.周围实体列表的数据结构选取很关键.经过测试,经过内存优化的hash_map在这里具有更好的适用性.

总体实现下来,1600实体的检测消耗依然会达到6%以上.是很大一头.需要考虑更多的优化

三.更多优化

圆形算法的定时检测是个计算密集的地方,更多的优化,需要考虑进一步挖掘硬件的潜力.可供选择的有 矢量化(SSE),并行化以及利用GPU的通用计算能力加速(OPENCL).根据算法的特点以及服务器的硬件条件(核多利用不充分,GPU),选择并行化进行下一步的优化重点。

并行化的底层实现方案有很多比如openMP,tbb, vc2010的自带并行库自实现等.

为了更好的适用性以及方便,可以选openMP.

现在服务器逻辑结构一般都是单线程/多进程的.引入并行化后,为了防止多线程的扩散,以及尽量多的计算放入到并行循环中需要我们把检测期 派发出现/消失事件的逻辑剥离.等并行计算结束后再触发.

    定时检测的主循环并行后,大概如下:

#pragma omp parallel for

for(iy = 0; iy < m_cntRow; ++iy)

curCellID = iy*m_cntCol;

for( ix = 0; ix < m_cntCol; ++ix, ++curCellID)

{

检测curCellID内玩家到其他格子实体的距离

检测本格子内 玩家到其他实体的距离,并审查标记位

}

}

触发缓存的事件

并行后的效果非常明显,根据核的个数,一般能提升N*0.9.8000实体相互检测只占5%左右

四.广播算法的复用及其他

鉴于广播在服务器的重要性,为达到最大化复用/优化的效果.我们可以在服务器另外启一个进程专门来做这个事情,约定跟主逻辑服的协议,可以让所有游戏通用

定义主逻辑服为M,广播服是N.协议定义如下:

M-->N    创建场景

M-->N    某个位置创建实体

M-->N    实体移动

M-->N   实体删除

N-->M    实体之间出现

N-->M    实体之间消失

 如果出现/消失事件本身的处理消耗比较大的话,可以对圆形视野广播算法适当进行改进,小视野进,大视野出.减少玩家频繁在边界来回移动产生的事件

.引申应用

  基于如上的算法思想,也可以把它应用于无限大世界的客户端资源加载上.

  客户端的资源加载也有服务器广播的缺点:资源加载不均衡,边界地带还会有频繁的创建和销毁.

  我们可以在九宫格基础上,把每个格子继续细化成更小的格子.通过小格子距离的判断来近似达到圆形加载的效果.

  再引入大小视野,减少边界地带的创建/销毁.


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值