1. 尽可能避免每帧处理html
比方:数组
function Update() { DoSomeThing(); }缓存
可改成每5帧处理一次:函数
function Update() { if(Time.frameCount % 5 == 0) { DoSomeThing(); } }布局
2. 定时反复处理用 InvokeRepeating 函数实现性能
比方。启动0.5秒后每隔1秒运行一次 DoSomeThing 函数:优化
function Start() { InvokeRepeating("DoSomeThing", 0.5, 1.0); }3d
3. 优化 Update, FixedUpdate, LateUpdate 等每帧处理的函数orm
函数里面的变量尽可能在头部声明。htm
比方:
function Update() { var pos: Vector3 = transform.position; }
可改成
private var pos: Vector3; function Update(){ pos = transform.position; }
4. 主动回收垃圾
给某个 GameObject 绑上下面的代码:
function Update() { if(Time.frameCount % 50 == 0) { System.GC.Collect(); } }
5. 执行时尽可能下降 Tris 和 Draw Calls
预览的时候,可点开 Stats,查看图形渲染的开销状况。
特别注意 Tris 和 Draw Calls 这两个參数。
通常来讲,要作到:
Tris 保持在 7.5k 下面
Draw Calls 保持在 20 下面
6. 压缩 Mesh
导入 3D 模型以后,在不影响显示效果的前提下,最好打开 Mesh Compression。
Off, Low, Medium, High 这几个选项,可酌情选取。
7. 避免大量使用 Unity 自带的 Sphere 等内建 Mesh
Unity 内建的 Mesh,多边形的数量比較大,假设物体不要求特别圆滑。可导入其它的简单3D模型取代。
8. 优化数学计算
比方。假设可以避免使用浮点型(float),尽可能使用整形(int),尽可能少用复杂的数学函数比方 Sin 和 Cos 等等
下降固定增量时间
将固定增量时间值设定在0.04-0.067区间(即,每秒15-25帧)。您可以经过Edit->Project Settings->Time来改变这个值。这样作减小了FixedUpdate函数被调用的频率以及物理引擎运行碰撞检測与刚体更新的频率。假设您使用了较低的固定增量时间,并且在主角身上使用了刚体部件。那么您可以启用插值办法来平滑刚体组件。
下降GetComponent的调用
使用 GetComponent或内置组件訪问器会产生明显的开销。您可以经过一次获取组件的引用来避免开销,并将该引用分配给一个变量(有时称为"缓存"的引用)。
好比。假设您使用例如如下的代码:
function Update () {
transform.Translate(0, 1, 0);
}
经过如下的更改您将得到更好的性能:
var myTransform : Transform;
function Awake () {
myTransform = transform;
}
function Update () {
myTransform.Translate(0, 1, 0);
}
避免分配内存
您应该避免分配新对象。除非你真的需要。因为他们再也不在使用时,会添加垃圾回收系统的开销。
您可以经常反复使用数组和其它对象,而不是分配新的数组或对象。
这样作优势则是尽可能下降垃圾的回收工做。同一时候,在某些可能的状况下,您也可以使用结构(struct)来取代类(class)。这是因为,结构变量主要存放在栈区而非堆区。
因为栈的分配较快,并且不调用垃圾回收操做,因此当结构变量比較小时可以提高程序的执行性能。
但是当结构体较大时。尽管它仍可避免分配/回收的开销。而它因为"传值"操做也会致使单独的开销,实际上它可能比等效对象类的效率还要低。
最小化GUI
使用GUILayout 函数可以很是方便地将GUI元素进行本身主动布局。然而,这样的本身主动化天然也附带着必定的处理开销。您可以经过手动的GUI功能布局来避免这样的开销。
此外,您也可以设置一个脚本的useGUILayout变量为 false来全然禁用GUI布局:
function Awake () {
useGUILayout = false;
}
使用iOS脚本调用优化功能
UnityEngine 命名空间中的函数的大多数是在 C/c + +中实现的。从Mono的脚本调用 C/C++函数也存在着必定的性能开销。您可以使用iOS脚本调用优化功能(菜单:Edit->Project Settings->Player)让每帧节省1-4毫秒。此设置的选项有:
Slow and Safe – Mono内部默认的处理异常的调用
Fast and Exceptions Unsupported –一个高速运行的Mono内部调用。只是。它并不支持异常,所以应慎重使用。它对于不需要显式地处理异常(也不需要对异常进行处理)的应用程序来讲,是一个理想的候选项。
优化垃圾回收
如上文所述,您应该尽可能避免分配操做。
但是,考虑到它们是不能全然杜绝的,因此咱们提供两种方法来让您尽可能下降它们在游戏执行时的使用:
假设堆比較小。则进行高速而频繁的垃圾回收
这一策略比較适合执行时间较长的游戏,当中帧率是否平滑过渡是基本的考虑因素。像这种游戏通常会频繁地分配小块内存,但这些小块内存仅仅是临时地被使用。
假设在iOS系统上使用该策略,那么一个典型的堆大小是大约 200 KB。这样在iPhone 3G设备上。垃圾回收操做将耗时大约 5毫秒。假设堆大小添加到1 MB时,该回收操做将耗时大约 7ms。所以。在普通帧的间隔期进行垃圾回收有时候是一个不错的选择。一般,这种作法会让回收操做执行的更加频繁(有些回收操做并不是严格必须进行的),但它们可以高速处理并且对游戏的影响很是小:
if (Time.frameCount % 30 == 0)
{
System.GC.Collect();
}
但是。您应该当心地使用这样的技术,并且经过检查Profiler来确保这样的操做确实可以减小您游戏的垃圾回收时间
假设堆比較大,则进行缓慢且不频繁的垃圾回收
这一策略适合于那些内存分配 (和回收)相对不频繁,并且可以在游戏停顿期间进行处理的游戏。假设堆足够大,但尚未大到被系统关掉的话。这样的方法是比較适用的。但是,Mono执行时会尽量地避免堆的本身主动扩大。所以,您需要经过在启动过程当中预分配一些空间来手动扩展堆(ie,你实例化一个纯粹影响内存管理器分配的"无用"对象):
function Start() {
var tmp = new System.Object[1024];
// make allocations in smaller blocks to avoid them to be treated in a special way, which is designed for large blocks
for (var i : int = 0; i < 1024; i++)
tmp[i] = new byte[1024];
// release reference
tmp = null;
}
游戏中的暂停是用来对堆内存进行回收。而一个足够大的堆应该不会在游戏的暂停与暂停之间被全然占满。因此。当这样的游戏暂停发生时。您可以显式请求一次垃圾回收:
System.GC.Collect();
另外,您应该慎重地使用这一策略并时刻关注Profiler的统计结果,而不是假定它已经达到了您想要的效果。