Overview: Performance Optimization

1. Use Static Typing

When using JavaScript the most important optimization is to use static typing instead of dynamic typing. Unity uses a technique called type inference to automatically convert JavaScript constructs to statically typed code without you having to do any work.

JavaScript
var foo = 5;

using UnityEngine;
using System.Collections;

public class example : MonoBehaviour {
public int foo = 5;
}

import UnityEngine
import System.Collections

class example(MonoBehaviour):

public foo as int = 5

In the above example foo will automatically be inferred to be an integer value. Thus Unity can apply a lot of compile time optimizations, without costly dynamic name variable lookups etc. This is one of the reasons why Unity's JavaScript is on average around 20 times faster than other JavaScript implementations.

The only problem is that sometimes not everything can be type inferred, thus Unity will fall back to dynamic typing for those variables. By falling back to dynamic typing, writing JavaScript code is simpler. However it also makes the code run slower.

Let's see some examples.

JavaScript
function Start () {
var foo = GetComponent(MyScript);
foo.DoSomething();
}

using UnityEngine;
using System.Collections;

public class example : MonoBehaviour {
void Start() {
MyScript foo = GetComponent<MyScript>();
foo.DoSomething();
}
}

import UnityEngine
import System.Collections

class example(MonoBehaviour):

def Start():
foo as MyScript = GetComponent[of MyScript]()
foo.DoSomething()

Here foo will be dynamically typed, thus calling the function DoSomething takes longer than necessary - because the type of foo is unknown, it has to figure out whether it supports DoSomething function, and if it does, invoke that function.

JavaScript
function Start () {
var foo : MyScript = GetComponent(MyScript);
foo.DoSomething();
}

using UnityEngine;
using System.Collections;

public class example : MonoBehaviour {
void Start() {
MyScript foo = GetComponent<MyScript>();
foo.DoSomething();
}
}

import UnityEngine
import System.Collections

class example(MonoBehaviour):

def Start():
foo as MyScript = GetComponent[of MyScript]()
foo.DoSomething()

Here we're forcing foo to be of specific type. You will get much better performance.

2. Use #pragma strict

Now the problem is of course, that you don't usually notice when you are using dynamic typing. #pragma strict to the rescue! Simply add #pragma strict at the top of a script and Unity will disable dynamic typing in that script, forcing you to use static typing. Wherever a type is not known, Unity will report compile errors. So in this case, foo will produce an error when compiling:

JavaScript
#pragma strict
function Start () {
var foo : MyScript = GetComponent(MyScript) as MyScript;
foo.DoSomething();
}

using UnityEngine;
using System.Collections;

public class example : MonoBehaviour {
void Start() {
MyScript foo = GetComponent<MyScript>() as MyScript;
foo.DoSomething();
}
}

import UnityEngine
import System.Collections

class example(MonoBehaviour):

def Start():
foo as MyScript = GetComponent[of MyScript]()
foo.DoSomething()

3. Cache component lookups

Another optimization is caching of components. This optimization unfortunately requires a bit of coding effort and is not always worth it. But if your script is really used a lot and you need to get the last bit of performance out of it, this can be a very good optimization.

Whenever you access a component through GetComponent or an accessor variable, Unity has to find the right component from the game object. This time can easily be saved by caching a reference to the component in a private variable.

Simply turn this:

JavaScript
function Update () {
transform.Translate(0, 0, 5);
}

using UnityEngine;
using System.Collections;

public class example : MonoBehaviour {
void Update() {
transform.Translate(0, 0, 5);
}
}

import UnityEngine
import System.Collections

class example(MonoBehaviour):

def Update():
transform.Translate(0, 0, 5)

Into this:

JavaScript
private var myTransform : Transform;
function Awake () {
myTransform = transform;
}

function Update () {
myTransform.Translate(0, 0, 5);
}

using UnityEngine;
using System.Collections;

public class example : MonoBehaviour {
private Transform myTransform;
void Awake() {
myTransform = transform;
}
void Update() {
myTransform.Translate(0, 0, 5);
}
}

import UnityEngine
import System.Collections

class example(MonoBehaviour):

private myTransform as Transform

def Awake():
myTransform = transform

