原文地址:http://www.gameres.com/478430.htmlhtml
实时动做游戏在近年来获得迅猛的发展。而游戏同步问题,成为你们继续解决的核心问题之一。早在 2004年,国内游戏开发还处于慢节奏 RPG满天飞的状况下,我就开始实时动做游戏研究。分别在 2005-2006期间写了一系列相关文章,被好多网站转载:算法
帧间同步模式:《帧锁定同步算法》(2007):
http://www.skywind.me/blog/archives/131
玩法规避模式:《网络游戏同步法则》(2005):
http://www.skywind.me/blog/archives/112
预测插值模式:《影子跟随算法》(2007):
http://www.skywind.me/blog/archives/1145
现在十年过去,网上愈来愈多的人开始讨论游戏同步技术了,然而不少文章每每只针对某种特定的游戏状况,而观点又常常以偏概全。不少人并无真正开发过实时动做游戏,更别说了解同步技术的前世此生了。转载别人的观点并加上本身理解的人不少,实际动过手的人不多。避免给更多人形成无谓的误导,我今天基于先前的实践和对欧美动做游戏,战网游戏,主机游戏(PSN,XBox Live等)网络技术的了解,来对这个问题作一个简单总结:
网速的变化
开发快速动做游戏,首先要对公网的网络质量数据有详细的了解。这里所说到的网速,是指 RTT,数据往返一周的毫秒时间,而非每秒传送多少 KB/s。我写这篇文章是基于我 2005-2006年开发的东西来讲的,当时国内公网质量比国外差不少:

上图为 2005-2006年国内的网络环境,某三个省级 IDC的状况采样。当时公网 RTT平均值基本在100ms,120ms左右徘徊。因此我文中引用了不少 100ms。这个状况在2009 年之后已经好了不少(60ms的rtt)。到了2012年之后,公网平均 RTT已经下降到平均 40ms-50ms,省内平均10ms之内了:

上图为 2015年某省级 IDC的全国延迟状况,如若全国多布点以及区别电信联通的话,平均延迟能控制在20ms之内,延迟基本接近国外水平(固然带宽还差不少),比我当年文章中提到的网络状况好了很多。
帧间同步法
关于帧间同步的“
帧锁定算法
”系列的方法有不少相似实现(包括后面提到的帧间无等待改进,包括 LockStep等),可是他们的核心都是一个:
保证全部客户端每帧的输入都同样
。这样的方式被格斗游戏,RTS和足球(FIFA类)、篮球(NBA)等体育和动做游戏大量使用,好比咱们熟悉的各大战网平台游戏(Xbox Live等),还有不少基于模拟器的街机对战平台。以及很多大型多人横版动做游戏。以开发便利,同步逻辑直观而受到你们欢迎。
帧锁定算法多用在 C/S模型中(或者一人作主多人作从的P2P里),它和 LockStep(多用于P2P)共同存在的问题就是 “网速慢的玩家会卡到网速快的玩家”,老式游戏常常一个角色断网,全部人就在那里等待。为此出现了帧锁定的改良版本 “乐观帧锁定”(具体描述见帧锁定文章的下半部分)通过了很多游戏的实践检验。先前还有几款上线的横版格斗页游(如熟知的街机三国)用 Flash 的 TCP without NODELAY 来每秒20个关键帧的模式(特地找该游戏开发者确认了一下)跑该算法(因为近两年国内网速提升,Flash的 Tcp without NODELAY也能作不少事情了),效果还不错。
具体实施时用不着按照文所述每个步奏都相同,能够有不少变通。好比不必定是有变化的时候才通知服务端,有线上某横版格斗页游就是也能够每秒 20次向服务端直接发送数据(flash时钟不许须要本身独立计时),服务端再每秒 40次更新回全部客户端,看具体状况而定。
也有使用 UDP的端游,客户端每秒钟上传50次键盘信息到服务端,丢了就丢了,后面持续发送过来的键盘数据会覆盖前面的数据,因此丢了不要紧,更快捷。固然,UDP也不是必须的,近两年网速提升很快,省内都能作到10ms的 RTT 了,跨省也就 50ms的rtt,很多页游上用该方法上裸的 TCP 照样跑的很顺畅。
而近两年国外动做游戏领域也涌现出其余一些新的改良方法,好比 Time Warp,以客户端先行+逻辑不一致时回滚的方式,带来了更好的同步效果,俗称时间回退法。不果国内暂时没看到有游戏这么尝试,更多的是国外近两年的双人动做游戏比较多,要求游戏每帧状态均可以保存,逻辑上开发会复杂一些。国内大部分是超过两人出去副本的,在3-4人出去 PK的状况下,引入状态回退,会让整个效果大打折扣。不过2人的效果确实有所改进,有兴趣的同窗能够搜索 Time Warp相关的论文。
2009年,云游戏(游戏远程渲染)技术获得普遍应用,客户端上传操做,服务端远程渲染,并以低延迟视频编码流的方式传回给客户端,用的就是这样相似的技术。客户端不须要高额的硬件,也不存在盗版问题,其中 Gaikai和 OnLive两家公司作的比较好。
2012年,Sony推出 Playstation Now技术,能够在 PSV和 PS3/PS4上玩云游戏,玩家不须要购买游戏就能够免费体验必定时间。使得 PSV/PS3等低端硬件也能够流畅的跑 PS4游戏。

