网络游戏同步问题综述

http://blog.csdn.net/yxriyin/article/details/23377271

最近看了比较多的网络同步问题因为我只做过回合制,没做过arpg,所以稍微去看看大致是怎么实现的。基本上可以归为两个问题:玩家位置同步和战斗指令同步。玩家位置同步的情况要比战斗指令同步的情况简单,不过正因为如此,你为了更好的同步,就会采取复杂的同步策略。另外,这两种同步其实是息息相关的,战斗肯定会涉及到位置判断。所以我打算一起思考这两个问题。

首先我们要知道在arpg游戏中,是需要对时协议的,就是说客户端和服务端的时间戳要基本保持一致。至于这个对时的频率和策略,可以有各种优化的版本,我们只考虑最简单的情况,就是每隔一段时间同步时间戳。一般可能是5HZ或者10HZ,当然战斗时候肯定会高些,平时可以降低些。

为啥需要一个时间戳呢?因为不论是位置同步,还是防止玩家使用加速器,包括客户端作弊等,在有时间戳的情况下会简化很多。

首先利用对时协议可以让客户端和服务端得知网络延迟的大概时间。虽然是大概,但也是比较准确的。

为了更好的阐述问题,我们假定玩家A,网络延迟为1s,玩家B,网络延迟为2s。这是非常大的延迟,因为如果是100ms左右的延迟,其实不用采取任何技术你都能跑得比较爽。

玩家A本来位于坐标5,下达了向坐标10移动的指令,玩家速度为1,服务端接收到指令的时候,玩家理论上其实已经到坐标6了,这里我们是无法让玩家A等待服务器响应再移动的,因为没人受得了我移动一下都要卡1s。服务端知道网络延迟为1s,所以可以轻易估算出位置为6,同时向B通知A的位置, B获得了A的坐标,其实A应该已经到8了,当然B也知道网络延迟,所以也能估算出A的位置应该是8。一切看上去都似乎还可以,但不难发现一些问题。首先,网络延迟是不稳定的,忽高忽低,根据时间戳去计算,是需要检测其合法性。比如延迟高达10s,你估算的结果都快让玩家瞬移了,我们可以判定10s的延迟肯定是不合理,甚至可以丢弃这个包。假定2s一下的延迟才会进入估算,而2s以上的,恐怕还是当做2s来处理。那玩家如果作弊呢?发各种各样奇怪的位置过来,这也是需要检测的,服务端肯定有玩家原来的位置,通过与玩家新位置的比较,看看两者的时间差有没有可能做这样的移动,如果没可能,说明有作弊嫌疑,多次发现,就直接踢下线处理。这样似乎解决了这个问题。但再思考,玩家A下达这个指令后,B将A同步到8,突然A的第二条指令来了,A跑到5.5之后,其实往回跑了,同理,服务端接收到信息,发现A的位置是5.5,这和本来预测的位置6相差0.5,说明自己的预测产生了误差,我们依然采取相信客户端的做法,因为假如你强行同步A位置为6,那么玩家A会产生往回跑的奇怪体验。这时服务端通过估算A在4.5,当然A可能突然停下来,这个问题我们不考虑,因为只需要增加一个停下来的指令或者判断目标位置就可以解决。服务端这时候通知B,A到4.5了,B收到信息,估算出A应该在2.5,发现问题所在了吧,A本来应该在8的怎么突然跑到2.5了?当然由于中间只经过了0.5秒,所以A在B看来还没到8,只是在向8跑的路上,大概是7。如果我们没有任何估算,那么情况会变成A在6,服务端认为是5,同时告诉B A在5,延迟了1, 如果A跑到5.5回头,那么A其实在4.5,服务端认为是5,B收到也是5,这样看起来似乎也没那么糟糕。那么问题的症结来了,如果不估算,那么毫无疑问,服务端获得的位置是客户端延迟前的数据,客户端得知其他玩家的位置则是两边延迟的叠加。这绝不是一个好的策略。那么估算的风险我们也看到了,可能会误打误撞反而是误差变大。我们发现误差变大的原因是玩家突然变向往回跑,导致经过一堆延迟后的速度相反,反而是误差增大。但也许这些都不是问题,这里我拷贝云风大大的一段话:

