1.MonoBehaviour的细节优化
在MonoBehaviour中,如果没有相应的事件要处理,请删除默认的空函数
Update、FixedUpdate、LateUpdate中,如果没必要每帧的逻辑,可以降低频率,例如:
Void Update(){
if(Time.frameCount%6==0){
DoSomething();
}
}
如果间隔更长,没必要每帧的逻辑,使用周期性的协程更妥当,例如:
InvokeRepeating("DoSomeThing",0.5f,1.0f);
Gameobject不可见时,设置 enabled = false 时,update 就会停止调用。
在update 中尽量不要调用查找对象或组件方法如 FindByTag 或Find 等等,可以在start中获得引用,然后使用。
2.协程会产生GC
使用 yield return new WaitForSeconds() 将会每帧导致 21Byte GC,而yield return null 会产生 9 Byte GC。
所以因为GC问题,所以不推荐使用协程,Invoke或 StartCoroutine。
3.Transform细节优化
Transform在初始化时,使用内建的数据,如 Vector3.zero 而不是 new Vector(0, 0, 0),
transform.localRotation = Quaternion.Euler(Vector3.zero);
transform.localScale =Vector3.one;
transform.localPosition =Vector3.one;
4.GameObject 细节优化
缓存Gameobject,在脚本挂载对象引用,可减少查找。
缓存组件,调用 GetComponent 函数有查找开销,用变量挂载到脚本使用,降低开销(GetComponent时如果获取到空的组件也会产生GC)。
查找对象标签用if (go.CompareTag (“xxx”)来代替if (go.tag == “xxx”)。GameObject.tag会在内部循环调用对象分配的标签属性,并分配额外的内存,并且效率也更低。
SendMessage,BroadcastMessage,SendMessageUpwards,少用这三个函数,因为它们的实现是一种伪监听者模式,利用的是反射机制,性能非常低。具体的性能大概是委托的十分之一,建议使用委托代替。
5.优化数学运算
尽量采用整型代替浮点型,除法改乘法。例如:
float a = 2.0 如果精度允许改为 int a = 2
a/2,改为a*0.5
巧用位操作,代替2的倍数的,整乘整除。例如:
int a = 100 >> 1 相当于除2取整 结果为 50
int a = 100 >> 2 相当于除4取整 结果为 25
int a = 100 << 1 相当于乘2取整 结果为 200
int a = 100 << 2 相当于乘4取整 结果为 400
在运算操作时,能整不浮,能乘不除。而位操作是操作符比传统乘除效率要高,适合大量计算时使用。
同时位操作符,还可用来取整操作,更多技巧以后独立开篇具体说明。
6.遍历数组的技巧
在遍历数组时,我们会用到Length属性。很多人不知道的是这个属性其实是会动态计算数组的长度的。
举个栗子:
int[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9};
int a;
const int count = 10000000;
Stopwatch sw = new Stopwatch();
sw.Start();
for (int j = 0; j < count; j++)
{
for (int i = 0; i < arr.Length; i++)
a = arr[i];
}
sw.Stop();
Debug.Log("time1:" + sw.ElapsedMilliseconds);
sw.Reset();
int len = arr.Length;
for (int j = 0; j < count; j++)
{
for (int i = 0; i < len; i++)
a = arr[i];
}
sw.Stop();
Debug.Log("time2:" + sw.ElapsedMilliseconds);
time2是将arr.Length缓存到len里的耗时。下面是具体的耗时图:
可以得知,当循环数量很大时,数组获取Length的开销还是挺大的,并且数组越大耗时也越大。希望大家不要忽视这个细节。
网友评论