优化移动游戏性能:获取关于物理、用户界面和音频设置的专家建议

THOMAS KROGH-JACOBSEN / UNITY TECHNOLOGIESSenior Technical Content Marketing Manager
Jul 13, 2021|13 Min
优化移动游戏性能:获取关于物理、用户界面和音频设置的专家建议
为方便起见,此网页已进行机器翻译。我们无法保证翻译内容的准确性或可靠性。如果您对翻译内容的准确性有疑问,请参阅此网页的官方英文版本。

Unity的Integrated Success团队向来以帮助客户解决最复杂的技术问题为目标。本次,我们请到了这支高级软件工程师团队来与大家分享一些移动游戏优化方面的专业知识。

Unity Studio Productions团队对引擎的源代码了如指掌,并与大量的Unity客户有过合作,帮助他们最大限度地利用引擎。团队的日常工作包括深入剖析客户项目,搜寻其在速度、稳定性与效率方面有待优化的部分。

我们的工程师在分享中可谓是倾囊相授,如此多的锦囊妙计无法在一篇博文完整地讲完。因此,我们决定将这些堆积如山的知识编篡成一本完整的电子书(可在此处下载),并推出一个博文系列,重点介绍其中75个可操作性强的技巧。

在本文属系列第二篇,我们将话题聚焦于UI、Physics和音频上的性能优化方法。第一篇关于剖析、内存和代码架构的博文可在之前的帖子查看——我们将在下一篇博文中专门讨论素材资源、项目配置和图形方面的优化,请继续关注。

想要立即看完所有内容?那就来这里免费下载完整版电子书吧。

让我们马上进入正题!

物理

Unity内置的Physics物理模拟(Nvidia PhysX)在移动设备上很可能会耗费过多机能,而下方提示将指导你如何挤出更高的帧率。

项目设置优化

请尽可能多地使用PlayerSettings下的预烘焙碰撞网格

带有深灰色背景的播放器设置框的图像,文本"预烘焙碰撞网格*"被选中并用红色框住。
启用Prebake Collision Meshes。

找到项目的Physics设置项目设置 > 物理),并尽量简化碰撞层级矩阵

禁用自动同步变换,启用重复使用碰撞回调

带有灰色背景的项目设置框的图片,其中"自动同步变换"和"碰撞层级矩阵"部分用红色框住。
简化项目物理模拟设置可以增强性能。
性能分析器的物理模块图像,5ms部分在黑色背景下显示绿色、蓝色和橙色的活动。
时刻注意Profiler中Physics模块可能出现的性能问题。
简化碰撞体

网格碰撞体的性能开销一般比较高昂,因此用原始或简化后的网格碰撞体来代替复杂的碰撞体是较好的选择。

使用原始网格或简化网格来表示碰撞体。
使用原始网格或简化网格来表示碰撞体。
使用物理手段移动刚体

使用类似MovePositionAddForce等方法来移动Rigidbody对象。直接在Transform组件上进行平移会让引擎重新计算整个物理空间,如果恰巧场景还非常复杂,则整个流程会耗费大量的机能。物理对象的移动方法应防在FixedUpdate而非Update下。

正确设定Fixed Timestep(固定时间步)

Fixed Timestep在默认情况下为0.02(50 Hz)。请根据你的目标帧率将其调成合适的值(如30 fps应为0.03)。

如果运行时出现了掉帧,这可能暗示了Unity在一帧上调用了多次FixedUpdate,且执行了过于繁重的物理运算,消耗了过多的CPU性能。

Maximum Allowed Timestep(最大时间步步长)可在掉帧出现时限制物理运算和FixedUpdate的运行时长。更低的数值表示物理运算和动画会在掉帧时被限制,从而降低其对帧率的影响。

项目设置中固定时间模块的图像,背景为灰色,文本为白色。
请根据你的目标帧率来修改Fixed Timestep的步长,将时间限定到合理的范围内来减少卡顿。
使用Physics Debugger可视化物理运算

Physics Debug(物理模拟调试)窗口(窗口 > 分析 > 物理调试器)可帮助你排除有问题的碰撞体或不准确的物理运算,它会以一定的颜色来显示出可相互碰撞的GameObject。

带有网格覆盖和蓝色阴影的橙色船只在物理调试对话框中的图像。
Physics Debug工具能以图像显示出物理对象的相互作用。

关于工具的更多信息请参见Unity文档的Physics Debug Visualization

用户接口

Unity UI(UGUI)是性能问题中的常客。UGUI的Canvas组件负责为UI元素生成和更新网格,并向GPU发出绘制调用,而这些运作的性能消耗较大,因此我们在使用时要记住以下要点。

分割Canvas画布

如果某个大型Canvas包含了上千个元素,单个UI元素的更新也会导致整个Canvas更新,造成不必要的CPU占用。

这时我们可利用UGUI的多画布功能,根据更新频率来划分UI元素。将相对静止的UI元素放在一个画布上,将需要时常更新的动态元素放在小型的子画布上,

然后统一画布内所有UI元素的Z轴坐标、材质和纹理。

隐藏不可见的UI元素

部分UI元素可能只会间断地出现(譬如角色受伤时出现的血条),就算这个元素变得不可见,它仍可能会发出绘制调用。因此我们需要具体地禁用所有不可见的UI组件,仅在需要时重新激活。

如果你只需隐藏画布,可以禁用Canvas组件,不必禁用整个GameObject,从而避免引擎再度绘制网格和顶点。