一种,收到的信息是属于其它玩家的。我们从最新得到的状态信息,预测一段时间之后(比如一秒后的状态),用一条直线运动去修正。即,设想一秒后这个玩家在哪里,然后反推回现在应该用什么速度运动可以在一秒后到达那个地方。

另一种,收到的信息是属于自己的,即服务器认可的自己的状态(并广播给别人了)。这个偏差是由于服务器的预测补偿造成的。为了保持用户的操作手感,对于不太极端的偏差,我们全部不修正,而是依然发送客户端自己操作的位置状态给服务器。服务器那边玩家是处于一种离散的运动状态的。而其他人见到你会再做预测补偿;如果和服务器相差过于剧烈,则直接跳转到服务器认可的新位置。

这里几乎全部相信客户端的行为,以获取最好的操作手感。防止客户端作弊是另外一个话题,也不是不能解决的,但目前不要碰了。

客户端到底以怎样的频率发送那些位置信息给服务器呢?

策略应该是这样的:

每次发送完一个完整的位置信息后,预测服务器看待这个位置信息包一秒后的位置大约在哪里。每次变化做一个累积,一秒内都但不用立刻发送。但每次小的状态改变都和假设的预测位置做一些比较,如果位置偏差比较大,就可以提前发送。否则一直累计到一秒再发送。

这个一秒的周期可以根据实际测试情况来调整。可能一秒太短,也可能过长了。

每次收到服务器发送过来的新的玩家位置信息时,都在里面会找到一个时间戳,表识的包发出的服务器时间。客户端可以验算之前的网络延迟是否正确。如果网络延迟稳定在一个固定值,说明没有问题。但如果延迟值为负数,则说明之前的对时流程中网络不稳定(可能是因为上下行时间偏差比较大造成的,也可能是当时服务器负载很大,造成了较大的内部延迟),造成本地时间和服务器时间的时差计算错误。这个时候重新发起对时流程就好了。

以上就是云风博客中内容,我们可以看到对于B玩家而言,A玩家其实已经不再误差范围内,应该直接将它变成2.5或者4.5,这么来看由于刚才我们分析B大概在7左右,如果从7变成4.5似乎还是可以接受的。毕竟本来我们就是从5变成了8.一切也没那么糟,当然如果你要把它变成2.5,那么只能使用瞬移了,不然玩家总是以一种比常人快的速度运动了。所以,我个人更喜欢保守估计,不要说太满,宁愿延迟一些位置,也不要过头了。

基于上述的结论,我们来看看玩家只是跑动的话毫无疑问是感觉到流畅的,因为所有人都没有等待就看到自己开始移动了,一切似乎都很完美。但是,如果是战斗呢,先不说pvp,我们就将pve好了,玩家对怪物进行攻击,如果有网络延迟,我们不得不等待,因为这个是不能放在客户端计算的(当然确实有游戏这么做,这个我会再写一篇博客探讨)。我们不能信任客户端,所以玩家延迟1s在攻击出手,这似乎非常蛋疼。然后看怪物,怪物攻击玩家是客户端发起呢还是服务端处理呢?首先我们对怪物也是要做位置同步的,因为怪物的AI肯定是客户端直接处理。假设是客户端发起,它同样也有延迟的问题,不过由于是怪物,也就无所谓了。但是我们说了移动是瞬间的,那么玩家攻击了,然后直接跑走,却发现攻击要在1s后才响应,自己明明要跑走,却突然去攻击了对方一下。这里有一个技术叫做客户端预测。当你攻击怪物的时候,客户端按照服务端的代码去执行,所以你确实看到自己毫无延迟的砍了下去,当然服务端那边也会计算,不过是1s之后的了,这时候你收到了服务端计算的结果,如果结果和客户端计算的是一样的,那么恭喜,你啥都不干就行了,玩家非常流畅的结束了战斗。但如果服务端计算和客户端不一致呢?没错,由于暴击概率,闪避概率等等的存在,很可能你客户端打中了服务端却没有打中,当你发现状态不一致,你就直接同步状态。那么问题来了,我客户端预测的意义在哪?只是为了播放那几下攻击,然后发现怪物慢慢的在1s后作出响应,而我还是默默的攻击着。虚幻引擎作者说:用缓冲技术,客户端存储状态和指令,当服务端状态发送过来时不是单纯的同步,而是将缓冲中无效的指令先去掉,比如已经过时的指令。然后再把服务端发过来的状态插入第一个,用操作缓存中的指令继续预测,获得到最新的状态进行同步。但你马上就意识到了,那岂不是不停的重复指令了?没错,你会发现你杀死了一个怪,突然这个怪又活了,又被你杀死了。为了避免这个问题,我们要确保每个指令其实只是被执行一次,也就是说你每次预测同步都只是执行一次的动作后更新结果,如果这些指令执行过了,那么你不用执行了,单纯的去同步结果就好了。当然还是会有怪物突然加血减血的问题。而且这个技术的最大问题在于你的客户端也要有服务端的对应的逻辑代码。对于真大作才能如此霸气。所以不打算采用这种技术。