可是目前国外网络环境下跑的还比较流畅,国内的网络环境要低延迟传送 HD画质的视频流还比较困难,视频都是比较费带宽的。可是帧锁定等保证每帧输入一致的算法,在当今的网络质量下传递一下玩家操做,仍是没有任何问题的。
状态同步法
对于逻辑不须要精确到帧的游戏类型而言(RPG/ARPG,FPS,赛车),容许每一个客户端屏幕上显示的内容不一样,只要将他们统一到一个逻辑中便可,这部分见:“
网络游戏同步法则
”(最好给策划看看这篇,从玩法上规避)。若是是 RPG游戏,其实更可能是使用障眼法从玩法和动画效果上减小 “一次性的”,“决定性”的事件便可:
RPG 游戏的移动很简单,只须要“谁在哪里朝着哪里移动”,客户端再作一些简单的平滑处理便可,不须要额外的“时间”参数。好比《魔兽世界》移动时,就是差很少每秒发送一次(坐标,朝向,速度),别的客户端收到之后就会矫正一下,若是矫正错误,好比 A原本往北走忽然拐弯向东,这个数据包传到B上,B屏幕上的A可能在拐弯前往北跑了更远,导致拐弯向东时被树卡住,那么B就会看到A被树卡了两秒没法移动,而后忽然瞬间移动到新的坐标,继续朝着东跑。
一般 RPG攻击分为“有锁定攻击”和“无锁定攻击”,有锁定攻击意思是,我朝你发射火球,无论你怎么跑,火球都会追踪并射击到你,好比你在我面前横着跑过,我向你发射火球,能够发现火球并非直线飞行,而是曲线追踪着你就过去了,这叫有锁定攻击。无锁定攻击通常是范围攻击,先播放个动画(好比挥刀),而后将攻击请求提交服务器,服务器结果回来时,动画恰好播放完毕,而后你们一块儿减血。
而 FPS和 赛车类游戏的同步性要求比 RPG高不少,每秒发包量也会多不少(10-30个),多半采用位置预测及坐标差值的“导航推测算法(DR)”,具体实现见个人:“
影子跟随算法
”(DR算法的一个改进实现)。

这类算法因为位置断定更为精确,因此计算量大,不少无法服务端判断,而是客户端直接判断,好比 FPS射击是否打到别人,客户端先判断,除了狙击这种一枪毙命的射击外基本都是客户端判断的。因为计算更为复杂,每秒同步发包差很少到 30个以上,这样的模式下,每局游戏的人数也不可能不少,通常16人左右。并且不少才用 P2P的方式运行,具体 FPS游戏的实现,及 DR算法的代码编写,见 “
影子跟随算法
”这篇文章。
其实状态同步是一种乐观的同步方法,认为你们屏幕上的东西不一样不要紧,只要每次操做的结果相同便可,不须要象“帧间同步”那样保证每帧都同样,所以,对网速的要求也没有 “帧间同步”系列算法那么苛刻,通常100ms-200ms都是可以接受的(DiabloIII里面300ms的延迟照样打),偶尔网络抖一下,出现1秒的延迟,也能掩盖过去。然而比起 “帧间同步”,状态同步方式对玩法有很多要求,诸如 “一次性”,“决定性”的事件要少不少,并且代码编写会复杂一些,不果因为能容忍更坏的网络状况,以及容纳更多同时游戏的人数,在一些玩法肯定的游戏中(RPG,FPS,赛车),被普遍使用。

