今天我们为大家带来由蓝港互动研发的3D横版动作手游《王者之剑2》的 UWA测评报告分析。该游戏在各种档次的移动终端设备上,无论是画面表现力,还是性能开销都非常优异。在此,我们将对该款游戏的性能数据进行深度剖析,希望通过这篇文章可以让大家对移动游戏各个模块的运行效率有更为深刻的认知,并对大家的项目研发有所帮助。
该游戏目前在App Store已经正式上线,感兴趣的朋友可以通过http://wz.8864.com 一睹为快哦!
CPU性能
该游戏在CPU占用方面的性能非常不错,下图为该游戏在 红米Note2 设备上按照剧情进行游戏时的性能数据。可以看出,在红米Note2上运行的19636帧中,超过33ms的帧数占比为3.2%,超过50ms的帧数占比为1.7%。考虑到切换场景时资源加载的开销,一款游戏如果超过33ms的帧数占比低于10%,则说明该游戏的性能非常优秀,绝大多数时刻游戏运行非常流畅。
其整体CPU性能的优秀表现与其各个模块的合理使用是分不开的。接下来,我们就详细讲解一下其CPU性能方面的亮点之处。
一. 渲染模块
通过UWA性能测评报告,我们可以看到该游戏详尽的渲染模块性能开销。该游戏在红米Note2设备上运行时的渲染模块CPU开销如下图所示。通过统计,半透明物体渲染的CPU消耗均值为2.6 ms,主要集中在0.5~6.8ms范围内(5%~95%)。不透明物体渲染的CPU消耗均值为1.5 ms,主要集中在0.2~4.3ms范围内(5%~95%)。Draw Call峰值为158,且主要集中在27~119范围内(5%~95%),属于合理范围之内。
通过下图可以看出,Draw Call与Triangle的走势基本一致,在Draw Call或Triangle数值较高处,均为战斗副本中的怪物较多时出现。纵观整个游戏运行走势图,Draw Call、渲染Triangle的开销均处于合理范围之内。
二、物理模块
在UWA测评报告中,该游戏运行时的物理模块CPU开销如下图所示。可以看出,Physics.Simulate的CPU占用主要集中在1ms以下,该值处于合理范围之内(一般建议在3ms以下)。
物理模块的高效性能取决于对碰撞、Contact数量的控制得当。从下图可以看出,在游戏运行过程中,Contacts数量全部为0。同时,Active Rigidbody的数量峰值为0,碰撞体的数量峰值低于60,均处于合理范围之内。对此,建议大家时刻关注UWA测评报告中Contacts数量、Rigidbody和碰撞体数量的变化,通过对应的项目截图来判定数量高值处是否合理。
三、UI模块
该游戏在红米Note2设备上运行时的UI模块CPU开销如下图所示。该游戏使用NGUI作为UI界面的解决方案。经过统计,UI模块总体的CPU占用均值为1.8 ms,主要集中在0.1~3.5ms范围内(5%~95%)。堆内存累积分配45.7MB,平均每帧分配堆内存2.4KB。该值略高,一般我们建议平均每帧堆内存分配尽可能控制在2KB以下。
从下图中可以看出,UI堆内存的主要分配来自于UICamera.Update。该函数一般负责处理UI界面的点击操作,而一次分配较高内存,说明此处存在Instantiate实例化UI界面的操作。通过进一步查看Instantiate的详细调用开销,果然可以查看到UICamera.Update下存在较高的性能开销。
如果你的项目中也存在类似的开销,可根据UI界面使用频率的不同尝试以下方案:
1、如果该UI界面开启的频率很低,可考虑直接通过Instantiate/Destroy来进行切换;
2、如果该UI界面使用较为频繁,可尝试通过Active/Deactive来代替Instantiate/Destroy操作,从而降低UI切换时的性能开销;
3、如果该UI界面使用非常频繁,则可尝试直接改变UI界面位置的方式来移进/移出相机视域体,从而来极大提升UI界面的切换效率。
同时,关于UI界面的使用频率,这个本身没有明确的固定标准,需要大家根据自己项目的需求来进行规定。比如,通过检测游戏项目一天中UI界面的点击率来进行规划等等。
内存模块
《王者之剑2》在内存上的表现如下图所示。总内存峰值达到243MB,Mono堆内存峰值为28.2MB,且内存在游戏运行过程中表现较为平稳。243MB的总内存分配相对来说略高,研发团队可尝试在低端机器上对资源进行进一步控制,从而降低低端机器上的内存占用。
一、Mono堆内存
从上图可知,该游戏的总体Mono堆内存控制得很好,在19635帧中,Mono的堆内存峰值仅为 28.2MB。该值属于合理范围之内(<40MB)。
如此少量的Mono堆内存分配,主要得益于项目中函数堆内存分配控制得当,下图为当前游戏运行19600+帧的函数堆内存分配情况。因此,建议大家对函数代码堆内存的分配进行严格控制,对于堆内存分配较高(10000帧10MB+)的函数进行详细定位其分配原因。在UWA测评报告中,我们提供了堆内存分配Top10的具体堆栈,以方便大家尽快地定位堆内存分配出处。
经过进一步定位,该游戏在运行时Instantiate实例化操作造成较高的堆内存分配(总共累积37MB+)。因此,建议大家在查看项目报告中密切关注Instantiate实例化操作的性能开销,降低Instantiate/Destory的调用频率,将有效降低其堆内存的分配。
二、资源内存
经过统计,该游戏的纹理资源数量峰值为350个,内存占用峰值38.2MB。在全部纹理资源中,ETC1和ETC2格式纹理占有242个,Alpha8格式纹理占有9个,RGBA32和ARGB32格式纹理共占有44个,RGB24格式纹理占有18个,其余为RGBA16格式纹理。
对于RGBA32、ARGB32、RGB24和RGBA16格式的纹理,我们建议在视觉效果可以保证的情况下,尽可能使用ETC1格式纹理(Android平台)进行替换,不仅可以达到更小的内存占用,同时可以获得更快的加载效率。对于纹理资源的加载效率,我们在之前的Unity加载模块之纹理篇中进行了详细的分析和阐述,建议大家进一步查看,来加深对加载模块的掌控能力。
其他资源的内存占用情况如下:
Mesh资源:
AnimationClip资源:
以上则为《王者之剑2》游戏在CPU性能和内存管理方面的具体使用情况。优秀的CPU性能、较低的堆内存分配以及引擎模块间的合理使用,足以说明该研发团队具备非常深厚的技术功底和对于引擎相当优秀的把控能力。
同时,该游戏在资源实例化和加载模块方面仍有一定的提升空间。在此,我们对其进行罗列,希望同样可以帮助到大家的研发项目。
性能优化、进无止境
一、Instantiate实例化
目前,游戏的战斗副本中Instantiate实例化的频率较高,如下图所示。较高频次的Instantiate/Destroy操作会造成一定的内存碎片,从而造成GC的加速到来。
对于频繁的Instantiate调用,我们的建议如下:
1、对于一般的GameObject(比如技能特效、怪物角色等),可将其放入缓存池并通过Active/Deactive来进行切换;
2、对于使用频率较高的UI界面,则可通过直接改变Transform的方式来移进移出相机视域体,可以得到更加高效的性能。
二、加载模块
该游戏在运行过程中,非切换场景处存在较为频繁的Loading.UpdatePreloading CPU占用,如下图红框中所示。经过进一步分析,红框中的CPU占用为UI界面开启/关闭时的Resources.UnloadUnusedAssets API函数调用开销。对此,建议研发团队密切关注加载模块中Resources.UnloadUnusedAssets的调用频率,尽可能避免较短时间该函数的重复调用。对于长时间停留在一个场景中的项目(比如MMO游戏)来说,可尝试间隔一定时间(比如15分钟甚至更长时间)来主动触发一次Resources.UnloadUnusedAssets。
以上则为该项目在后续研发中可进一步提升性能的主要方面。在我们测评过的项目中,Instantiate实例化和Resources.UnloadUnusedAssets操作调用频率过高等问题也是绝大多数研发团队遇到的共性问题。希望以上的讲解对大家的相关问题有所帮助。
最后,非常感谢《王者之剑2》研发团队对 UWA 的认可和支持。感谢他们乐于将项目性能数据与大家一起分享,让更多的研发团队了解到一款性能优秀的3D横版动作游戏在各个模块上应该做到怎样的程度。同时,也希望更多的开发团队可以与我们一起来分享他们的性能数据,让更多的游戏开发者受益!