那么我们只能老实接受这个延迟带来的坑爹现象了嘛?还是有些小技巧的。比如攻击前摇,你攻击的时候,先要抖一下,这个抖可能没有实际作用,但确实的提供了短暂的时间等待服务端返回结果。这当然不算啥技术,但是我们不得不正视一个事实,网络不好肯定体验就会变差,而且打不过网络好的玩家。比如pvp,无延时的玩家,几乎是发出一个指令就打到你了,你一点办法都没有。老实的等待被打吧。当你攻击别人时,你觉得打中了,但到了服务器那边发现人家老早走远了。所以如果是pve,还是能对网络不好的玩家做些补偿,毕竟能打中就当做打中好了。

基本就这些了,讲的可能比较乱。想看其他资料的参考我转载的一篇博客,网络同步啥啥的,有几篇英文写的特别好。

时间: 2024-10-08 12:28:32

网络游戏同步问题综述的相关文章

[转载]小谈网络游戏同步

小谈网络游戏同步 同步在网络游戏中是非常重要的,它保证了每个玩家在屏幕上看到的东西大体是一样的.其实呢,解决同步问题的最简单的方法就是把每个玩家的动作都向其他玩家广播一遍,这里其实就存在两个问题:1,向哪些玩家广播,广播哪些消息.2,如果网络延迟怎么办.事实上呢,第一个问题是个非常简单的问题,不过之所以我提出这个问题来,是提醒大家在设计自己的消息结构的时候,需要把这个因素考虑进去.而对于第二个问题,则是一个挺麻烦的问题,大家可以来看这么个例子: 比如有一个玩家A向服务器发了条指令,说我现在在P1

网络游戏同步的算法

转自:https://blog.csdn.net/lovemysea/article/details/78888739 不知道大家是否碰到过这种情况,当某个玩家发出一个火球,这个火球有自己的运动轨迹,那么如何来判断火球是否打中了人呢?大部分情况,当策划提出这个要求的时候,一般会被程序否认,原因是:太麻烦了,呵呵.复杂点的还有包括两个火球相撞之类的事情发生. 那么网络游戏中,是否真的无法模拟实现这种模拟呢? 首先我们来看看模拟此种操作会带来什么样的麻烦: 1,服务器必须trace火球的运行轨迹,乍

[转载自CSDN] 网络游戏同步法则

出处 http://blog.csdn.net/skywind/article/details/392461 ----------------------------- 网路的硬件也有限,而人的创造也无限,在公网平均130ms的Latency下,是不存在“完全的”的同步情况.如何通过消除/隐藏延时,将用户带入快速的交互式实时游戏中,体验完美的互动娱乐呢? 以下六点,将助你分清楚哪些我们可以努力,哪些我们不值得努力,弄明白实时游戏中同步问题关键之所在,巧妙的化解与规避游戏,最终在适合普遍用户网络环

