《穿越火线》郭智:游戏开发过程中的问题与技术拓展分享
在近日举行的 开发者大会期间,来自腾讯穿越火线项目组的郭智分享了《穿越火线》相关的游戏开发经验,以下是演讲实录:
郭智:各位好。我是腾讯穿越火线项目组的郭智。我先做一下个人介绍,我是2011年加入腾讯,现在是穿越火线枪战王者主程序,也负责多款手游客户端研发工作,我有十年的工作经验,历经了MMOG、FPS和端手游各类项目,有比较丰富的自研和一些商业化引擎链接使用经验,今天主要跟大家分享在穿越火线游戏里所遇到的问题和使用里我们所做的技术的拓展。
我们先说一下整个项目技术的背景介绍,因为背景介绍关乎我们在开发流程里跟随版本进化里的一些技术演化。大家可以看到其实我们这个项目是在2015年3月份的时候开始做技术预研的,经历过五个月的时间,9月份我们第一次对外测试,经历了两轮技术测试之后,11月进行三轮测试,2016年进入稳定运营期,2017看到发布的非常重磅的版本,就是生存特训模式,就是现在非常流行的大世界的一些《吃鸡》玩法,在整个三年里我们技术演化其实总共经历了三个阶段,主要是2015年属于研发期,当时强调.6的版本,我们用的4.6版本,当时的移动设备手机发展还是刚刚迅猛发展起来,所以说当时我们做的时候,面对五个核心问题,也就是说我们解决了五个核心问题,一个是游戏架构,一个是反外挂,再加说弱网络同步,还有游戏手感,最后一个是画面和性能。这是2015年刚开始在研发期所遇到的五个核心问题。
到了2016年其实我们处于整个是多玩法的运营期。2016年是整个稳定运营期,我们尝试了十多种不同类型的玩法,每个月我们都会推出一些玩儿法给玩家尝试,来保持热度。这些玩儿法也给我们带来一些技术挑战,比如我们出一些穿越火线塔防玩法,也有多人配合打Boss的玩法,也会有一些像生化统领的一些放置类和控制类玩法,各种各样的玩法给我们不同的挑战。2017年是整个开放世界技术爆发的一年,所以2017年投入到开放世界开发里,我们也相对遇到一些问题,最主要的四个问题,一个是大世界的五个方案,还有工具链,还有对整个引擎功能做出拓展和做出合理使用,最后是对大世界技术里比较重要的一些性能优化与适配。
我前面说到了我们面临一个比较大的挑战就是FPC游戏网络建构。这是业界一个标杆架构的存在。我说一下当时在研发期间,我们通过对网络调研和实地测试,可以看到无线网络,虽然延时不断的向固网靠近,但是仍然会有抖动和丢包的情况会比较多,在弱网络情况下如果直接套用当时的一些端游的技术方案来说,流量和电量消耗比较大,玩家体验不会那么好。所以可以看到弱网络情况下当时的环境是这么分布的,这是现在我们玩家里这么分布的。所以在这样的弱网络情况下实现我们FPS游戏实时对战,并且强调竞技用户有很好的用户体验。
我们看一下传统的FPS游戏架构是怎么样的?传统的FPS游戏架构是服务器不进行逻辑运算,它只是说对一些战斗计算和移动计算数据校验相应做转发,直接把一些移动,还有战斗计算通过服务器算的通过了进行转发。这种方案会有以下的优势,主要说服务器运算逻辑比较简单,性能也会高,它的开发门槛也会比较敌,比如说客户端开发完直接把DL放到服务端就可以了。但是也会遇到下面的问题,比如核心的运算在客户端里,会面临各种各样的一些外挂问题,还有它其实服务器是比较受限的,它没办法做各种各样复杂的玩法,并且它容易受到移动网络的影响,弱网络在这种情况下是不流畅的。基于这样的特点,我觉得我们对于品质要求这么高的手游来说,这个架构我觉得是不适合的。所以当时我提出了我们CS的架构,我们单独搭建实现我们BS服务器,跑的完全游戏逻辑。这个时候服务器和客户端会运行,执行一致的移动和逻辑计算,然后按照一定的帧率把数据同步到客户端,这样可以做高强度的反外挂,卖二手手机靓号平台并且可以在弱网络下做更多决策,从而达到我们更加良好的同步,然后用户体验也会比较好。所以会看到我们有三大优势:一个是高强度反外挂,在弱网络下我们会做补偿,做良好的同步,再下来会做各种各样客户端和服务端延时补偿,整个客户体验很好的。但是也有局限,就是对开发效率都会比前面的方案低一点,但是只有这个方案才能让我们走的更远。这是2015年投入的整个方案。
经过2015年到现在的2018这个方案不断演化。看一下我们的整体架构是怎样的。其实2015年搭建的这套框架我们是基于CS基础上搭建的这个架构图。首先说我们的底层都是,里封装了物理引擎等一系列方案,同时我们服务器,首先我们服务器也跑的完整的物理器,我们在服务器编译的开源的。在数据层写了相对应的导出工具,导出碰撞模型和关卡数据提供给服务端使用,并且保证一致。在逻辑层客户端是用编写的,服务器为了高性能,使用C++,保证关键数据是一致的。客户端和服务器都会做同样的移动计算。服务器会在同样的位置进行运动伤害计算,并且通知客户端要验证结果表现。同时我们再在上层的逻辑同步上面在封装了我们移动同步的封装,基于这个架构基本能囊括业界的所有方案。
我们可以看到当时我们的视图,一个是客户端的语音视图,一个是服务器物理视图,是基于我们跟米那服务器引擎合作做的服务器视图。可以看到总体来看服务器永远是权威,客户端是亚终端,这样的话可以杜绝很多外挂的出现,这是这么多年来我们对抗外挂一个比较强的手段。
基于这个架构我提一下,我们其实在各种各样的场合里大家都接触了各种各样的同步方案,但是这些同步方案要么导航预测算法,影子预测算法里都会使用,但是会遇到各种各样的,大世界里我们遇到各种各样的挑战,比如高精确的物理同步,比如快速行驶的汽车,业界都会遇到如下的问题,比如我们要实现在据同步的时候的话,会发现载具同步比较快,延时也比较高,服务器运行帧率远远低的,最大的服务器跑30帧,这样没办法做准确的物理运算。对人眼一些不规则的速度会非常敏感,所以会看到在参与不规则物理运算的时候,人眼一看,这个比较假。基于这项特点可以看到业界做手游做载具相撞的时候就停下来了。这时候我们提出了Move 方案,核心是通过预测不,通过碰撞模拟做一定的相对的混合。比如说在正常移动过程中我们是走最左边的预测同步的阶段,在这个阶段里完全做,由服务器驱动做导航预测算法,做预测的同步。当预测到相对应发生碰撞的时候,我们采取物理模拟动态授权的方案,把所有物理模拟授权分发给各个客户端,然后客户端做物理授权,做自己的物理表现。这个时候客户端可以做准确的物理表现。最后,再通过了碰撞物理模拟阶段之后,然后我们再回到了最后的物理混合。只有基于这种物理混合的方式我们才能做一些复杂的物理表现和同步的方案。这是我们在2017年做的相对的技术演化。
说完整个网络架构之后,我们其实还会面临一些挑战,比如说现在的一些硬件发展趋势下面的一些高性能的并行架构,对于CF手游卖相来说是这样的,就是小型场景里的精确同步,比如你可以有的团队爆破在,最多不会超过20个人,30个人,因为是竞技化,要求同步里我能准确同步每个人行为,我能够让玩家体验比较好,能够完成整个竞技化的需求,当年是这个样子的。到了2016年变成这样的场景,变成小型场景大量同屏战斗,曾经有一个场景打50个Boss,有60个怪。到了2017年变成这样子,就是超大世界高复杂度的战斗,从区域有500个关卡要素,有3千多渲染等等。把所有复杂高的东西都在大世界里实现,同时手机计算能力也是非常有限的,由于CF手游一直给人的印象性能非常好,像小米1的手机都能跑。所以当时定义大世界的方案里需要有百元机也能跑三帧这样的基调。同时还要求有充实的元素,画质品质也很优秀,再下来我们还要在乎功耗,就是在这么高要求的,画面要求计算量那么大情况下我们还可能。我们怎么解决的,这个解决方案我们也经过三个阶段的技术演化。第一阶段,提出了高性能的并行架构,主要是处理多合调度和并行化,还有性能功耗均衡,然后适配也要做到最优,适配跨平台,跨厂商,跨芯片的适配。第二阶段,基于整个高性能并行基础上我们做大世界的管理与剔除。也就是说我们要做到管线更加优化。比如当时提出来在业界里处于非常顶尖地位的一个可见剔除方案,在这个方案再做大世界的管理。有以上两个基础后我们再不断做引擎的拓展以及整个技术整体性能的调优。为什么做并行方案,芯片包含了大小盒,这是HMP的架构。对于老的芯片来说,它其实都是SMP架构,也就是说双大盒或者四大盒的架构。可以看到无图式这样架构的特点。如图可以得到如下的结论:就是不同内核它的工作的内耗是不一样的,支持的计算能力不同的,计算能力越强功耗越高。还有计算量走到高频的时候,像到90%的时候功耗会抖帧。所以做出了这个策略,要选取合理的功耗内核,和降低大核。我们基于整个机制,封装了整个引擎flg的调度层。基于这上面我们封装了我们整个并行引擎的管线,再基于这个管线上做自己所有并行化任务,比如并行任务等等的。后面我其实后面案例会涉及到这些并行任务在这儿怎么跑起来的。
有了并行架构我们有很多优化,就进入第二阶段,就是开放大世界技术的一些实现。大家可以看到开放大世界的实现里的一个典型的场景,在这个典型的位置里可以看到这个位置有60万个面,有700个和15+人和载具。这个时候这个量级的渲染主流的机型,像小米4直接渲染出来不做任何优化的话,只能够跑小于15的,所以我们要把它优化好。我们想到的第一点大世界里要做剔除。所以我们要有合理的剔除方案,包括遮挡剔除,合理就是基于上建造一套最合理的,在业界最顶尖的一套遮挡剔除 系统。所以当时提出了CF可见性剔除方案,首先回到刚才的游戏世界,把游戏世界拆开成两个世界,一个是不变的部分,这个叫静态世界。动态世界是变的部分,就是人,载具,特效,UI这种是变的部分。静态部分只会在世界开始那一帧的时候,就是不变的,比如决定哪些场景渲染的时候这些是永远不变的,只会受摄像机的移动影响。
主要的核心原理是,我需要有一条单独的线程做可见性检测,静态的部分我抛离 data,使用 Data做软件光栅化,得到深度结果。查询深度结果驱动渲染。我们可以看到中间的线程是拿软件光栅化得出剔除结果决定哪些要渲,哪些不渲。如图可以看到这条管线里有两个非常重要的实现,一个是数去的提取,还有是运行时,就是软件光栅化。
我说一下我们离线数据提取,这个包含业界很多的算法,首先拿到原始模型,然后对这个模型做集合的简化,然后得到每个模型里哪些有共面的三角形。再做平面空间的简化,我把相应的共面三角形做到平面空间的简化,最后得到平面空间简化的结果,再切割到视图上,再依据像素范式,就是光栅化像素提取轮廓做简化,最后得出一个最优集成集合。再返回到世界空间里,就可以得到运算超快,数据表达超简单,能够快速做软件光栅化的一些数据。经过我们提取后389个面变成72个面。可以看到做的两个图,沙漠图和绿地图,基本上是是数据的27%和24%。整体算法是选取合理的图形算法,各个维度对模型做最极大的简化。还对业界的算法有更优的一点是说业界的简化算法只可以提取不可以进去的建筑,导致一些不准确的运算。如图,像即使一条缝的人也要保证他准确的结果,这样的话能够保证我们在APS里的公平性,不可能这个人裁掉的时候打不到。
总结一下我们可建性剔除方案,就是小型场景还会有的剔除。大世界户用自己的剔除方案。剔除方案其实是可建性剔除是纯CPU方案,它适用所有移动端硬件,它可以做良好的引擎集成,就引擎做并行化,优化,其实就像我们基于做一些优化。还有做里面封装一个共线剔除,做最优的LD管理。同时它的运行速度非常快,得到最优的剔除结果,同时它可以自动化生成一些,可以优化美术师的一些工作。
经过软件光栅化剔除后,还会面临一些问题,比如会发现为还很高,美术为了品质会增加资源,复杂度高,动态控制加载距离不同倍镜等需求,要控制住:高中低配硬件流畅运行。首先需要有一个整体空间管理方案,基于这个管理方案我们先做相对应的资源优化,提取收益最高的LD集合,LD集合代替单个物体LD。执行完之后我们会进行性能的规范,会使用规范算法,会调整策略,比如说我们会执行严格的预算,我们会考虑站在每一块场景里面的一些性能损耗是什么样子的,它的性能参数是怎么样的,它是不是符合性能规范,会做高层次规划算法。我们会做自动化测试,专业测试和上报的监控,今天基于这管线不断的迭代和轮训我们可以得到最合理的场景。
我再细说一下我们空间管理怎么做的。因为在手游做空间划分,可以划分物理层,细节层等等。每一层可以单独定义每个Care的力度,比如它的加载距离是50×50,还是100×100,高度是,三维高度每一百米要做一个划分,像高度是100×100×100,进行距处的分组,如图,绿色是物理层,黄色是环境层,也就是说我们的建筑,蓝色是细节的小物件和细节的表现,每一层走可以单独进行它的一些相对一些定义,然后做管理,最后很好的在这个层次里把它空间做出很好的划分。
之后做距处分组,这个其实就是整个距处资源优化过程。其实整个过程是我们选取LD距处集合合并,然后预计算它的收益比。也就是说,我们对这些距处进行Mach后它的收益和损耗到底是怎样的。最后再根据我们算出来的每个收益的损耗,要用算法得出最优收益比怎么跟LD集合。可以看到比如说我们在不同Tele里是不是要把这两个物件合并起来,可以根据刚才说的预算分值进行衡量,如果分值比较高,比较合理就合起来。如果合起来,虽然合起来面少了,但是收益低,就不合。永远通过这些运算得出合理的大世界的预算管理。有了这套后再执行距处替换LD策略,就是在最近的时候可以看到做模型的LD切换。在稍远的距离里我们会使用我们刚才合并的替换的模型。在最远的距离,其实我们还是会对不同LD级别替换不同的模型,这样的话能让我们整个损耗是最少的。这个核心原理就是说我越近的地方,越用最精简的模型;越远的地方,不同的LD用我们距处优化模型,这样可以得到最合理的资源优化。这个过程需要不断的测试和调试,不断的调整策略,然后达到不同平台里最优的表现。
大家可以看到如下这个图,这个图里就是说我们会在离线烘焙阶段会算我们站在每个地图角落里所看到的三角形,看到的面数,看到的数据,可以算出来每一块里的收益和损耗比,然后做离线的规划。用我们离线规划算法做离线规划,再对它的资源做合并。最后核心还是说我们要保证每个位置里性能是完全可控的。基于完全可控的地形里,我们再把一些可控的结果做相对的LD替换。
基于有了这个开放大世界的管理之后,我们其实就进入到我们技术演化第三个阶段,也就是非常重要的,其实有了使用引擎里,其实引擎一个非常大的理念,是要让它变成我们自己手上的引擎。我们团队其实在这么多年组建以来,一直演化,我们要成为国内最顶尖的设计游戏团队,所以我们会对整个引擎进行不断拓展和性能调优,我做了如下事情。这是我们整体的架构图,可以看到分层是非常合理和严谨的。首先,最下面是平台独立层。我们以下封装了我们UDP整个网络层。刚才说到的网络同步方案是基于这个UDP网络层做网络同步的。同时,其实我们也会封装自己的多线程角度库和基于本身的多线程方案封装自己多线程调库。我们也会封装我们数学库和指令库。我也会对一些手柄和平台做出接入。这是我们平台层。
再现在是,我们CF手游高性能下做的。基于做的底层各种各样的渲染优化,大世界里的植被系统的渲染应该怎么做,还有的LD怎么做,多线程的怎么做,还有我刚才提到的整个大世界的管理方案,和系统整个方案,同时骨骼动漫来可以做GPU Skin等的操作。同时我们也对它整个物理算法做出了封装,保证个服务端一致。
基于这个技术引擎层可以推出我们工作架构流,像我们工作逻辑是怎样的,我们前后端交互框架怎样的,再加上大世界的管理等等都在这上面。基于这个工作流我们会在上面开发,开发了现在不止50个游戏模式了,不止100多个关卡了,500多枪了,还有各种各样的人物形象载具,任何需求对我们团队都没问题的,其实只要跟引擎厂商合作,把它打造成属于我们自己的引擎。我们同时也会提出自己一些创新的突破性的项目。
在我介绍里我所说的PPS数学和物理库我们做出一定的封装。比如我们提出业界最快、最适合移动射击游戏的数学物理库。我们其实基于引擎数据库进行封装的。比如说我们会PPS检测,像球,胶囊体的算法得到最优。可以重新定义射击游戏的物理的模型。然后重新定义射击游戏手游里的一些标杆,一些手感,比如支持数百种枪械射击手感的数据模型。也可以定义认为的标准,我们多款移动射击游戏其实是性能和手机的基石,其实成为了整个行业业界的标杆。同时我们图印象也不断做拓展,同时保证高中低配效果都会是最优。可以看到我们这个屏幕都非常高清了,大家可能还是看不出来,我们哪个是高配,哪个中配,哪个是低配,通过不断的图形优化,让我们品质永远达到最优的。
有了图形之后我们不断的会对情况做出优化。我们当前基于做到了,我们适配了市面上98%的一些市面机器。安卓上百种模式针对稳定在45帧。我们生存模式,平均帧率到29帧。上百种模式帧率到50。我们可以集成一些电量策略盒子和集成了现在整个性能测试。还有一些适配做支持。所以说我们永远保证了性能是最优的。
基于这一点其实今天可能分享是这些,大家也可以跟我们做相应的交流。
提问:我们如何自己做引擎,我们对的依赖是什么?
郭智:我本身用过很多引擎,我感觉本身帮你解决很多问题,可以对行业做出的技术方案做封装。我们基于这种非常完善的技术方案再做引擎的拓展,和你所需要功能开发,为什么你还需要自研一款引擎,要重造轮子呢?你觉得你在不同场景里所使用的技术方案,如果你想实现的话你自己做实现就可以了。
提问:关于这个技术是基于客户端做的吗,就是这是一个纯粹的客户端业务,还是先在服务端抓取一些再到本地做遮挡剔除。
郭智:这个方案最美术做的场景资源,和对他所有的3D模型作出相应的遮挡数据的提取。提取出来数据后用软件光栅化,做遮挡和剔除的结果,至于这个结果其实现在可以用在客户端,也可以用在服务器上,但是现在主要用在客户端上。
提问:物理在服务器算的话会存在延时问题,在客户端会存在作弊的问题。所以我想问一下物理混合是什么,是服务器算出结果,客户端再拟合吗?
郭智:其实物理混合非常关键的问题,如果是以服务器计算精度不可能达到这么高精确物理同步的,所以我们依赖把动态授权分发到各个客户端里做相对的计算。计算之后服务器端同时也在算,在这么短时间,比如说在2-3秒时间内把碰撞结果做出一定的表现。这样最后再通过物理表现再跟服务端最后算出来的权威结果做混合,这样才能达到我们这么高精度的物理同步。所以说在这个阶段里你所面临的外挂可能是这2-3秒的时间。如果说这2-3秒时间被利用到了,那么我们现在其实服务端也有完整的运算,可以通过比如说方差或者平均差这种数据判断一些方式,然后达到防止它的这样的目的。
提问:因为我们都知道物理引擎不稳定的,在不同的平台,不同的设备上跑出相同的完全的表现是不可能的。也就是说,我们现在的实验方式,就是说服务器用来做最终的结果,然后不同的客户端做不同的表现,但是最终拟合到服务器的结果就可以了吗?
郭智:对,就是做最后准确计算的时候。
提问:你们基于状态同步的,现在感觉又类似于帧同步,这里有没有明晰的界面,或者是自己单独创造了一套,是结合了两个优势的?
郭智:我们本身就是CS架构,这不是帧同步。帧从不的概念是把相对的操作发给服务器,但是现在不是。所以说我们还是纯的CS架构的一个状态同步的机制。只是说对高精确,你刚才所看到的同步,把一些计算结果交给客户端做出一定模拟。
提问:问一下离线同步原理的问题。
郭智:如果最场景里,比如60万个三角形,你做任何优化都会花费时间,可能是50毫秒到上百毫秒,所以第一阶段要把相对数学模型做简化,就是把你所需要的三角形换算你所需要的轮廓表达形式。要至于最终的表达形式在这里我不方便透露。
提问:这个离线是事先生成好的遮挡数据是吧?
郭智:离线有几个,一个是把静态物体先生成后提取出来,对动态物体,动态添加到我所维护的一个遮挡,就是一个遮挡剔除的事件里。
提问:这个数据的话,你如果在不同的视角遮挡的数据是不一样的。
郭智:这是纯的三维世界,所以是完全一样的。因为提取是正常的三维的世界,所以最后在不同视角,一个摄像机能得到你所视角的结果,它跟Nbla方案是不一样的。
提问:关于反外挂的问题,像客户端把模型的材质透明了,透视化是怎么解决的?
郭智:透视外挂要解决最合理的方案还是在服务器上做相关性检测,相关性检测有几个维度:一个是基于空间管理的。比如说在这个人在这个位置看不到这个空间角色的,不应该同步过来。第二,基于客户端维度,就是像刚才说的遮挡剔除,剔除结果其实并没有发给渲染器,所以渲染器怎么改也改不过来。
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。