多人实时对战网络同步方式研究

写在开头:已经研究生毕业快一年半了,一直在一家游戏公司做客户端研发。至于这篇文章讲的却是服务端的东西,主要是因为以前一直没想写博客,学到的东西也一直记在本子上就得了。本人喜欢有剧情的东西,像RPG游戏(仙剑爱好者),有剧情的电视、电影,还有竞技类型的游戏,像dota/2、王者荣耀等。最近在做的项目和玩的王者荣耀都涉及到游戏的同步问题,王者荣耀做的不错,但也有自己的问题,就准备研究下这方面。本文的内容是从这两个网站https://developer.valvesoftware.com/wiki/Source_Multiplayer_Networkinghttp://www.gabrielgambetta.com/fast_paced_multiplayer.html学习总结出来,并实现了一个demo,效果也确实不错。

好了,下面说点具体的内容,所有的内容以moba类游戏为例。

所有moba类游戏或者一些对同步要求比较高的游戏都面对一些具体的问题。一、如何让玩家体验到非常流畅的体验,而不是一顿一顿一卡一卡的表现等。二、如何防止玩家作弊。

针对玩家作弊,我进入游戏界最先听到的一句话就是“永远不要相信玩家”,一切操作都在服务端实现。但是呢由于手游的崛起以及流量的费用,一些手游还是会部分的相信玩家。

扯远了,一句话就是“在服务端进行验证”。那么最简单的实现就是玩家的任何操作都先向服务端发送请求,然后等待服务端的响应做出相应的反馈。如图一所示。客户端想向右移动一个单位,先向服务端通知,服务端反馈给客户端结果。客户端在100ms的延迟之后执行向右移动一个单位的操作。


图一

很明显上面的结果是,玩家点了向右移动的按钮,过一会才会向右移动(体验很差)。

 

优化一下 :既然上面体验不好就优化一下呗,可以发现如果我点击向右移动按钮,就直接向右移动,而不是等服务端的响应就会比较好。可是这就引发了问题二,玩家作弊怎么办?大家可能已经想到了,我先向右走然后等服务端的响应,等服务端发送过来响应的时候再检查一下,当前客户端的状态是不是对的,如果对的就好了,不对的可能就是客户端作弊了,比如说跑的快了。如图二所示。


图二


问题:但是上面又有一个问题,如果服务端响应的较慢,在服务端响应回来之前玩家已经又进行了一次操作怎么办呢?如图三所示。


图三

一个可行的方案是:客户端没法送一个操作给服务端的时候,加上一个序号。客户端继续按照上面介绍的方式去运行,不用等待服务端的反馈。当服务端的反馈到来的时候,客户端不再是去检测当前客户端的状态和服务端反馈的状态是否一致,而是要检测客户端当前的状态与服务端反馈的状态+还未执行的客户端状态是否一致。如图四,当服务端反馈#1时,客户端的位置为12而服务端的反馈的位置是11, 但是服务端反馈的位置11+#2的操作的结果是位置12所以验证时合法的。同理在服务端反馈#2的时候,验证的结果也是合法的。可见使用这样的方法,可以保证合法的玩家的用户体验很不错,同时能检测到作弊的玩家,对于作弊的玩家怎么处理可以根据项目的具体需求具体操作。


图四


上面解决了客户端内只有自己的玩家的问题,当有其他玩家的时候,如何同步其表现呢?

我们还是从最简单的开始考虑。如图五所示,那就是服务端直接同步客户端1的操作结果给客户端2,客户端2直接设置玩家1在客户端2的位置,你会发现在客户端2上客户端1的玩家的位置一跳一跳的。

一个可行的简单的优化是:既然你一跳一跳的表现不好,那我们就让它平滑一点呗(游戏中常用的方式)。让它在一段时间内以一个恒定的速度从当前位置移动到服务端反馈的位置。这样表现会稍微好点,但是当我们设定了一个恒定的时间或者恒定的速度,都会出现玩家很快移动到目的地停下来等待下次操作或者还没移动到目的地就要向下一次目的地移动,一直跟踪不上节奏。聪明的读者可能想到,出现这个的问题是因为我们无法预测玩家下一次到到达的位置,无法动态的平滑的调玩家的移动速度、移动时间来刚好达到目的地。一个巧妙的方式是“我们不要追踪当前即时的目标点,而是追踪一个我们已知的目标点”。如图六所示,我们来介绍这句话的理解。由于服务端会同步别的客户端的玩家的位置给你。在当前时刻了客户端2已知知道了客户端1经过第二次操作跑了位置12和上一次操作玩家在位置11.在当前时刻,根据一个延时,算出客户端1的玩家在一个延时之前的位置,把它表现出来,这样客户端1的表现就会很流畅。比如设置延时时间为0.1s,对人眼而言也没有什么大的误差。对于像cs:Go这样的游戏,还可以通过在服务端上做延时回放可以得到精确的位置,这里就不介绍了。想看的话可以去提供的链接1valve上去看。


图五


图六


说了这么多具体怎么实现呢?

由于涉及到客户端和服务端,要是都讲的话,只服务端都得介绍很久。这里我只讲下实现的具体思路,特别想知道具体的实现或者自己实现有问题的,可以联系我一起讨论下。

 

客户端:

一个全局的操作序号:  seq

有一个记录上传服务端的操作序列,记为self_op

一个记录其他玩家的操作反馈,记为other_op

 

玩家操作时:

记录到self_op中

同时seq++

在客户端直接操作

 

定时器:

定时上传self_op到服务端上去

 

服务端回调结果:

如果是自己的:

         根据反馈的操作序列+剩余的操作序列self_op与当前客户端玩家状态进行验证

         合法 ok  不合法:惩罚

如果是其他玩家的:

         记录到other_op中

 

logic循环:

       根据other_op和设定的延时时间计算并设置其他玩家的状态

 

服务端:

根据收到玩家的op,计算玩家的状态,存储到status中

 

logic循环:

同步当前所有的玩家状态给同一个team的所有玩家

 

(注:这是原理的实现,具体项目实现肯定还要进行一些针对性的优化)

 

 

好了,第一次写博客。 谢谢大家!

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值