Overview: Performance Optimization
Scripting
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.

var foo = 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.

function Start ()
{
var foo = GetComponent(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.

function Start ()
{
var foo : MyScript = GetComponent(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:

#pragma strict
function Start ()
{
var foo = GetComponent(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:

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

Into this:

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

function 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 aligned.

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

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 aligned.

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

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:

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

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.

function OnBecameVisible () {
enabled = true;
}

function 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

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

function OnTriggerExit (c : 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.