更快更顺畅 -- 天天飞车性能优化秘籍
当前手机游戏发展迅速,手机性能也参差不齐,导致手机游戏性能要求比较高。腾讯游戏都是面向海量用户的,所以必须兼容市场上大部分的手机。天天飞车,在游戏开发期间,针对性能相关也做的大量优化。天飞主要根据玩家设备选择对应的游戏品质,根据对应的游戏品质做了一些效果上的简化。尽量保持游戏的流畅性的情况下,让游戏效果表现得最好。下面,我们主要从效果自适应模块、CPU优化以及内存优化这三方面来介绍一下天天飞车的性能优化。
1. 效果自适应模块
1.1. 游戏品质等级划分
天天飞车根据玩家设备,把游戏品质分成了5个等级。各个等级,不仅仅控制下面的参数,有些逻辑会根据游戏当前的品质,选择加载不同的内容或者简化表现效果,以保证游戏流畅性。渲染层面,我们的Shader是做了LOD的,主要是根据品质等级,选择对应的渲染效果。5个等级的分级情况如下图所示。
图 1 显示品质等级控制
各个参数分别表示:
l Level:品质等级
l ResolutionScale:分辨率比率
l MaterialQuality:材质质量
l HideDecorationLayer:隐藏装饰层
l Fog:雾效
l BoostParticleRate:大喷中,摧毁赛车展示火焰粒子的比率。
不同的品质等级主要影响了以下几个方面:
l 品质等级控制Shader的LOD。
l 低品质等级,场景降低赛道块种类。
l 低品质等级,只加载基础音效。
l 品质等级,决定某些特效效果是否显示。
1.2. 根据手机型号和配置,选择默认品质
1.2.1. 苹果设备:
一些较老的机型默认选择较低品质。性能较好的机型以及新出机型默认选择较高品质。
图 2 IOS设备品质控制
1.2.2. Android设备:
Android手机是根据CPU频率和内存容量选择品质。某些特定的机型,通过配置指定默认品质。
如下图所示,如果当前机器型号不在配置表上,则会根据机器的CPU频率和内存大小选择对应的显示品质。如果玩家机器的CPU和内存能达到Element0要求,则选择最高品质,依次类推。如果当前机器型号在配置表上,这选择配置品质。由于某些机型可能不支持某些效果,我们就可以控制该机型的显示品质,来避免渲染问题的产生。
图 3 Android设备品质控制
Model | Ultra | High | Middle | Low | VeryLow |
GT-I9500 | 1 | 0 | 0 | 0 | 0 |
GT-N7102 | 1 | 0 | 0 | 0 | 0 |
GT-N7100 | 1 | 0 | 0 | 0 | 0 |
GT-I9300 | 1 | 0 | 0 | 0 | 0 |
GT-I9200 | 1 | 0 | 0 | 0 | 0 |
X909 | 1 | 0 | 0 | 0 | 0 |
Nexus 7 | 1 | 0 | 0 | 0 | 0 |
GT-N7105 | 1 | 0 | 0 | 0 | 0 |
GT-I9100 | 0 | 1 | 0 | 0 | 0 |
GT-P7500 | 0 | 0 | 0 | 1 | 0 |
Xiaomi 2013022 | 0 | 0 | 0 | 1 | 0 |
Lenovo S890 | 0 | 0 | 0 | 1 | 0 |
GT-I9152 | 0 | 0 | 0 | 1 | 0 |
Meizu M040 | 0 | 0 | 1 | 0 | 0 |
SM-N900 | 1 | 0 | 0 | 0 | 0 |
T328 | 0 | 0 | 0 | 1 | 0 |
GT-S7562i | 0 | 0 | 0 | 1 | 0 |
图 4 Android指定机型品质控制
1.3. 根据当前游戏的平均帧率调整品质等级
上面的策略在游戏单局开始,会根据玩家手机型号或者配置,选择对应的默认参数。
而根据平均帧率调整品质等级则是:每隔15秒,检测平均帧率。如果平均帧率大于28帧,提升游戏品质。如果平均帧率小于20帧,降低游戏品质。
这种方法可以保证玩家机器获得最好的显示品质。但是由于以下两个原因,我们现在已经把这个策略关闭了。
1、但是由于某些资源加载可能会导致显示品质在单局中频繁切换,体验不太好。
2、因为玩家手机开了过多的应用,导致手机内存不足,游戏会降低显示品质。但是,我们还是希望玩家玩游戏前关闭其他不必要的应用以获得最好的游戏体验。
图 5 平均帧率控制游戏品质
下面是最低品质等级和最高品质等级的对比:
图 6 最低品质(上) 和 最高品质(下) 对比图
2. CPU优化
2.1. 对象池
天天飞车大部分常见的游戏对象都采用对象池来管理。对于同一个对象,第一次使用的时候,加载到内存。使用完成后放到指定的池子(某个节点),并且Deactive。下次使用的时候,直接从该池子里面取。池子中的对象列表为空时,允许克隆新的对象,放到池子。对于某个对象,定义一个最大的分配数量,控制最大生成量。
对象池的特点是:加载后不释放,不使用时放到对象池,,下次用时直接从池子里取,并且可以定义最大的分配数量控制内存。使用对象池可以方便管理同一个资源,控制其生成的最大数量。根据游戏对象的特性,合理的设定其对象池的最大分配数量,可以控制脚本较多的物件的生成上限。
值得注意的是,同一个对象,实例化多个对象出来,他们是共用贴图和模型的,所以内存增加不会增加很多。
2.2. 降低不必要的更新频率
降低不必要游戏更新频率,一方面可以降低性能上的消耗,保证用户体验,另外一方面,可以降低手机电量消耗。论坛上很多玩家反馈手机游戏耗电量高,如果我们在用户挂机的情况下降低帧率,可以改善耗电量。
2.2.1. 时间不操作,降低游戏帧率
在游戏中,长时间没有获得用户输入,游戏自动降低帧率。如果在游戏大厅降低至10帧/秒,单局内降低至15帧/秒。如果用户在单局中暂停游戏,因为需要保持UI的响应,所以只把游戏场景中的物件停止更新,并且把帧率降低至10帧/秒。
2.2.2. 降低NPC车的更新频率
在天天飞车的单局中,NPC车贯穿了整个游戏单局,因此NPC车是我们重点的优化对象。因为NPC车的逻辑比较复杂,所以NPC车也分模块调整更新频率。例如,一些不需要实时反馈的碰撞检测,降低其1/3的更新频率。
为保证用户体验,常规的 NPC都提前刷出来,所以在其与玩家距离较远的情况下,可以降低或者暂停其更新。在特殊情况下,例如超级大喷,场景中生成大量的NPC车。因为,此时玩家车速度较快,并且被特效包围,所以停止NPC车的更新,玩家是感知不到的。
2.3. 优化碰撞检测
Unity的物理世界和逻辑世界是分开的。简单的说,就是你当前这一帧看到物体A从P1点移动到P2点,但是A的物理体可能还是停留在上一帧的P1点,需要等物理世界更新的时候,才把两个世界同步。物理世界相对于逻辑世界的延迟取决于游戏工程的FixedTimestep(真实物理的帧率)。碰撞检测是基于物理世界的同步的,所以如果是赛车碰撞,擦车等检测,不然要求物理世界更新及时。如果更新不及时,很有可能导致两个物体穿插而过,但是却没有检测到碰撞。但是,Unity的物理系统是不管这个物体是否有移动,都一起更新的,这样会导致性能上的消耗。
项目组初期是采用Unity自带的Box Collider做碰撞检测的。但是随着游戏发展,里面的模式和方法逐渐丰富,需要碰撞体的物件越来越多。但是,很多时候,场景中的很多物件是不更新或者不动的,所以同步物理世界导致的性能浪费越来越大。因此,项目组根据天飞的特点写了一套基于AABB碰撞检测的物理碰撞系统。
新的碰撞检测系统把物理世界的同步拆分成个体同步,某个物件位置发生变化后,同步自己的位置信息到物理系统,这样就可以实时获得碰撞结果。该系统把物件拆分成不同的碰撞类型,每个物件可以指定需要检测的碰撞类型,减少多余的碰撞检测消耗。
2.4. 音频格式选择
Unity的音频文件可以是原生的或未压缩的。Unity支持大多数的格式(MP3、Ogg、Wav等)。但是,Ogg这种经过压缩的音频格式,在Unity中播放的时候,是需要消耗CPU周期来解码的。所以,在游戏中,最好是播放Wav这种未压缩的音频格式。但是,Wav文件比Ogg文件大很多(大概4倍,如下图所示)。所以,如果直接把Wav格式的文件打进包里,必然会导致包量增加很多。所以在天飞采用的方法是,把Ogg文件打进包里,在游戏运行的时候,把所有的Ogg文件解压成Wav文件到另外一个目录。在游戏运行期间,直接读取Wav文件。
图 8 音频文件大小对比
3. 内存优化
3.1. NGUI优化
Unity提供一套自带的GUI系统,但是这套GUI系统实在是太难用了。几乎没有游戏会使用这个原生GUI系统的,也因此催生了很多UI插件。市面上成功用Unity开发的游戏,都是使用UI插件的。最常见的UI插件有:NGUI 和 EZGUI。天天飞车采用的是NGUI。使用NGUI,需要了解NGUI的特点进行优化。
3.1.1. 图集管理
NGUI以图集(Atlases)方式管理贴图。图集就是把零散的贴图,整合在一张大的图片中。这样可以整合零散的贴图,并且减少图片文件的大小。需要注意的是,如果在游戏中需要引用图集中的某一个贴图,则整个图集就会被加载进来。所以,设计图集的时候,需要考虑里面贴图的使用范围,合理分配贴图所在的图集。不同场景中,采用不同的图集,避免场景图集相互引用。
3.1.2. 尽量复用贴图
在游戏开发初期,我们游戏就为开始考虑贴图复用问题,对于内存和包量是能省则省。美术就为游戏设计了一些通用的原子贴图。UI设计的时候,尽量采用原子贴图。拼接面板的从原子贴图集里面取贴图拼接,就不需要额外增加贴图量。
设计通用九宫格,UI按钮和面板大部分都使用九宫格做底框,可以减少很多类似的贴图重复设计,减少图集大小。
在图集中,避免增加大块的贴图。一方面,大块的贴图复用率低。另一反面,大块贴图在图集中可能导致图案周围留有较多空白位置减低利用率。
3.2. 资源规范
游戏开发初期,美术和客户端同事通过不断的尝试,以找到游戏性能和表现的最佳平衡点。从程序的角度,当然希望游戏尽量的节省资源消耗。对于美术同事,他们希望获得足够的表现效果。在程序和美术共同探索的过程中,制定了美术资源制作规范。天飞游戏里面,需要重点关注的主要有赛车和赛道。其实都是根据游戏的特点,制定一些比较合适这些特点的优化。
3.2.1. 玩家赛车
精度:因为大厅展示需要精细展示,而游戏单局中的赛车比较小,所以把单局内外的赛车模型分开。他们的模型精度分别是:大厅4500顶点,单局2500顶点。
贴图:大厅和单局理论上可以共用一份贴图,天飞这里是拆分成两份的。因为大厅中赛车没有距离变化所以采用一张512*512去掉MipMap的贴图。单局中,采用的是128*128带MipMap的贴图。
在天飞里面的材质都是采用无光的,材质加简单CubeMap来模拟动态车漆效果。
3.2.2. NPC车
NPC车的贴图总尺寸比主角少一半。模型精度不超过2500顶点。
3.2.3. 赛道
天天飞车是一个类跑酷游戏,因为不能预知玩家能跑多远,所以采用的是赛道快拼接的方法生成赛道块。上面已经介绍了赛道制作的规范。采用赛道块拼接的方法,一方面可以减少赛道加载带来的顿卡,另外一方面美术好控制模型制作的规范。一个赛道块的制作规范如下:
模型精度: 3500顶点以下。总贴图大小,不超过1024*1024(包含lightmap, diffuse)。Drawcall不超过6个。
图 9 赛道块
4. 总结
上面主要从某些模块介绍了部分优化的经验,当然还是有很多点是上面没有覆盖到的。游戏性能,应该在研发过程中一点一滴的优化和调整做出来的。这样才能保证好整个游戏的品质。在游戏性能和美术表现上,开发和美术可能会经常产生分歧。在这个问题上,我们尽量从性价比的角度来考虑。当然,我们在研发过程中也要坚持我们的一些制作原则。例如在游戏效果方面,需要禁用实时阴影,实时光照,后处理等与大多数手机硬件不匹配的技术。
美术和开发应该多沟通,共同思考和利用一些巧妙的方法制作出效果很好的画面品质。例如,在游戏大厅的车库,用背景图实现类似景深的简单效果(如图9所示)。根据赛车角度,控制车灯光片的大小,实现车灯的渐变(如图10所示)。
图 10 用背景图实现简单的景深效果
图 11 车灯渐变效果