网络游戏同步法则

网路的硬件也有限,而人的创造也无限,在公网平均130ms的Latency下,是不存在“完全的”的同步情况.如何通过消除/隐藏延时,将用户带入快速的交互式实时游戏中,体验完美的互动娱乐呢? 以下六点,将助你分清楚哪些我们可以努力,哪些我们不值得努力,弄明白实时游戏中同步问题关键之所在,巧妙的化解与规避游戏,最终在适合普遍用户网络环境中(200ms),实现实时快速互动游戏: 1. 基本情况:(A) 网络性能指标一:带宽,限制了实时游戏的人数容量(B) 网络性能指标二:延时,决定了实时游戏的最低反应时

SynchronizationContext(同步上下文)综述

>>返回<C# 并发编程> 1. 概述 2. 同步上下文 的必要性 2.1. ISynchronizeInvoke 的诞生 2.2. SynchronizationContext 的诞生 3. 同步上下文 的概念 4. 同步上下文 的实现 4.1. WinForm 同步上下文 4.2. Dispatcher 同步上下文 4.3. Default 同步上下文 4.4. 上下文捕获和执行 4.5. AspNetSynchronizationContext 5. 同步上下实现类 的注意事

关于游戏的网络同步探索

找了些资料,以后慢慢更新 著名游戏网络同步方案汇总 下表为本人汇总的各著名游戏的网络同步方案,已尽力添加引用来源.通过该表,读者可尝试思考:为什么他们会采取这样的方案?找找看有否什么规律?相信看完下文,应该可以找出答案.注,本文的锁步同步(Lockstep)特指只同步操作的确定性锁步同步(Deterministic Lockstep).本文不讨论快照同步(Snapshot Synchronization.Snapshot Interpolation),认为其等同于状态同步(State Synch

cocos2dx3.2开发 RPG《Flighting》(一)基本介绍

前言: 上次写了一个消灭星星,很多人都回复了我,并且提出了宝贵的意见,先感谢大家啦~上几个月我发现了一个很好玩的游戏--<BattleHeart>,心里面想着,这么好的游戏要是可以联机跟好朋友一起玩(就像CS那样)那就爽歪歪了,于是就动手开始模仿这款游戏,并且为其加入网络模块.可惜,因为对多人网络游戏开发并不熟悉,虽然最后还是开发出来了,但是效果却差强人意.不过在开发过程中学到了很多新的知识和网络游戏用到的技术(例如boost::asio搭建服务器,网络游戏同步等),也算是一个不错的经历了.

帧同步在竞技类网络游戏中的应用

帧同步在竞技类网络游戏中的应用 帧同步在网上可以搜的资料比较少,关于游戏的更是没有,不过,实现的原理也比较简单,最近几天就写了份关于帧同步的文档,当作给同事扫扫盲,顺便也在这里发发,可以给其他人参考参考     --竞技类网络游戏设计方案   一.        前言 帧同步,根据wiki百科的定义是,一种对同步源进行像素级同步显示的处理技术,对于网络上的多个接入者,一个信号将会通过主机同步发送给其他人,并同步显示在各个终端上.同步信号可以是每帧的像素数据,也可以是影响数据变化的关键事件信息.

(转) 网络游戏实时动作同步方案手记

和MMORPG不同,实时动作型网络游戏 追求操作的响应要求极高(<150ms).动作型网络游戏的制作人希望做到单机游戏的体验,网络游戏的服务.    网络指令在多客户端间的同步算法,从原理上来说,围绕两种特性的取舍而定:  * 牺牲局部实时性:某程度的互等待,保证各客户端间指令集在指定时间段一致.  * 牺牲局部一致性:容许客户端本机先行模拟,等待后续指令到达纠正.(DR) 网络的存在导致鱼与熊掌不可兼得,所以现在市面上的动作网络游戏都有如下的妥协和折衷实现:  * 在客户端本机上算大量关键运算