而状态同步又分为“DR同步”和“非DR同步”,前者针对 FPS,赛车或者更激烈点的 ARPG,后者针对 RPG和普通 ARPG。他们对网速的要求和错误的容忍度也是不同,固然,带来的游戏即时感也是不一样的。
总得来讲,你但愿游戏体验更爽快,即时感更强,那么你每秒发包数就越多,每局(副本)支持的人数越少;而你若是追求对网络的容忍,想下降发包数,而且增长同时游戏的人数,那么相应的就须要以下降即时感为代价,其两者不可得兼。然而聪明的策划和程序们总能想出不少好主意,利用障眼法和玩法规避,动做掩盖等方法,在相同的状况下来掩盖延迟,让玩家“看起来”更加“即时”和“爽快”,而这个方法具体该怎么作,并无统一的作法,就得你们结合本身的游戏和玩法,发挥本身的聪明才智了。
结果同步法
结果同步每每比较简单,位置即便所有错乱或者延迟好久都没有关系,由于游戏过程彻底不在意位置,只在意最后的结果,好比《梦幻西游》这样的“回合制 RPG” 游戏,屏幕上的人走到哪里确实无所谓,全部操做都是要点击或者选择菜单来下命令,象这样的游戏背后实际上是文字游戏,只是加了一个图形的壳。
游戏表面上看起来是动做/RTS 游戏,可是没有玩家直接协做和对抗,都是单机游戏,并不须要同步什么东西,服务端只要监测下结果不离谱便可,延迟检测都不要紧。基本是 PVE,并且无协做。即便是 PVP也就是打一下别人的离线数据,和无同步回合制游戏并没有本质上的区别。
传输协议选择
老话题 TCP仍是 UDP,答案是大部分时候,TCP打开 NODELAY便可,如今网络状况好了不少,不必引入新的复杂度。即使是“帧锁定算法”上线的多人实时格斗游戏,也有在用 TCP跑着的。帧间同步若是可以作到更好的架设机房,那么延迟基本能控制在 10ms之内,将游戏玩家按照区域分服务器,让他们选择更快的服务器。
即使是带 DR的状态同步,不少也都是 TCP的,《魔兽世界》和《暗黑破坏神3》都是基于 TCP来实现的,因此个人建议是,先上 TCP,把你的游戏发布出去。
固然,等到你的游戏发布出去了,开始挣钱了,你想改进你的游戏效果,特别是高峰期的卡顿比例(须要收集客户端统计),那么你可使用 UDP来改进,《街霸4》和《英雄联盟》都是使用 UDP的,好比你可使用 libenet(英雄联盟用的)。不过 libenet所采用的传输技术,是上世纪的标准 ARQ作法了,《街霸4》所采用的传输技术远远高过 libenet,若是你想采用更为现代的传输技术,赢得更低延迟的话,可使用个人“快速传输协议-KCP”(
http://www.skywind.me/blog/archives/1048
),被再若干上线项目和开源项目使用的协议,效果远远 PK libenet。
在使用 KCP时,你能够用在你 TCP的基础上,再登录时服务端返回 UDP端口和密钥,客户端经过 TCP收到之后,向服务端的 UDP端口每隔一秒重复发送包含握手信息,直到服务端返回成功或者失败。服务端经过 UDP传上来的密钥得知该客户端 sockaddr对应的 TCP链接,这样就创建 TCP链接到 UDP链接的映射关系。为了保持链接和 NAT出口映射,客户端通常须要每 60秒就发送一个 UDP心跳,服务端收到后回复客户端,再在这个 UDP链接的基础上增长调用 KCP的逻辑,实现快速可靠传输,这样一套 TCP/UDP两用的传输系统就创建了。
中国的网络状况比较特殊,会存在有些网络 UDP链接不上的状况,所以都是先链接 TCP,而后试图 UDP,UDP不通的状况下,退回 TCP也能正常游戏,一旦 TCP断开,则认为 UDP也断开了。
不果归根结底,仍是先上 TCP,再根据本身游戏的特色和是否出现传输问题,选择 UDP。
话题总结
根据游戏类型,选择恰当的同步方式和传输协议是最基础的问题,不少讲述网络同步的文章通常就是只会强调上述那么多种算法的其中一种方式,好像使用该方式就能够 hold住全部游戏同样的,其实并不是如此。技术须要多和策划沟通,别策划一个需求下来,技术就来一句:没法实现,这样的游戏永远没有竞争力。就像国内当时都是慢节奏 RPG,偶尔有点 ARPG的时候,你们以为《DNF》这样的游戏没法实现,因而韩国实现了,在市场上取得了先机,国内才慢慢跟进,再一看,哇塞,好多坑呢。
而后开发者开始在网上寻找各类同步算法,东一榔头西一棒子,明明是一款须要帧间同步的格斗游戏,结果却上了导航推测,最后发现问题永远解决不了,一堆 BUG这就叫误导。正由于我 2004年就开始弄同步相关的问题,期间也指导过很多游戏设计他们的同步方案,因此此次至关于将之前的观点作一个总结和点评,根据本身的游戏类型选择最适合的同步算法,为玩家提供更好的体验才是关键。