今天在其他地方看到

Alan : 今天在其他地方看到的,可能做手游的朋友有兴趣,就 搬运进来了。主要“王者荣耀”如何崛起。

5月12日下午,在Unite 2017 Shanghai的案例分享专场,腾讯

《王者荣耀》项目技术总监邓君分享了题为《王者技术修炼 之路》的演讲。邓君讲述了《王者荣耀》从立项之初经历的 惨淡时期到华丽的翻盘过程中碰到的技术问题、游戏方向修 改,以及《王者荣耀》的技术方案,实际原理、问题和优化 的思路。

下文为邓君的演讲全文:

邓君:大家好,我是《王者荣耀》的邓君,很高兴今天能够 有这样一个机会跟在座的同行一起聊聊技术,互相交流,也 感谢Unity提供这样的机会。

这次的主题主要是讲一下《王者荣耀》从立项之初经历的惨 淡时期到华丽的翻盘,这里不管碰到技术方面的问题,还是 游戏方向上的改变,我是技术出身的,整个课题也是技术面 的,会重点介绍《王者荣耀》和现在见到大部分不同的技术 方案,它实际原理、问题和优化的思路。

先简单自我介绍一下,我是2004年加入腾讯,在腾讯做了4年 多的应用层面开发,还包括web各种各样后台都做过,经历比 较丰富,在2009年我回成都,刚好成都的岗位也就只有游戏

部门是比较合适的,就转行做游戏了。在成都这边,参与过 一个《QQ封神记》的开发,从封神记出来之后,又开发了一 款游戏,这款游戏开发了三年多,游戏从1.0、2.0、3.0,这个 时候再转型做手游,直接做的《王者荣耀》。

从立项的惨淡时期到华丽翻盘的《王者荣耀》

我们介绍一下《王者荣耀》,现在了解《王者荣耀》或者在 玩《王者荣耀》的人确实比较多,但是我们曾经也没有想过

《王者荣耀》有这样的结果。当时端游很久都没有做出来成 绩,业绩和收入都面临比较大的问题。霸三国做到1.0之后, 要操作多个单位,2012、2011年的时候,大家觉得特别费操 作,要控制很多单位的游戏,操作起来很难,一开始可以操 作5支单位然后变成3支,3支完了觉得也很痛苦,这个游戏策 略性很强,慢慢把5个单位的技能合在一个身上。你要做创 新,你要脱颖而出,是很难的事情。在2014年年底的时 候,2015年我们准备开一个手游团队。为什么开手游团队? 国内环境里面,基本上都在开发手游,能够继续开发端游或 者要准备立项端游的非常少,包括腾讯也就是2、3款端游在 开发,端游还是有希望的,开发的团队比较少,手游也是一 个机会,希望在2015年把我们的霸三国端游在手游上呈现。 这个时候我们进行了一个初期Demo的验证,Demo验证只有 三个人,引擎的、框架的、后台的,大概做了两周到三周, 把Demo做出来,里面有基本的进游戏、选人,然后可以释放 技能,正常的战斗,到结算。但是是用Unity来做的,两、三 周做完之后,觉得Unity很好用,开发确实比较高,简单的先 这样,2015年才开始进行一个真正的独立招聘20、30人做手 游项目,当时是这样的想法。2014年年底的时候,我们制作 人去公司开会,当时这是一个非常明智的决策,我们需要马 上暂停端游的开发,直接做手游。就是这样的一次决策,真 正的是扭转了我们整个团队的命运。如果晚一年,可能今天 的游戏就是另外一个,应该不是王者。

我们从端游转型做手游,做手游肯定要面临选择什么样的引 擎,采用什么样的方案进行手游的开发。当时的环境,周边 包括腾讯还有成都的创业团队,基本上都是Unity,我都不知 道,大概在2013、2014年出来很多游戏都是Unity,我们做 Demo的时候,也会选择大家用的,已经有产品进行验证了, 同时我们也考察它适不适合我们的团队。Unity对中小团队, 包括作为一些大型项目,它有几个比较明显的优势。在两三 周你就可以做出Demo,易上手是一个非常大的优势,在座可 能都理解。另外,它的工具都是很完善的,能够做到一站式 解决,你不需要在这里面下载工具,那里面额外补充一些插 件。另外还有它插件资源很丰富,我们从最开始做Demo的时 候,基本上都是找一些我们可以用来验证我们想法的,它肯 定可以加快我们开发的效率。上面这三点加起来,是它非常 明显的优势,开发效率特别高。还有跨平台,那是肯定的, 它本是就是跨平台的引擎。还有你能够对人员的补充,非常 容易,因为在周边包括社会上招聘都很容易招聘到熟悉Unity 的开发人员。我们这边直接对比以前自己做引擎,或者用过 其他的引擎,从效率上来讲,我们选择了一个开发效率最高 的引擎。这里面回过头来,从端游转换到手游是在2014年 底,我们真正开始的时候在2015年3月份就进行开发,这个时 候我们开发的周期短,我们需要尽快把手游做上线。我们本 身霸三国开发大概有40、50个人,后面把周边的兄弟部门都 合并在一起了,里面有一些会Unity、会手游的,还有一部分 没有手游开发经验的,组合在一起,形成了100多人的团队, 进行了游戏的开发。

还有一个很重要的选择,我们本身是一个网络游戏。当时在 2013、2014年的时候,游戏在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在多线程的渲染,也有

很好的作用,使用引擎优势也是很必要的。随着性能的提 升,我们会对王者的画质进行提升。

2017-05-16(29赞)

评论区:

开坦克的贝塔 : 先把服务器分区给取消,玩家自己的数据只能局限在一个服务器上,太弱了 中毒的蘑菇 : 王者荣耀现在不是很想玩了囧

kimaxv : 哈哈这个说的好,估计开始没想玩这么大

Yakulto : 可以跨服联机已经算好了,看撸啊撸,不同服务器还不能联机,你A朋友在1区B朋友在2区,你要跟他们玩,还得 两个区都有角色

关注公众号"懒人找资源",星球资源一站式服务

results matching ""

    No results matching ""