def Update():
myTransform.Translate(0, 0, 5)

The latter code will run a lot faster since Unity doesn't have to find the transform component in the game object each frame. The same applies for scripted components, where you use GetComponent instead of the transform or other shorthand property.

4. Use Builtin arrays

Builtin arrays are fast, very fast, so use them.

While the ArrayList or Array classes are easier to use since you can easily add elements they don't have nearly the same speed. Builtin arrays have a fixed size but most of the time you know the maximum size in advance and can just fill it out later. The best thing about builtin arrays is that they directly embed struct data types in one tightly packed buffer, without any extra type information or other overhead. Thus iterating through is very easy on the cache as everything is linear in memory.

JavaScript
private var positions : Vector3[];
function Awake () {
positions = new Vector3[100];
for (var i = 0; i < 100; i++)
positions[i] = Vector3.zero;
}

using UnityEngine;
using System.Collections;

public class example : MonoBehaviour {
private Vector3[] positions;
void Awake() {
positions = new Vector3[100];
int i = 0;
while (i < 100) {
positions[i] = Vector3.zero;
i++;
}
}
}

import UnityEngine
import System.Collections

class example(MonoBehaviour):

private positions as (Vector3)

def Awake():
positions = array[of Vector3](100)
i as int = 0
while i < 100:
positions[i] = Vector3.zero
i++

5. Don't call a function if you don't have to

The simplest and best of all optimizations is to perform less work. For example , when an enemy is far away it is most of the time perfectly acceptable to have the enemy fall asleep. That is do nothing until the player comes close. The slow way of handling this situation would be:

JavaScript
var target : Transform;

function Update () {
// Early out if the player is too far away.
if (Vector3.Distance(transform.position, target.position) > 100)
return;
// perform real work work...
}

using UnityEngine;
using System.Collections;

public class example : MonoBehaviour {
public Transform target;
void Update() {
if (Vector3.Distance(transform.position, target.position) > 100)
return;

}
}

import UnityEngine
import System.Collections

class example(MonoBehaviour):

public target as Transform

def Update():
if Vector3.Distance(transform.position, target.position) > 100:
return

This is not a good idea since Unity has to invoke the update function and you are performing work every frame. A better solution is to disabling the behaviour until the player comes closer. There are 3 ways to do this: 1. Use OnBecameVisible and OnBecameInvisible. These call backs are tied into the rendering system. As soon as any camera can see the object, OnBecameVisible will be called, when no camera sees it anymore OnBecameInvisible will be called. This is useful in some cases, but often for AI it is not useful because enemies would become disabled as soon as you turn the camera away from them.

JavaScript
function OnBecameVisible () {
enabled = true;
}

function OnBecameInvisible () {
enabled = false;
}

using UnityEngine;
using System.Collections;

public class example : MonoBehaviour {
void OnBecameVisible() {
enabled = true;
}
void OnBecameInvisible() {
enabled = false;
}
}

import UnityEngine
import System.Collections

class example(MonoBehaviour):

def OnBecameVisible():
enabled = true

def OnBecameInvisible():
enabled = false

2. Use triggers. A simple sphere trigger can work wonders though. You get OnTriggerEnter/Exit calls when exiting the sphere of influence you want

JavaScript
function OnTriggerEnter (c : Collider) {
if (c.CompareTag("Player"))
enabled = true;
}

function OnTriggerExit (c : Collider) {
if (c.CompareTag("Player"))
enabled = false;
}

using UnityEngine;
using System.Collections;

public class example : MonoBehaviour {
void OnTriggerEnter(Collider c) {
if (c.CompareTag("Player"))
enabled = true;

}
void OnTriggerExit(Collider c) {
if (c.CompareTag("Player"))
enabled = false;

}
}

import UnityEngine
import System.Collections

class example(MonoBehaviour):

def OnTriggerEnter(c as Collider):
if c.CompareTag('Player'):
enabled = true

def OnTriggerExit(c as Collider):
if c.CompareTag('Player'):
enabled = false

3. Use Coroutines. The problem with Update calls is that they happen every frame. Quite possibly checking the distance to the player could be performed only every 5 seconds. This would save a lot of processing power.