现在的位置: 首页 > 综合 > 正文

实时多人在线游戏研究(同步和延迟)

2013年09月18日 ⁄ 综合 ⁄ 共 2530字 ⁄ 字号 评论关闭

本文讨论实时多人在线游戏的服务器和客户端技术。

实时多人在线游戏主要包括2类,FPS(quake系列,UT系列,CF等),ACT(DNF,龙之谷这类)

 

其共同特点是需要用户操作尽快的得到体现。并且所有客户端的结果要一致。

同一世界玩家数量较少(这是有原因的,下面讨论),有较真实的物理效果模拟。

 

通用的C/S做法:

A. 客户端采样输入数据->Server处理数据->分发结果。

其他不可靠的实现方法:

B.客户端采样计算动作结果->通知server(校验)->分发结果

或者p2p         ->>>>>>>>>>分发到其他client

 

这里输入数据就是用户的操作,比如开火/技能,移动这些。

 

A.做法所有数据在服务器上面处理,因为客户端不可能直接修改服务器数据,所以数据是可信的(利用bug除外)

由于数据在服务器处理,所以结果一定会有延迟(传输时间)

B.做法的不可靠在于数据的处理是由客户端进行,由于客户端hack可能具有很大的作弊空间(DNF/洛奇全屏秒怪什么的)。加上server端校验可以一定程度上减少作弊。

好处是所有结果本地立即获得,客户端体验很好。

另外在客户端相互作用时,因为延迟的关系,可能会有很奇怪的同步效果(跑跑卡丁车被影子撞飞)。

 

下面只讨论A的实现

==============================================================================

采样方式分固定采样和消息采样。

1.固定采样是以一定的时间间隔,采样所有输入的状态,主要用于fps游戏。一般为20-40hz。

2.消息类型的采样,只在输入状态变化时发送变化的数据。(就像KEYDOWN,KEYUP这样)act游戏很适合这种。

fps类游戏只能固定采样的原因是鼠标输入都是连续的数据。如果用消息的话一次鼠标move就可能产生很多的采样请求。

另外可以1,2组合为混合采样,对鼠标用固定采样,其他按键用消息采样

 

为了减少延迟,客户端在发出采样后,可以立即本地模拟计算结果,然后开始做预测移动。

server收到采样数据后,根据时间戳来计算真实可靠的结果,分发到每个客户端。

客户端收到自己的结果后,计算预测结果和实际值的误差,误差超过一定范围后做误差修正。

客户端收到其他客户端结果后,插值显示其他客户端状态。

 

 

延迟的影响:

假设采样速度为1单位.

设客户端A/B到服务器S ping 延迟为2单位,那么路由对称情况下a->s == s->a == 1 , b一样。

server time: 0          1             2                 3                   4      

S        发送:s0                       ar1+br1       ar2 +br2                 

           接收:                           as1+bs1     as2+bs2     

A         发送:            as1          as2                

           接收:             s0                               ar1+br1

B       发送:              bs1        bs2

          接收:              s0                               ar2+br1

 

上面s0是server 的初始化消息,as/bs是a/b的采样包,ar/br是采样对应的结果。

由以上表格可见:

对A来说,他的动作会经过1/2 ping后在server体现,同时他看到的B是1/2 ping以前server上的状态。

也就是说,如果ping是2秒的话,你看见一个人,瞄准后开火,基本上都打不中人。

(里我们不关心B实际的位置,因为B实际在这个时间的位置是客户端B自己模拟的结果。我们只关心本地和server上的区别)

 

降低延迟影响的tick。

1.历史快照

CS Source做法是保留客户端最近的一些快照,对于高延迟玩家,选择历史快照里面最近的一个来做射击时的判断。

CSS资料里面说保留0.5秒以内快照(可设置)

引入的问题:

假设一个战壕或是其他什么东西,角色蹲在里面是完全不可能被打中的。

一个玩家蹲下后,还是有可能被高ping玩家击中(因为历史快照里面可能还是站起状态)。

2.另外一个办法是本地预测其他客户端:

因为A动作执行在1/2ping后,B现在位置是1/2 ping以前的,如果能精确计算出B在time=time+ping以后的状态的话,A瞄准预测后的B应该和Server端结果一致。

不过因为预测结果的不准确性,可能会使得玩家体验变得很差(插值预测结果可以稍微改善这个情况)。

3.Server延迟计算(Server模拟客户端状态)

令T=min(所有玩家的ping)

Server收到输入后,用输入时间-T/2 以前的server状态做射击判断,生成下一帧,发送并缓存。

一定时间后,更新所有玩家状态到下一帧。

 

对上面表里面情况来说

time 2时,server计算的是1时射击检测,生成的是3 的快照。

time 3时,server计算的是2时射击检测,生成的是4 的快照。

看起来很完美了。唯一的延迟在于击中效果的滞后。

和1不同的是这个算法相当于对所有玩家的ping 减去(T/2+sample rate)。例1里面的情况基本不会出现(除非所有人ping都很高,但这时仍然可以说是完全公平的)

 

现在的问题是,假如某个客户端ping很低,其他人ping高,那么这个算法就基本不起什么作用。

幸运的是高ping模拟低ping很难,但是低ping模拟高ping是比较容易的事情。

一个简单的做法是缓冲低ping玩家输入输出包,使其变为ping >=T的效果 ,这样可以把T设置为一个固定的值,比如100ms。

 

因为客户端采样帧/结果的错位,事实上所有lag降低算法都无法完全解决延迟的影响,只能是改善不同ping玩家之间的优劣势。

 

 

 

 

 

抱歉!评论已关闭.