Unity游戏开发优化事项

此篇博客内容均根据Unity官方文档内容翻译并总结而来。官方文档的目录为:

UnityManual ---->Bset Practice Guide ----> Understanding Optimization in Unity ----> General Optimization  和 Special Optimization

用户可以自行对文档中的这部分内容进行查阅,这里对这几部分内容只做提炼和总结。


一般优化:

1. 使用Shader , Materail , Animator相关的API功能时,尽量使用它们的属性ID ,避免使用字符串。假如我们要设置一个Material的中某个shader属性的值时,尽量使用material.SetFloat(int nameID, float value) 这个API,少用material.SetFloat( string  name, float value) .


2.多使用不分配内存的API。 例子是: 使用RaycastNonAlloc 方法替代 RaycastAll  方法;使用SphereCastNonAlloc 方法替代 SphereCastAll 方法。


      3.Unity 在移动或旋转一个Transform的时候,往往会通知这个transform下所有子物体的tranform进行移动或旋转,所以尽量避免在每一帧多次对Transform进行操作。如果非操作不可,也尽量算出最后的Vector3的值,并只进行一次移动。 另外,在操作类似Charactor这些transform层级很深的对象时尤其应该主意,尽量使用角色的Animator系统来操作角色。


4.进行Vector3 或者 四元数 进行计算的时候,尽量注意计算的顺序。例如:

int a , b   ;    vector3 V;         a * V * b  的性能  会 低于  a * b *V


5. 执行Find 函数 和 FindGameObjectOfType 函数时,系统会遍历所有的Gameobjects 和components,随着项目的复杂,效率越来越低,因此要慎用。但是具体应该怎么去避免的话,应该是尽量缓存需要使用到的gameobject,不要经常在全局find其他的gameobject,通过代码去引用其他的gameobject,这是笔者自己的经验,官方文档并未给出建议的方法。


6.使用Camera.main 代码的时候会调用系统的Object.FindObjectWithTag函数,这也不是一个效率的方法,建议 在一个Start 或者OnEnable 方法中获取这个camera,然后缓存起来,或者建立一个自己的C amera管理类来管理游戏中的Camera。


7.封装游戏中自己的Debug类。并使用[Conditional] 属性。这样的话在发布release版本的时候,游戏中所有的debug相关代码就不会执行了,也不用删掉很多调试的代码。例子如下:

Public Static Logger{

[Conditional("ENABLE_LOGS")]

public void Debug(string logMsg) {

Debug.Log(logMsg);

}

}

只需要控制编译变量,就可以方便的控制整个工程的是否打印Log,很方便。


特殊优化:


8.代码中使用多维数组的时候,尽量使用Array[][]  的形式来替代 Array[ , ] 的形式。原因是后者会让编译器生成更多的中间代码,进行影响执行效率。


9.使用粒子系统时,它们通常会消耗3.5KB 的内存,而且这些内存会根据例子系统中所激活的模块而增加,并且就算将这个例子系统disable了,这些内存也不会释放,除非将这个粒子destroy掉。我们在游戏的运行中往往会使用大量的粒子系统,建议建立相应的数据结构对这些粒子系统进行有效的管理,进而降低这部分消耗,虽然这也挺费事的。。(其实不大懂官方文档这部分描述的意思)


10. 对Update 方法进行管理。Unity内部会维护一个列表,这个列表会收集内部所有活动的Update,并执行它们。而且unity还会在Monobehaviour被Disable或者Enable的时候分别 将它们的Update  进行移除或者加入。随着内部Update的数量越来越多,后面对update的移除或者添加操作的效率越来越低,因此建议建立自己的update管理单例类,或者使用c#的委托,并根据需要,将其他类的update订阅到这个类中。没有需要的时候再取消订阅,这样的操作会更有效率。

另外,使用c# 的委托时,如果在每一帧都会有大量的订阅或者取消订阅的这类的操作,且非常频繁的情况下,最好建立自己的数据结构去进行删除和插入操作,而不是使用委托。因为数组的插入和操作是比较低效率的,而链表则更方便来进行删除和插入操作。


11.加载资源时的线程管理。Unity的主线程和渲染线程是在ThreadPriority.Normal 优先级下的,如果有其他的加载资源的线程会高于等于主线程时,有可能会造成卡顿的现象,因为分摊了CPU的时间,因此在使用加载资源的API的时候,使用一些类的时候要注意。有一系列的异步加载资源的API都使用不同的线程优先级,这里我就不说了,具体可以去找Unity官方的原文档。我们这里只说对主线程有影响那个API,就是WWW.LoadFromCacheOrDownload,这个API会创建一个全新的线程,并且这个线程默认所使用的优先级和主线程是一样的,会对主线程造成影响。因此我们在使用这个API的时候要对它的线程优先级进行设置。 如果不理解线程优先级的概念,可以自行查阅相关资料。


12. 涉及到大量的物体运动的情形下,使用CullingGroups。具体内容可参考官方文档,我没有进行相关实践。


13.尽量减小方法调用所造成的开销。这部分属于写c#代码时应该注意的问题。具体不阐述,有兴趣可以自己看文档。


14.多使用系统默认的常量。例如Vector3.Zero 替代 new Vector3(0,0,0).定义常量时使用 static readonly关键词修饰。这些细节点也值得我们注意,虽然它们对于性能的影响非常小。

猜你喜欢

转载自blog.csdn.net/q568360447/article/details/78820181