限制GraphicRaycasters数量、禁用Raycast Target

类似屏幕触摸或点击等输入事件需要使用GraphicRaycaster组件处理。组件会循环检测屏幕的每个输入点,检查其与UI的RectTransform是否有重叠。

但我们不必将GraphicRaycaster放在默认Canvas层级的顶层,而可以将GraphicRaycaster添加到需要互动的元素(按钮、滚动条等等)上。

灰色图形射线投射器对话框的图像,带有白色文本。
禁用默认启用的反转图形。

此外,不一定每个UI文本都要为Raycast Target(射线目标)。在不必要的位置禁用这个选项可让UI运算进一步简化,这在复杂的UI上意味着不小的性能收益。

带有灰色背景和红色方框中标出"Raycast Target"文本的对话框图像。
如无必要,请禁用Raycast Target。
避免使用Layout Group(布局组)

由于Layout Group的更新效率较低,所以非动态内容完全可以不使用这项功能,转而借助锚点来实现比例化布局。或者,你也能用自定义代码在布局生成完毕后禁用Layout Group组件。

如果你确实需要在动态元素上使用(水平、垂直、网格式)Layout Group,请避免嵌套使用。

带有灰色背景和白色文本的网格布局组对话框。
Layout Group,尤其是在嵌套使用时,可能会显著降低性能。
避免使用大型的List与Grid视图

大型List和Grid视图会占用大量性能。如果你需要创建一个大型的List或Grid视图(比如一个包含数百个物品的物品栏),可以考虑建立一个UI库,重复使用库中的元素而非为每个物品创建一个元素。请在这个GitHub项目样例中查看实例。

避免多元素的重叠

将大量的UI元素堆在一起(比如卡牌游戏中的卡堆)会造成过度绘制。我们可使用自定义代码,在运行时将堆叠的多个元素合并成几个或几批较小的元素。

使用多种分辨率和纵横比

目前移动设备的分辨率和屏幕尺寸五花八门,而制作不同分辨率的UI、让其完美适配设备也就很有必要了。

Device Simulator(设备模拟器)支持在引擎中模拟UI在各个设备上的表现。你也可以使用XCodeAndroid Studio来创建虚拟设备。

设备模拟器的图像,背景为灰色对话框,模拟在智能手机上的赛车游戏。
在Device Simulator中预览各种样式的屏幕。
在UI覆盖全屏时隐藏不可见内容

如果暂停或开始菜单覆盖了整个场景,我们可以禁用渲染场景的摄像机,同样地,隐藏在顶层画布背后的元素也可被禁用。

你甚至可以在UI显示期间使用Application.targetFrameRate来降低帧率,因为UI不需要以高帧率刷新。

在游戏空间与Camera Space Canvas上摆放摄像机

如果EventRender Camera字段为空,则Unity会强行在其中加入Camera.main,造成不必要的性能浪费。

我们可以在画布的RenderMode中使用Screen Space - Overlay,来省略掉摄像机的使用。

相机空间画布对话框的图像,背景灰色,文字为白色。
当然,在World Space Render Mode(游戏空间渲染模式)下,请不要忘了指定一个Event Camera。
音频

尽管音频通常不是性能瓶颈,但你仍然可以进行优化以节省内存。

检查器对话框,背景为灰色,文字为白色,底部有一个橙色的音频调制器。
优化AudioClips(音频片段)的导入设置。
尽可能地采用未经压缩的原始WAV文件作为资源

Unity会在导入时解压所有的压缩格式(如MP3或Vorbis),在构建时再度进行压缩,这就导致了音频经受两次压缩,最终音质将不可避免地受损。

降低音频压缩时的压缩比

使用压缩技术降低音频大小和内存使用:

  • 大部分音效使用Vorbis格式(不打算循环播放的音效可使用MP3)。
  • 短促且经常出现的声音(如脚步声、枪声)使用ADPCM格式。相较于未压缩的PCM格式,该格式减小了文件体积,还能在播放时快速解码。

移动设备上的声效最高频率应为22,050赫兹,较低的频率虽然对最终音频的影响不大,但你最好用自己的双耳来做判断。

选择恰当的Load Type(加载类型)

Load Type设置应根据音频的体积而异。

  • 短音频(< 200 kb)可以设为加载时解压。这时音频会被解压成原始的16位PCM音频数据,产生一定CPU和内存占用,所以音频不宜过大。
  • 中等音频(>= 200 kb)可保持在内存中压缩
  • 长音频(背景音乐)应设为流播放,避免将整个音频资源一次性加载到内存中。
释放无声音AudioSources的内存

实现静音按钮时,不要仅仅将音量设置为0。你可以销毁 音频源组件以将其从内存中卸载,前提是玩家不需要频繁切换此功能。

下载完整版电子书

我们将在下一篇博文中讨论图形和资源方面的优化。当然,如果你立即学习所有团队提出的技巧和窍门,可在此处下载全本电子书。

电子书封面图像,背景为红色,图形为一款冒险游戏,画面中有龙,文字为"优化移动游戏性能",字体为粗体白色。

下载电子书

若想详细了解Unity的Integrated Support服务,或希望直接联系Unity工程师,为你的项目寻求专家建议和最佳实践指导,请点击此处了解Unity的Success Plans。

敬请期待更多优化技巧

我们希望帮助每位Unity创作者发挥出自己项目的最大潜力,如果你有任何想要深入发掘的优化课题,请在评论中给我们留言。