如今越来越多的开发者使用Unity开发Android及iOS项目,开发过程中难免会遇到一些性能方面的问题,例如掉帧、延迟和卡顿等等,导致游戏体验变差甚至毫无游戏体验可言。今天这篇文章将由Niels Tiercelin,为大家深入剖析Unity项目优化过程。
游戏性能分析
Unity Profiler
建议使用Unity Profiler工具(Window > Profiler)来分析项目性能,该工具以图形化的方式呈现游戏具体的行为、计算所需的时间以及每帧渲染的时长等等,包含所有可能会影响性能的数据。
使用该工具非常简单,只需点击图表本身(例如点击图表中的某个高峰)就可以查看该帧的详细计算数据。Unity会显示耗时最长的处理步骤。如果并不理解其中某个处理步骤的意义,也很容易在网上搜索来查找相关内容。
Unity Profiler 本身在编辑器环境下运行,并展示游戏运行的细节,但请注意,这里并不能反映出游戏的真实性能。由于Unity编辑器需要处理游戏本身以及额外的内容,因此此时的游戏运行速度会比构建之后的游戏慢一些。
Remote Profiler
使用Unity Profiler无法得知游戏运行的真实性能,所以需要在设备上运行游戏并进行分析。下面以Android设备为例,配置 Android SDK和JDK 后构建项目,然后就可以开始使用Remote Profiler了。
在Build Settings中(File > Build Settings)同时勾选 “Development Build” 和 “Autoconnect Profiler”,并确保 Editor Settings 设置中的 “Device” 一栏为 “Any Android Device”。
现在将设备连接到计算机并运行游戏。正常情况下Unity中会出现Profiler窗口,显示设备的运行状态。如果Profiler窗口未出现,则打开Profiler窗口,在 “Active Profiler” 下拉菜单中选择类似 “AndroidPlayer(ADB…)” 的条目,这个一般就是您的设备。
直接对设备本身进行分析可以更精确地获取游戏的性能数据,因此优先考虑这种方法。
选择设备作为“Active Profiler”
编辑器日志
另一种获取信息的方式是编辑器日志。游戏构建完毕后立刻打开Console窗口(Window > Console),在窗口的右上方有一个按钮,点击后选择 “Open Editor Log”。
此时系统会打开一个文档,其中包含很多构建相关的信息,特别是构建文件的大小以及资源占据的空间等。
在不同设备上进行测试
Android开发相当复杂,可能会出现很多问题。因为某个性能问题可能仅在某些设备上出现,而在另外一些设备上完全不是问题。因此应该在不同设备上测试游戏,从而避免此类问题,保证您的游戏能够在绝大多数设备上正常运行。
虽然等到项目开发后期再做优化这种想法很常见,但此时的性能问题可能已堆积成山。因此最好的做法是周期性地检测游戏,例如在每个里程碑达成时进行性能分析。这样随着游戏不断修改,需要进行的优化工作也会越来越少,也能越来越快地找到性能瓶颈所在。
脚本
搞定渲染优化这个大目标之前,应该先保证脚本不会出现问题。如果您是程序员,最好在把锅甩给美术之前先检查一下脚本是否有性能问题(哪怕真的是美术的锅!)
慎用Update
Unity初学者通常最大的误解在于过于依赖Update()函数。将所有内容都塞到Update()中确实是最容易的做法,例如检查某个状态并根据状态做出相应动作等,但如果场景中的每个GameObject都要在Update()里检查非常多的东西或进行复杂操作,就会大大影响游戏性能。
所以,在使用Update()之前,首先问一问自己,要实现的功能真的需要逐帧运行吗?
使用协程
如果不是必须逐帧运行,还可选择其他几种方式来实现。例如,可以利用协程(Coroutines)让某个方法每秒钟运行一次:“yield return new WaitForSeconds (1);”
可以用下面的方法刷新UI:
还可以每两帧调用一次方法来进行某种复杂计算,如下:
善用Events、Actions,响应式编程(Reactive Programming)
调用方法真正高效地方式是仅在需要时调用。例如当某个变量改变时、某个方法被调用时,或者某个事件发生并弹出UI菜单时等等。这就是响应式编程的基本原理,即利用Events,对某个事件作出反应。
在C#中您可以使用 委托 ,尤其是 Action委托 ,来创建事件。当事件发生时调用某个函数,然后由该函数去调用订阅了该事件的方法。
例如,创建 “玩家跳跃”事件,在代码中每当玩家跳跃时就会发起这个事件。例如某个方法生成了一些灰尘效果或者播放跳跃音效,将该方法订阅到“玩家跳跃”这个事件上,玩家跳起来时就会调用生成灰尘效果播放音效的方法。这仅仅是一种简单的应用,您还可以深入探究。
如果您对响应式编程有兴趣,可以参考 UniRx - Reactive Extensions 插件。这是为Unity设计的响应式编程拓展,支持LINQ异步及多线程、LINQ订阅到事件等等。
利用射线检测可触摸GameObject
在Unity中,除了UI之外并没有什么比较容易的办法来检测某个GameObject在屏幕上的点击。OnMouseDown() 函数对于移动平台并不生效。一种可行的方案是使用射线。从摄像机出发,以屏幕上手指点击的位置为方向。如果射线检测到某个对象则调用该对象的方法。
可以先定义一个Touchable类,一个Touchable层。触摸到某个对象时则调用下面的方法:
如果检测到触摸操作作用在带有Touchable的游戏对象上,则调用该对象的OnTouchDown()方法。
物理
检查脚本时一定要检查物理交互相关的代码(如果存在)。当然,移动设备上最好不要有此类代码,但如果无法避免,应特别注意以下几点:
动态刚体(Rigidbody)的数量越少越好,它们会大量消耗计算性能。
使用基础碰撞体,避免使用网格碰撞体,后者的计算处理要复杂得多。
尽量将“Collision Detection Mode” 设置为 “Discrete”,因为 “Dynamic” 会用掉更多的性能。
最后,可以在TimeManager窗口(Edit > Project Settings > Time)中设置 “Fixed Timestep” 的值。这个值表示两次FixedUpdate()调用之间的时间间隔。
游戏性能分析
Unity Profiler
建议使用Unity Profiler工具(Window > Profiler)来分析项目性能,该工具以图形化的方式呈现游戏具体的行为、计算所需的时间以及每帧渲染的时长等等,包含所有可能会影响性能的数据。
使用该工具非常简单,只需点击图表本身(例如点击图表中的某个高峰)就可以查看该帧的详细计算数据。Unity会显示耗时最长的处理步骤。如果并不理解其中某个处理步骤的意义,也很容易在网上搜索来查找相关内容。
![](http://forum.china.unity3d.com/data/attachment/forum/201709/03/195541wqm5zp55xryx65pe.jpg.thumb.jpg)
Unity Profiler 本身在编辑器环境下运行,并展示游戏运行的细节,但请注意,这里并不能反映出游戏的真实性能。由于Unity编辑器需要处理游戏本身以及额外的内容,因此此时的游戏运行速度会比构建之后的游戏慢一些。
Remote Profiler
使用Unity Profiler无法得知游戏运行的真实性能,所以需要在设备上运行游戏并进行分析。下面以Android设备为例,配置 Android SDK和JDK 后构建项目,然后就可以开始使用Remote Profiler了。
在Build Settings中(File > Build Settings)同时勾选 “Development Build” 和 “Autoconnect Profiler”,并确保 Editor Settings 设置中的 “Device” 一栏为 “Any Android Device”。
![](http://forum.china.unity3d.com/data/attachment/forum/201709/03/195558ytjk8fft5wtw444u.jpg.thumb.jpg)
现在将设备连接到计算机并运行游戏。正常情况下Unity中会出现Profiler窗口,显示设备的运行状态。如果Profiler窗口未出现,则打开Profiler窗口,在 “Active Profiler” 下拉菜单中选择类似 “AndroidPlayer(ADB…)” 的条目,这个一般就是您的设备。
直接对设备本身进行分析可以更精确地获取游戏的性能数据,因此优先考虑这种方法。
![](http://forum.china.unity3d.com/data/attachment/forum/201709/03/195640rm0ut9m0u09u230o.jpg.thumb.jpg)
选择设备作为“Active Profiler”
编辑器日志
另一种获取信息的方式是编辑器日志。游戏构建完毕后立刻打开Console窗口(Window > Console),在窗口的右上方有一个按钮,点击后选择 “Open Editor Log”。
此时系统会打开一个文档,其中包含很多构建相关的信息,特别是构建文件的大小以及资源占据的空间等。
![](http://forum.china.unity3d.com/data/attachment/forum/201709/03/195737punwc6rcbzrirxz1.jpg.thumb.jpg)
在不同设备上进行测试
Android开发相当复杂,可能会出现很多问题。因为某个性能问题可能仅在某些设备上出现,而在另外一些设备上完全不是问题。因此应该在不同设备上测试游戏,从而避免此类问题,保证您的游戏能够在绝大多数设备上正常运行。
虽然等到项目开发后期再做优化这种想法很常见,但此时的性能问题可能已堆积成山。因此最好的做法是周期性地检测游戏,例如在每个里程碑达成时进行性能分析。这样随着游戏不断修改,需要进行的优化工作也会越来越少,也能越来越快地找到性能瓶颈所在。
脚本
搞定渲染优化这个大目标之前,应该先保证脚本不会出现问题。如果您是程序员,最好在把锅甩给美术之前先检查一下脚本是否有性能问题(哪怕真的是美术的锅!)
慎用Update
Unity初学者通常最大的误解在于过于依赖Update()函数。将所有内容都塞到Update()中确实是最容易的做法,例如检查某个状态并根据状态做出相应动作等,但如果场景中的每个GameObject都要在Update()里检查非常多的东西或进行复杂操作,就会大大影响游戏性能。
所以,在使用Update()之前,首先问一问自己,要实现的功能真的需要逐帧运行吗?
使用协程
如果不是必须逐帧运行,还可选择其他几种方式来实现。例如,可以利用协程(Coroutines)让某个方法每秒钟运行一次:“yield return new WaitForSeconds (1);”
可以用下面的方法刷新UI:
![](http://forum.china.unity3d.com/data/attachment/forum/201709/03/195812w6doqledwqaoal4o.jpg.thumb.jpg)
还可以每两帧调用一次方法来进行某种复杂计算,如下:
![](http://forum.china.unity3d.com/data/attachment/forum/201709/03/195848t2m5arjtvjsmwjsj.jpg.thumb.jpg)
善用Events、Actions,响应式编程(Reactive Programming)
调用方法真正高效地方式是仅在需要时调用。例如当某个变量改变时、某个方法被调用时,或者某个事件发生并弹出UI菜单时等等。这就是响应式编程的基本原理,即利用Events,对某个事件作出反应。
在C#中您可以使用 委托 ,尤其是 Action委托 ,来创建事件。当事件发生时调用某个函数,然后由该函数去调用订阅了该事件的方法。
例如,创建 “玩家跳跃”事件,在代码中每当玩家跳跃时就会发起这个事件。例如某个方法生成了一些灰尘效果或者播放跳跃音效,将该方法订阅到“玩家跳跃”这个事件上,玩家跳起来时就会调用生成灰尘效果播放音效的方法。这仅仅是一种简单的应用,您还可以深入探究。
如果您对响应式编程有兴趣,可以参考 UniRx - Reactive Extensions 插件。这是为Unity设计的响应式编程拓展,支持LINQ异步及多线程、LINQ订阅到事件等等。
利用射线检测可触摸GameObject
在Unity中,除了UI之外并没有什么比较容易的办法来检测某个GameObject在屏幕上的点击。OnMouseDown() 函数对于移动平台并不生效。一种可行的方案是使用射线。从摄像机出发,以屏幕上手指点击的位置为方向。如果射线检测到某个对象则调用该对象的方法。
可以先定义一个Touchable类,一个Touchable层。触摸到某个对象时则调用下面的方法:
![](http://forum.china.unity3d.com/data/attachment/forum/201709/03/195908i599sffx7558m5n8.jpg.thumb.jpg)
如果检测到触摸操作作用在带有Touchable的游戏对象上,则调用该对象的OnTouchDown()方法。
物理
检查脚本时一定要检查物理交互相关的代码(如果存在)。当然,移动设备上最好不要有此类代码,但如果无法避免,应特别注意以下几点:
动态刚体(Rigidbody)的数量越少越好,它们会大量消耗计算性能。
使用基础碰撞体,避免使用网格碰撞体,后者的计算处理要复杂得多。
尽量将“Collision Detection Mode” 设置为 “Discrete”,因为 “Dynamic” 会用掉更多的性能。
最后,可以在TimeManager窗口(Edit > Project Settings > Time)中设置 “Fixed Timestep” 的值。这个值表示两次FixedUpdate()调用之间的时间间隔。
![](http://forum.china.unity3d.com/data/attachment/forum/201709/03/195925cc7byzypk172yebk.jpg.thumb.jpg)
所以Fixed Timestep值越小表示函数调用越频繁,从而获得更精确的模拟计算结果,代价则是消耗更多的资源。反之,该值越大越能降低处理物理相关数据所占用的时间,如果不需要特别精确的计算结果这也是一个很好的选择。
unity正版软件--官方指定代理广州元易qq微信2853068008