王者荣耀如何实现没有python实现浮点数计算

&腾讯邓君:《王者荣耀》如何从立项惨淡到华丽翻盘
腾讯邓君:《王者荣耀》如何从立项惨淡到华丽翻盘
日12时01分来源:
5月12日下午,在Unite 2017 Shanghai的案例分享专场,腾讯《王者荣耀》项目技术总监邓君分享了题为《王者技术修炼之路》的演讲。邓君讲述了《王者荣耀》从立项之初经历的惨淡时期到华丽的翻盘过程中碰到的技术问题、游戏方向修改,以及《王者荣耀》的技术方案,实际原理、问题和优化的思路。
下文为邓君的演讲全文:
邓君:大家好,我是《王者荣耀》的邓君,很高兴今天能够有这样一个机会跟在座的同行一起聊聊技术,互相交流,也感谢Unity提供这样的机会。
这次的主题主要是讲一下《王者荣耀》从立项之初经历的惨淡时期到华丽的翻盘,这里不管碰到技术方面的问题,还是游戏方向上的改变,我是技术出身的,整个课题也是技术面的,会重点介绍《王者荣耀》和现在见到大部分不同的技术方案,它实际原理、问题和优化的思路。
先简单自我介绍一下,我是2004年加入腾讯,在腾讯做了4年多的应用层面开发,还包括web各种各样后台都做过,经历比较丰富,在2009年我回成都,刚好成都的岗位也就只有游戏部门是比较合适的,就转行做游戏了。在成都这边,参与过一个《QQ封神记》的开发,从封神记出来之后,又开发了一款游戏,这款游戏开发了三年多,游戏从1.0、2.0、3.0,这个时候再转型做手游,直接做的《王者荣耀》。
从立项的惨淡时期到华丽翻盘的《王者荣耀》
我们介绍一下《王者荣耀》,现在了解《王者荣耀》或者在玩《王者荣耀》的人确实比较多,但是我们曾经也没有想过《王者荣耀》有这样的结果。当时端游很久都没有做出来成绩,业绩和收入都面临比较大的问题。霸三国做到1.0之后,要操作多个单位,年的时候,大家觉得特别费操作,要控制很多单位的游戏,操作起来很难,一开始可以操作5支单位然后变成3支,3支完了觉得也很痛苦,这个游戏策略性很强,慢慢把5个单位的技能合在一个身上。你要做创新,你要脱颖而出,是很难的事情。在2014年年底的时候,2015年我们准备开一个手游团队。为什么开手游团队?国内环境里面,基本上都在开发手游,能够继续开发端游或者要准备立项端游的非常少,包括腾讯也就是2、3款端游在开发,端游还是有希望的,开发的团队比较少,手游也是一个机会,希望在2015年把我们的霸三国端游在手游上呈现。这个时候我们进行了一个初期Demo的验证,Demo验证只有三个人,引擎的、框架的、后台的,大概做了两周到三周,把Demo做出来,里面有基本的进游戏、选人,然后可以释放技能,正常的战斗,到结算。但是是用Unity来做的,两、三周做完之后,觉得Unity很好用,开发确实比较高,简单的先这样,2015年才开始进行一个真正的独立招聘20、30人做手游项目,当时是这样的想法。2014年年底的时候,我们制作人去公司开会,当时这是一个非常明智的决策,我们需要马上暂停端游的开发,直接做手游。就是这样的一次决策,真正的是扭转了我们整个团队的命运。如果晚一年,可能今天的游戏就是另外一个,应该不是王者。
我们从端游转型做手游,做手游肯定要面临选择什么样的引擎,采用什么样的方案进行手游的开发。当时的环境,周边包括腾讯还有成都的创业团队,基本上都是Unity,我都不知道,大概在年出来很多游戏都是Unity,我们做Demo的时候,也会选择大家用的,已经有产品进行验证了,同时我们也考察它适不适合我们的团队。Unity对中小团队,包括作为一些大型项目,它有几个比较明显的优势。在两三周你就可以做出Demo,易上手是一个非常大的优势,在座可能都理解。另外,它的工具都是很完善的,能够做到一站式解决,你不需要在这里面下载工具,那里面额外补充一些插件。另外还有它插件资源很丰富,我们从最开始做Demo的时候,基本上都是找一些我们可以用来验证我们想法的,它肯定可以加快我们开发的效率。上面这三点加起来,是它非常明显的优势,开发效率特别高。还有跨平台,那是肯定的,它本是就是跨平台的引擎。还有你能够对人员的补充,非常容易,因为在周边包括社会上招聘都很容易招聘到熟悉Unity的开发人员。我们这边直接对比以前自己做引擎,或者用过其他的引擎,从效率上来讲,我们选择了一个开发效率最高的引擎。这里面回过头来,从端游转换到手游是在2014年底,我们真正开始的时候在2015年3月份就进行开发,这个时候我们开发的周期短,我们需要尽快把手游做上线。我们本身霸三国开发大概有40、50个人,后面把周边的兄弟部门都合并在一起了,里面有一些会Unity、会手游的,还有一部分没有手游开发经验的,组合在一起,形成了100多人的团队,进行了游戏的开发。
还有一个很重要的选择,我们本身是一个网络游戏。当时在年的时候,游戏在pvp上面比较弱,大部分是卡牌游戏、单机游戏,我们本身是一个端游,它的生命力包括趣味性也是很足的,我们做手游的目标,即使我们里面有创关,但是我们里面有最核心的东西,我们要把pvp做好,让玩家有真正的对抗,玩家与玩家有交流,体会到游戏的乐趣。所以在选择pvp,它可能就是一个网络游戏,网络游戏我们选择用什么样的同步机制呢?最常见的应该是cs状态同步,我们端游也是这样做的。后面我们为什么会选择帧同步,后面再说。
状态同步VS帧同步
先看一下状态同步的优缺点,它的安全性非常高,基本上外挂没有什么能力从中收益,基本上都是服务器校验。另外状态同步对于网络的带宽和抖动包有一个更强的适应能力,你有一个输入延迟200、300后面又好了,你其实感受不出来它不太舒服的地方,还有一个状态同步比较好的地方,在开发游戏过程中,比较容易体会到的好处,它的断线重回比较快。如果我的游戏崩溃了,回来之后需要服务器把所有重要对象的状态再同步一次过来,重新再创建出来就可以了。还有一个,它的性能上优化也比较明显,我说的性能优化是客户端的。客户端在做性能优化的时候,它可以做裁剪,我看不到的角色我可以不用创建,也可以不用对它进行运算,这是它的优点。
说完了优点,再说一下我认为的缺点。一个就是开发效率要相对帧同步差一些,很多时候你要从服务器客户端的每一个角色对象的状态之间保持一致,你很难做到它是一致的,包括客户端和服务器端更新的频率,他们对优化的一些裁剪,包括网络的一些抖动,你要让每一个状态在客户端有一个同步,是比较难,你要想调试这些东西,出现的漏洞、不一致的现象,调试周期比较长,想要达到优化好的水平,也是比较难的。另外一个,它比较难做出动作类游戏打击感和精确性。比如说你要做一个人是射击类,他的子弹每秒钟要产生几十颗,基于状态同步是比较难的事情,因为在很短时间会产生很多角色,要通过创建、销毁包括位置和运算。另外还有一个缺点,它的流量会随着游戏的复杂度,角色的多少它会是一个增长的过程。你做手游,也是想追求你在3G、4G也能够玩pvp,对你付费流量的消耗,我们希望能够做到一个比较好的水平,不希望能够打一局游戏需要消耗几十兆的数据流量。
我们再看一下帧同步,大部分人应该还是了解的。最初大家玩的心计、魔兽3都是帧同步,他们是基于局域网,网络非常好,也不需要服务器,他们直接用新型的网络就能够搞定。帧同步的优点是一个开发效率比较高,为什么说开发效率比较高?如果你整体的框架是验证通过,你把它的缺点解决了的话,你完全开发思路就跟写单机一样,你只需要遵从这样的思路,尽量保证性能,该怎么写就怎么写,相对于我们经验来说,以前要在状态同步下面做一个复杂的技能,有很多段位的技能,也许可能要开发好几天,才能有一个稍微过得去的结果,可能在帧同步下面,英雄做多段位技能很可能一天就搞定了。另外它的打击感确实比较强,打击感强除了我们说的各种反馈、特效、音效,还有它的准确性。你游戏里面看到这些挥舞的动作,它能够在比较准确的时刻就能够有反馈,包括它的密度可以做到很高的频率,是状态同步比较难做的。还有一个优点,它的流量消耗是稳定的。大家应该看过心计的录像,它的录像只有几百K,这里面就是网络流量里面全是驱动游戏的输入序列。帧同步只会随着玩家数量,流量才会增长,如果玩家固定的话,流量不管你的游戏有多复杂,你的角色有多少,它基本上都是稳定的。还有帧同步比较好的一点,可以做观战,录像的存储、回放,包括基于录像文件后续的处理都比较容易做。
说了这么多优点,它肯定也有缺点。它的缺点第一个最致命网络要求比较高,如果你的网络稍微有抖动,它是一个锁帧的,如果有这样的抖动,一段时间调用次数是不稳定的,网络命令的延迟会有挤压和舒展。另外一个缺点,它的反外挂能力很弱,帧同步逻辑都在客户端里面,你可以查得到它有没有作弊。游戏的逻辑是在客户端,你可以修改它。为什么王者敢用这样一个东西,当时选型的时候,半年的开发周期需要做出来,要做上线,要有几十个英雄,有时间的压力。另外一个这样一个游戏类型,不像成长类的游戏,它是基于单局的,单局你修改这个东西,顶多影响这一局的胜负,不会存档,你刷多少钱穿比较好的装备,这本身是一个弱成长的游戏,我们认为它不是一个致命的缺点。
你在这上面可以做到收益不明显,你做完之后我们可以发现你有没有作弊,作弊了一样有惩罚。反外挂虽然缺点在,在王者这样游戏类型下面不是特别明显。还有一个缺点,短线重回时间很长,我估计下面有王者非常多的玩家,也碰到过如果你玩着玩着最后闪退你回来有多痛苦,第二个100%等到完成你游戏进去了,游戏也结束了,这个帧同比是比较致命的,每一帧的盐酸最后才能算到正确的状态。还有一个比较大的缺点,它的逻辑性能优化有很大的压力。大家应该没有见到哪一款大型游戏用帧同步来做的,每一个逻辑对象都是需要在客户端进行运算。如果你做一个主城,主城里面有上千人,上千人角色虽然看不到它,但是你需要对它进行有效的逻辑运算,这就是它无法做非常多的游戏对象需要更新的游戏场景,这是它的缺点。
为什么《王者荣耀》选择了帧同步而放弃了状态同步
前面提到它两个优点缺点是相对的,这边的优点对于那边来说就是缺点。对于我们手游立项的时候,最重要就是时间。当时市面上正在开发的包括腾讯内部的都不止王者一款在开发,大家都在争取上线的时间,我们可能会选择一个开发时间周期最短的方案。然后我们做端游也有一个深刻的体会,做有趣的英雄,有趣的技能,它在状态同步上面很难调出一个比较满意的效果。它的优点包括我们自己对于状态同步的体会上面,最后我们依然选择帧同步的方案。选择帧同步方案,确实现在回过头来讲,我们把缺点优化掉规避掉,它带来的好处是比较明显的。我们的游戏比较好玩,除了英雄的设计包括整个技能的感觉,还有很重要的一点,它确实在做一些非常有特色的英雄,它的技能、反馈、体验上面都是做的不错,这是基于帧同步技术方案的优势。
我们选择了方案之后,当时觉得很hi,觉得这样一个技术方案开发起来得心应手,效率如此之高,做出来的效果也很好。但是它也有好的一面,也有坏的一面,技术测试版本上线后质量不好,其中技术层面应该就是这上面的三座大山。第一个同步性,同步性这块容易解决,其实也解决了;最大一个问题是网络问题,帧同步它的网络问题导致我们对它技术方案的原理没有吃透,碰到了一些问题,那时候游戏感觉延迟很重,画面卡顿,你明显感觉走路抖动的现象;第三性能问题始终存在,也一直在优化。
第一难关:同步
先看一下第一座大山,最容易解决的,说一下帧同步的技术原理,相当简单,10、20年前就有了,它要一个相同初始的状态,后面你需要有一个相同的输入,我往下一帧执行,执行的时候我所有代码的流程,大家走的是一样的,有了相同输入之后,输入包括第一帧、第二帧、第三帧,有了输入然后要执行相同流程,大家走的一模一样,这个结果调用完了以后,又有一个新状态,下一个状态大家又有一样,完成了循环,相同的状态,相同的流程,不停的这样循环下去。这个原理虽然简单,但是你要去实现它的时候,还是会有很多坑。
右边写的是实现要点,这是我们在解决第一座大山经验的总结,也是我们实际开发过程当中做的事情。
我们所有的运算都是基于整数,没有浮点数。浮点数是用分子分母表达的。我们可能还会用到第三方的组件,帧组件也要需要进行一个比较严格的甄别。我们本身用的公司里面关于时间轴的编辑器里面,最初也是是浮点数,我们都是进行重写改造的。你初次接触帧同步里面出问题,就是写逻辑的时候和本地相关、和我相关,这样就导致走到不同分支,真正客户端跟逻辑的话,要跟我这样一个概念无关。还有随机数,这个要严格一致。这是实现的要点,严格按照这上面的规则写代码还是有可能不同步,本身就很难杜绝这样的问题。真正一个比较重要的是提升发现不同步的能力,什么时候不同步了,不同步你还要知道不同步在什么点,这是最关键的。你需要通过你的经验和总结提升这样的能力。这个能力还是通过输出来看不同客户端不同输概率比较低,我说了不同步,在座有没有碰到不同步,王者的不同步是什么样的?我们看到不同步的现象应该是这样,有人对着墙跑,你看到就是你和别人玩的游戏是不一样的,进入平行世界。本身这一块,最开始上的时候,希望不同步率达到1%,就是100局里面有1局出现不同步,我们就算游戏合格,其实对于这么大一个体量游戏来说是有问题的,经过我们不停的努力,现在是在万分之几。一万局游戏里面,可能有几局是不同步的。这个问题不一定是代码原因或者没有遵循这些要点写出来的,包括你去修改内存,包括你去加载资源的时候,本地资源有损害或者缺失,或者是异常。异常说白了,你没有办法往下执行,大家走了不同分支,这都可能引起最终是不同步的。如果你不同步概率比较低,这种万分之几概率的时候,很难通过测试来去还原,去找到这样不同步的点。
最开始我们游戏出现不同步的时候,就是周末,随着你的概率越来越低,基本上你就自己还原不出来了,只能依靠玩家帮你还原这样的场景,来分析这样的不同步。
同步性遵循这样的要点,按照这样的思路来写,加上你不同步定位的能力,有了监控手段能够去发现,这个问题其实就解决了。解决之后,你就可以好好享受帧同步的开发优势。
第二难关:网络
我们再看一下第二座大山就是网络,技术测试版本出台的时候,延迟非常大,而且还是卡顿,现在看一下帧同步里面比较特别的地方。帧同步有点像在看电影,它传统的帧同步需要有buffer,每个玩家输入会转发给所有客户端,互相会有编号,第几帧,第几帧的输入,假如说我现在收到第N帧,如果我收到第N+1帧的话,N帧这一帧我是可以执行的,是这样一个情况。服务器会按照一定的频率,不同的给大家同步帧编号,包括这一帧的输入带给客户端,如果带一帧给你的数据你拿到之后就执行,下一帧数据没来就不能执行,它的结果有可能你网络非常稳定,绝对理想值的情况下还好,现实网络不是这样的。帧同步要解决问题就是有buffer,以前有动态的buffer,它有1到n这样的缓冲区,根据网络抖动的情况,收入然后放到队列里面。这个buffer的大小,会影响到这两个东西,一个就是延迟还有卡顿。如果你的buffer越小,你的延迟就越低,你拿到以后你不需要缓冲等待,马上就可以执行。但是如果下一帧没来,buffer很小,你就不能执行,最终导致的结果你的延迟还好,但是卡顿很明显。你会调到帧同步的buffer,假如我们认为网络延迟是1秒,你抖动调到1秒,那得到的结果虽然你画面不抖动了,但是你的延迟极其高。最坏的网络情况都考虑进去,buffer足够大,跟看视频是一样的,平行的东西,看你调大条小。一些局部的措施我们都做过,都是一样的问题。?
我们怎么优化卡顿这方面呢?本身刚才也提到了,它应该帧同步有buffer,这个buffer可以是1也可以到n,我们要解决我们的延迟问题,我们就让buffer足够小,最后我们做到buffer是零,它不需要buffer,服务器给了我n,马上知道是n,我收到n,我知道下一次肯定是n+1,所以我收到n之后马上就把这一帧的输入执行了,下一步可能就涉及到了为什么不卡顿了,画面不抖动了,是最后一条,是本地插值平滑加逻辑与表现分离。客户端只负责一些模型、动画、它的位置,它会根据绑定的逻辑对象状态、速度、方向来进行一个插值,这样可以做到我们的逻辑帧率和渲染帧率不一样,但是做了插值平滑和逻辑表现分离,画面不抖了,延迟感也是很好的。做了这些,我们还做了TCP换成UDP,在手机下面,弱网的情况下,TCP很难恢复,UDP本身作为游戏也有优势,之前还用过其他的,没有优化到最后,不是很理想,最后用了UDP来做。整体来说,在网络好的情况下,它延迟也是很好的,在网络比较差的情况下,做插值,网络情况差的话,也是传统cs的表现,我们经常见到角色A和B,有些客户端A在左B在右,有些是A在右B在左,帧同步逻辑上面AB之间的距离和坐标都是完全一样,但是画面上看到他们可能会不重合,那就是你把它们分离之后的表现。网络极其好的情况下,它应该是重合的,但是在网络差的情况下,可能会有些偏差。这里面是最重要的一块优化。
第三大难关:性能优化
下面是我们对性能优化,本身帧同步逻辑上面在优化上面存在一些缺点,所有的角色都需要进行运算。这里面还是用的Unity,里面也有很好的特性,如果你想追求性能上的极致,有些东西你需要寻求好的方式。比如讲热点的处理,我们是不用反射的,它都有GC性能开销,你可能经常会隐藏或者把它显示出来,我们的做法里面,把对象的显示隐藏放在不同的渲染层里面,尽量让整个游戏帧率是平滑的过程。还有我们本身有自己的系统,还有AI,这样的一个游戏类型里面的角色比较多,你如果想要做比较好,它的AI是比较复杂的。要去优化热点,我觉得就只有这三个步骤可以走。
从程序的结构上面能找到更优的,它的效果是最明显的,如果你的结构都是用的最好,就在挖掘局部的算法,调整你代码的一些写法。如果局部的算法都已经调到最优还是没有什么办法,那只有一条路,就是牺牲整个质量,就是分帧降频。GC这块刚才说不用反射,还有装箱和拆箱的行为也是尽量少用。Unity指导过我们的优化,从GC上面的考虑,他们建议每一帧应该在200个字节以内是比较好的状态,其实很难做到,王者也是每一帧在1k左右,很难做到200。还有Drawcall,这些传统的优化手段大家都用的很熟了。还有裁剪,帧同步里面是不能裁剪的,表现里面我看不到的可以降低频率或者不更新它,这在表现里面可以做的。还有我们的血条、小地图上面叠的元素比较多,比较丰富,这块我们用了31UI的方式来优化,没有用UGUI里面进行血条方面的处理。我们也牺牲了一些东西,我们把所有东西都加载了,在游戏过程当中,我们希望不要有任何IO行为,包括输出我们都是要布局的。你处理的决策和复杂度,如果在一帧里面放出100颗子弹,在放100颗子弹的时候一定要掉帧的,一定要在力所能及的时候把这些东西做到极致。
前面提的是第一代,去年5月份以前做的优化方案。5月份的时候我们还做了另外一件事情,为什么觉得IOS比安卓高一些,本身一个是IOS的CPU架构包括系统确实都优化的比较好,另外我们用的Unity4.6,在IOS下面它本身效率高一些,在安卓端的机器各种各样,性能也是千差万别,我们只能用性能比较差的方式。因为本身已经做到逻辑和表现是分离的,我们能不能把逻辑独立出来,做成一个C++的东西,我们在去年开始这样做了。做之前也测试过C++和Mono性能的差别,大概是2.5左右,本身我们的逻辑占比游戏消耗20%多,逻辑不是一个大头,我们做了这件事情之后,还是有效的,帧率提升了2到3帧,花的时间很长。整个时间大部分都消耗在了引擎和CPU的交互、调度,不是我们做GameCore就没有意义,做了这块我们有很显著我们以前逻辑上的GC没有了,我们有自己内存的管理、对象的管理,包括里面所有的容器类这些东西都是我们自己实现的,包括反射整个一套。它有了自己的内存管理,它本身效率就比较高,其实还是一个比较明显的优势,有了GameCore之后,有很多应用场景,这个东西就是玩法的服务器版本,应用场景运行服务器要做很多的分析,还有第三方使用都是可以的。GameCore可以做成一个多线程的话。
前方的路:将在热更新上寻找突破
我们接下来看一下我们后面可能打算考虑的一些事情,一个就是我们想能不能在热更新上面有所突破。因为王者这样一个游戏类型,包括它的体量,我们对于性能有一个比较极致的追求,不会轻易使用脚本层面在性能层面本身就不是最好的。这个我们要去研究的就是热更新,性能最好的方式。另外的话,包括硬件厂商也沟通,他们其实也是希望游戏能够真正发挥多核性能上的优势,大部分的游戏在单核上面,把一个核吃的满满的,很多时候我们现在得出的结论,GPU性能也很强,王者并没有对GPU占满,可能只用了30%,CPU反而吃的比较满,吃满以后它还有另外一个坏处,它的发热、降频,你如果用多线程、多核去尽量平坦,让它不要处于高频的工作方式,反而会有更好的效果。我们现在用Unity4.6,Unity进化到5.7,后面他们还会推出新的特性,我们希望结合一些Unity新特性,现在已经有些游戏用5.6可以提升性能。不光是提升性能问题,Unity在多线程的渲染,也有很好的作用,使用引擎优势也是很必要的。随着性能的提升,我们会对王者的画质进行提升。
行业爆料:猫与海(微信号 catandsea)
商务合作/采访/投稿:文静(微信号 mutou_kiki)
投稿邮箱:
—— 推荐 ——后使用快捷导航没有帐号?
 论坛入口:
  |   |    |   | 
我要游戏程序
查看: 23109|回复: 1
《王者荣耀》技术总监:技术架构与同步方案上做出改变?
iOS&Android&
《王者荣耀》能够成为如今国内最成功的手游,其后方成熟的技术团队可以说是功不可没。这个曾经在端游时代主导搭建RTS游戏《霸三国》框架的技术团队,在转型做MOBA手游《王者荣耀》后为游戏提供了巨大的支持。但这个过程也并非一帆风顺。
在今年刚结束的腾讯TGDC上,《王者荣耀》技术总监孙勋在技术专场中,对这款游戏进行了一次技术复盘,为听众嘉宾就从技术层面上讲解了游戏在引擎、整体网络架构与网络同步方案上的尝试与转变。
1.webp.jpg (76.49 KB, 下载次数: 6)
23:57 上传
孙勋称,目前游戏的服务器架构主要由“游戏大厅”和“PvP”2个部分组成,而在不断探索中,其后来又在架构中加入了Proxy中转服务器,也正是这个服务器的加入为《王者荣耀》解决了后来“安卓、iOS”同服等一系列出现的问题。
此外,他还介绍了《王者荣耀》在网络协议以及同步方案上的一些尝试,并一一复盘了这些尝试的优劣势,并解答了为什么,最终游戏会放弃TCP协议(传输控制协议)与曾经在《霸三国》中所使用的CLIENT-SERVER结构(C/S结构),并且转而使用了UDP协议(用户数据报协议)与帧同步同步方案。
以下为会议速记整理:
大家好,今天由我带来《王者荣耀》后台技术上面的分享。
我叫孙勋,是一名后台开发程序员。2005年加入腾讯,最开始不是做游戏,2007年前一直做拍拍网,2007年加入成都卧龙工作室,也就是现在的天美L1工作室。之前参与过《QQ三国》、《封神记》、《霸三国OL》,到后来的《王者荣耀》,现在是这款游戏的技术总监。
今天分几部分和大家介绍王者后台开发过程中的一些内容和思考:包括《王者荣耀》整个背景介绍、后端架构、上线后的调整,以及网络同步方案和反作弊方案等。
现在《王者荣耀》后端机器大概有4600多台,我们的容量也有一定的扩展,进程数目是4万多个。
《王者荣耀》游戏背景
2012年,我们当时做的端游《霸三国OL》,就是王者的前身。这款产品最开始是偏向RTS的游戏,后来我们把它改成了端游MOBA,再后来做成了手游MOBA,即现在的《王者荣耀》。从2012年开始做RTS游戏到2013年,从多控制单位的RTS游戏,变成MOBA游戏,到2014年启动手游MOBA的预研,再到2015年2月份我们把大量人力(大概100多号人)投入做《英雄战迹》(《王者荣耀》前身)开发,时间并不长。
《霸三国》的玩法是玩家可以在战前通过排兵布阵构成自己局内的策略,通过控制多个单位,技能释放、兵种特性的释放形成对抗。我们最开始做《霸三国》的时候客户端引擎是unreal,但在做《王者荣耀》的时候改用了unity引擎,3到4个月的研发时间内,产品本身从代码层面没有任何东西是从《霸三国》那里搬过来用的,全部代码都需要重写。
《霸三国OL》的一些启示
做端游《霸三国OL》的这段经历,给我们做王者带来很多相应的启示,比如策划、程序及整个团队对MOBA的理解。另外当时在做端游《霸三国》的时候,我们采用了CLIENT-SERVER的模式,但其实在过程中有借鉴类似帧同步的概念:例如在断线重回对视野的处理这块。
传统的做法是,重回时会发当前的镜像和后续的其他下行通知信息。这种做法会有一个问题,如果新增其他的场景内模块的时候,根据场景内包含的当前的各种物件、所在状态的各种各样信息,都需要把这些东西打包发下去,在后续开发、维护的时候会显得很麻烦。
我们的做法是,把服务器下发的所有序列包做缓存,并按顺序重发,让客户端做出快进的表现,它的概念和帧同步比较类似。还有一点,就是预留设计弹性,在最开始的RTS中,每个玩家最多可以操作5-8个单位进行对抗,到后来改成MOBA游戏,只能操作一个英雄,并且加入各种各样的场景,我们本身的技术框架并不需要做出颠覆性的改动。
3.webp.jpg (9.4 KB, 下载次数: 12)
23:57 上传
《王者荣耀》目前后台的整体架构设计是源自产品的需求。如果大家玩过《王者荣耀》就会知道,PvP对抗是不分区服的。微信1区的玩家可以和微信2区玩家一起对抗,甚至iOS平台也可以和Android平台的人一起玩,但同时一些共地方也保留了分区概念,比如战队、排行榜是基于“区”概念的。“区”在游戏里面就是编号,可以理解为打在玩家新建角色上的Logo。
我们最开始做架构实现的时候,服务器当时做得比较简单,从原型开始只是保留了大厅和PvP服务器这两块,两者是分开的。PvP服务器使用类似CGI调用,可以分配资源的使用,用完之后再回收,不负责其他的东西。需要的东西从大厅拿,用了之后回给大厅,让大厅回写DB。
我们在大厅和PvP之间做直联,后来把直联改成了中间转发,在《王者荣耀》里面我们叫Proxy,相当于代理服务器,以屏蔽本身后端很多进程分布的细节。因为游戏本身的机器、进程很多,还有不同的路由规则。
某些排行榜或者战队是根据逻辑区的编号来确定哪台机器,或者多台机器进行处理的。有些消息采用随机转发或者多发广播的方式,这些都是由Proxy负责路由。之后又加入了房间服务器,它负责的是《王者荣耀》内匹配、排位等相关功能,怎么样把实力比较接近的人糅合到一块儿玩,是由房间匹配服务器来做相应的负责的,因此会有战队和其他服务器战队匹配到一起。
最后我们在上面加入了一个Adapter,作用是用本身已经部署的大区资源实现跨服匹配的功能。游戏的后端架构,除了战队这样的服务器之外,所有其他的模块都可以在线扩容,或者在发现引起在线下降的故障时,从整个架构里自动屏蔽掉。因为路由方式会限定比如一区、二区、三区到这台机器处理,如果故障,影响的只是某几个逻辑区玩家请求的处理,降低故障影响范围。
4.webp.jpg (15.87 KB, 下载次数: 3)
23:57 上传
《王者荣耀》目前的机器数量,可能每周都会发现有机器坏掉,至少有一台机器宕掉,在架构里面保证模块自动屏蔽,和在线扩容,是非常重要的事情。整体结构比较像MMO的三层结构,MMO在腾讯有比较典型的三层级别结构。大厅服务器会根据玩家所在区,登录具体区的大厅服务器。单个大厅进程可以承载2万人,单个PvP可以承载1.2万,小区登录微信一区还是二区就是角色Logo,打在玩家身上。
《王者荣耀》现在外网有四个大区,比如Android手Q、Android微信、iOS手Q、iOS微信,此外还有抢先服。我们会用程序开关的方式,在大版本发布之前,优先更新抢先服,这时候它不能和正式服玩家匹配在一起,因为他们的版本不一致。当全服发布之后,它的版本更新一致之后,我们会打开开关,抢先服的玩家可以和正式服的玩家一起进行PvP的匹配。
除此之外,我们还有专门的体验服,是给策划验证相关设计的,体验服保留可能删档的操作,但在正式环境这是绝对不允许的。另外,以前的传统手游偏单机,就会做很多协议兼容,客户端版本没有更新可以玩。但是《王者荣耀》里的主要玩法是PvP,同时结合实现方式,不同版本的玩家不能匹配一起,所以我们没有做多版本协议兼容。
5.webp.jpg (28.12 KB, 下载次数: 9)
23:57 上传
上线后的调整
上线后,《王者荣耀》本身的后台架构,整体上没有做太大的改动,因为我们做端游的时候,对这套结构比较清楚,我们知道哪个地方可能有什么样的问题,所以整个结构一直比较稳定。
但是我们做了相应的微调,做得最多的是网络本身的优化。《王者荣耀》上线的时候,市面上要求网络及时性强的即时PvP游戏是比较少的。我们做了各种各样的尝试,比如在网络做CPU方面的性能优化、延迟、丢包等等,网络本身花的时间是最多的。
架构上的微调,像刚才提到的中转模块,我们架构中大厅机器很多,PvP机器很多,架构中不需要每个进程知道详细信息,比如大厅服务器不需要知道后面有多少房间服务器,只需要知道后面有房间服务器,可以访问就OK。
怎么划分、平衡负载、怎么屏蔽后端故障节点,都是由Proxy路由功能在负责。因为大厅、PvP机器太多,我们通过Proxy将整个架构划分成彼此之间没有交集的“树枝”概念,每组Proxy只负责一部分的大厅和PvP服务器。这两种服务器在《王者荣耀》服务器里面最多,但是后端通联之外,Proxy之间再建立连接,减少单个Proxy通道数的同时,保持整个结构的通联。
ProxyAdapter是上线后加入的,最开始上线只有四个大区,手Q、微信、Android、iOS四个环境,最早Android的玩家也不能和iOS开黑。开始Android和iOS分开也有一定原因,我们之前设想Android会先更新,iOS后跟新,以保持版本更新的稳定性。但后来我们希望Android和iOS的玩家可以因为关系链一起开黑。
所以当Android、iOS版本更新频率一致时,我们希望不需要部署太多额外的机器资源和开发,直接利用Android和iOS已有的PvP服务器和大区资源,打通Android和iOS的PvP。当Android玩家登录Android大区会连接到Android大厅,iOS登录之后连接iOS大区的大厅,当他们需要开黑的时候,我们通过Adapter把中转模块所有的大区桥接起来,通过一定的算法投递到某个大区。投递的选择和大区资源占比有直接关系。
网络同步方案
6.webp.jpg (12.58 KB, 下载次数: 6)
23:57 上传
之前做《霸三国》的时候采用CLIENT-SERVER的模式,服务器判定客户端表现,那为什么我们在做《王者荣耀》的时候选用帧同步的方式呢?
CLIENT-SERVER模式的好处在于:
首先,安全。因为都是服务器计算,客户端只是负责表现层面的功能,不会影响各种判定的结果。
另外,CLIENT-SERVER模式因为是基于结果的表现,所以中间可以出现丢包,丢包是可以被接受和处理的,只要最终结果补发一致即可。
帧同步在端游用得比较多,大家比较熟悉的DotA,还有《星际争霸》,都是用的帧同步技术。帧同步本身对网络要求更加严苛,下发的执行序列是不允许丢包的,需要严格保证顺序性,包是12345,就必须是12345,如果丢包,必须要等到丢的包到达之后才能顺序后续执行。
MOBA本身的单位比较多,同屏时客户端最多有将近100个单位,假如一个AOE技能打到20个单位,然后种了一个debuff,CLIENT-SERVER状态模式需要发这些信息下去,可能潜在的同步状态信息是比较多的。
另外一个CLIENT-SERVER模式本身开发的方式,客户端表现与服务器的判定,要完美的匹配是比较困难的。
我们之前做端游MOBA的时候,一个英雄技能我们开发要两三周的时间。《王者荣耀》当时开发周期是三、四个月,这样的时间压力下,我们用CLIENT-SERVER的方式搞不定,时间不够。当时团队心里会比较紧张,因为那时候市面上并没有看到用这种方式做强PvP、高及时性手游的。
帧同步网络抗抖动能力比较弱,因为不能丢包。帧同步的基本原理,大家有兴趣可以下来自己了解一下。一般会有区分,是网络还是主机模式。该技术的要点在于局内的运算都是基于客户端运算,10个人中,每个人都会各自算一份,有相同的起始、相同的输入、完全相同的中间运算逻辑,不存在随机过程,这时候运算的结果,理论上应该是一致的。
甚至包括浮点数运算都不应该存在,它有精度的问题。包括很多碰撞,动画,还有基本的数学运算库都是后台自己实现的,要去浮点整形化,避免客户端的本地逻辑,这是最容易犯的错误,这是出现不同步最常见的原因。如果某个经验不是很足的客户端程序,写程序时候用本地的代码做相应的逻辑,可能跑得越来越远,10个人都是平行的世界。
整体的网络结构,大体看来分三层:服务器、客户端逻辑层,客户端表现层。
服务器主要负责的功能有两部分:一是收集所有玩家上行的输入,把它按定时的间隔打包成输入的序列,投放给所有客户端;二是当客户端出现丢包的时候,服务器进行补发;还有把客户端上行冗余的信息替换掉,比如有新的输入到了,就把老的输入Drop或者替换掉。在《王者荣耀》里,我们的逻辑是66毫秒一次,1秒同步15个包,这是不能少的,因为帧同步不能丢包,数据包必须有严格的执行序列。
客户端逻辑层理解为客户端本地的服务,就是所有客户端运行的结果必须强一致,不能有真的随机、不能有本地逻辑、不能有浮点数运算。拿到相同的输入,产生结果必须一致。
客户端表现层会根据逻辑层的数据去做Copy或者镜像,然后在表现层进行平滑,帧数不一样,但是不会影响最终的运算结果,只影响动画和动作的表现。
PvP最开始上线时,我们用的是TCP技术。TCP在局域网的情况下表现还是不错的,没有什么问题,但是当外网出现丢包或者抖动的时候,受限于实现方式,比如窗口、慢启动各方面的原因,会发现当出现重连的时候游戏非常卡,所以后来我们没有用TCP,改为了采用UDP。如果出现丢包,服务器会在应用层做补发。UDP受限于MTU(最大传输单元)的大小,大于MTU,会出现分包,可能也会出现整包的丢失。
所以我们也会有些比较大的包会在App层由服务器做分包,中间出现丢包再由服务器补发,把零碎的包拼成整包再做解包。比较有价值的是UDP包,如果手机因为信号抖动等出现丢包,下发的时候通过冗余方式,是比较有效的解决方法。
帧同步的消息比较小,按照理论1秒15个驱动帧来算,20分钟的录像是10M左右。但是我们外网统计,正常的5V5对局20分钟,录像的大小大概是3M左右。服务器会把玩家的操作做纯内存的存储,当出现丢包的时候,服务器会通过编号快速找到缓存信息进行下发。同时根据丢包的情况,我们会计算给这个人发送冗余量的变化量。
最开始发送每个包会冗余前面3帧的信息,如果丢包严重,我们会尝试冗余更多信息再下发。客户端拿到之后会尽量压缩逻辑执行的过程。帧同步有比较麻烦的模式在于,它不像CLIENT-SERVER的模式随进随出,崩溃之后重回必须从一开始运行,中间运算过程不能少掉。
当然,我们也尝试过其他的一些方法。比如客户端上行之后,不需要服务器定时的间隔去做收集然后下发,而是通过染色帧编号直接下发,这样响应更及时,操作反馈更强、更快。当时我们做出来的结果是,这对手感的提升微乎其微,但是带来的负面问题却很大,因为不再是一秒15个包固定的下发,下发包的数量非常多,完全和这个人的操作习惯有关系,有可能一个人一秒之内产生了十几二十个输入,就需要把这些输入打包之后对客户端下发。客户端因为收包很多,设备也会明显发烫。
我们也有和其他部门合作,做类似于TCP的技术,大家直观想到如果丢包就在io层做重发。但是实际的结果会发现,做的这个技术偏底层,所以对丢包的控制性不那么灵活,而且可能出来的结果还没有tcp本身好。
传统的帧同步的方式会做延迟投递,这个我们也有尝试过。如果间隔时间内出现丢包,或者出现包下行的时网络波动,可以通过延迟投递这种方式抹平抖动和丢包的情况。我们尝试过这个方案但最终没有这样做的原因在于:《王者荣耀》里面一些英雄体验起来感觉偏动作,对反应要求比较快,延迟投递虽然抗抖动和抗丢包的能力确实不错,但是手感上达不到我们的要求。
另外,做CLIENT-SERVER方式的实现,一般都会有一个套路,客户端提前表现,根据服务器的表现做平滑或者拉扯。这个方案我们也尝试过,但最终还是放弃了,因为这个技术会让角色本身的表现有点发飘。客户端本地动,马上客户端表现就跟着动,但根据服务器的下行,其实会做一些偏移或者修正。当网络抖动出现的时候,角色会有一点发飘,所以这个方案我们放弃掉了。
帧同步方案,所有客户端进行运算,期望产生一致的结果,但如果因为bug或者某个人使用修改器,跑出来的结果会和其他人不一样,当不一样出现,我们的说法是不同步了。我们会定时把一些关键信息提取出来做hash,不同步的人的hash和其他人会不一样。《王者荣耀》不同步率上线时大概是2%,也就是100局可能有2局出现一个人或者多个人结果和其他人不一样。我们现在把不同步率做到了万分之三,一万局里面只有三局出现这个情况。
这是怎么提升的呢?如果你用帧同步一定会遇到不同步的问题,客户端写错了,用了本地逻辑,可能浮点数的运算误差达到那样的临界点,它就会产生运算结果不一致。
我们的方法有很多:自动化测试,用机器人不断跑,比如上新英雄之前,有脚本测试不断跑,看会不会产生不同步的结果;有专门的体验服、抢先服大区,发布到正式网络之前先测试,先暴露问题,再解决问题;另外,当不同步的时候,我们会把这局整个录像和客户端间的log上传和保存下来,这样可以根据录像和中间执行的日志序列快速的定位是哪个地方出现问题。
我们对延迟和单局质量也有相应的监控,这一局有没有卡或者卡多少次,有没有出现丢包,丢包多少,最大的延迟、最大的抖动是多少,我们都是有相应的记录和统计。运营部的同学给我们提供了很多帮助,我们会有相关的网络测速、问题分析的SDK的合入。
按照我们自己的统计,游戏卡顿主要的原因有几个:一是小区的带宽比较繁忙,很多小区其实都是公用带宽出口,比如有人在下电影、看直播,占用了很高带宽,你玩游戏就可能会卡。
二是Wi-Fi路由器延迟比较高,家里的Wi-Fi路由器长期没有重启,就会存在终端过多、信道干扰、其他大流量的应用下载情况,这也会影响你玩《王者荣耀》。还有手机信号差、信号抖动,Wi-Fi、4G空口丢包等。
我们其实在网络优化上做了很多的尝试,例如根据丢包情况加大冗余,然后优化我们各方面执行的效率,去减少CPU的占用。《王者荣耀》后台方面,有两个点是我们一直努力在做的,网络优化和匹配机制,我们尝试用各种各样的方法,甚至后面也会尝试用AI深度学习的方法,来更加精准的定位玩家本身的真实水平,让他能够匹配到更加真实的同等水平的对手和队友。
游戏葡萄整理
干货,mark}

我要回帖

更多关于 如何用电脑玩王者荣耀 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信