The following tips are not meant to be absolutes but rather guidelines for Unity users that want to learn how to make a well-performing game.
Profiler First. There is no such thing as a list of boxes to check that will ensure your project runs smoothly. Don’t spend time trying to optimize some obscure code or reducing the size of a texture unless you know it is a bottleneck. To optimize a slow project, you have to profile to find where the bottlenecks are that take up a disproportionate amount of time. Trying to optimize without profiling or without thoroughly understanding the results that the profiler gives is like trying to optimize with a blindfold on.
Are you using the right algorithm? Selecting the right algorithm for a task yields much better optimization than any other code tweaking you might do. Note that the best algorithm is not always the one with the lowest average complexity. For small data-sets, it is often better to use a slow algorithm with a small setup cost than a smart one with high initialization cost.
Avoid Memory allocation. Every time an object is created, memory is allocated. Very often in code, you are creating objects without even knowing it.
Use Object Pooling instead of Instantiate and Destroy. You may have made games in the past that created and destroyed a lot of items (such as bullets or enemies). What you may not have known is that the act of instantiating and destroying are inefficient and can slow your projects down. So using object pooling for ephemeral objects is faster than creating and destroying them, because it makes memory allocation simpler and removes dynamic memory allocation overhead and Garbage Collection, or GC.
Keep your FixedUpdate functions as lean as possible. These functions can get called around 50-100 times a second per applicable script per object, so they are a good target to optimize. If there are things that need to be only done when the display is updated, put that code inside the Update function.
If possible, disable scripts on objects when they are not needed. If you have a large level in your game and there is an enemy kilometers away, you can probably switch off its AI script until the camera gets closer. A good way to switch on and off objects is by using gameObject.SetActiveRecursively(false) and sphere or box colliders set as triggers.
Beware the empty Update functions. When creating new scripts with the Assets menu, they include an empty Update() function. Remove it if you don’t need it as it comes at a (rather light) performance cost. This performance cost applies to all overridable functions in MonoBehaviour scripts, with Update and FixedUpdate being the main targets.
Refer to a GameObject by the most logical component. One could theoretically write: someGameObject.transform.gameObject.rigidbody.transform.gameObject.rigidbody.transform, but there is a whole lot of needless work done there. If you want to deal with an object’s Transform, refer to it in your script as such in the first place.
Don’t use methods which search for objects any more than is necessary. This includes methods such as GameObject.FindByTag() and GameObject.GetComponent(), as well as all the component convenience properties (transform, light, etc.). These methods are optimised to operate as quickly as possible, but they still have to search through all the relevant objects to find the one you want. The most important thing is to avoid calling search methods repeatedly in Update() or FixedUpdate(). Instead, call the method once, store its result in a member variable of your class, and then use the member variable to access it the next time you need it.
Don’t use SendMessage() (or similar functions) if you don’t have to.SendMessage() is at least 100 times slower than calling a function directly, and this number increases as more scripts and functions are available on the object. If you can find the script you need ahead of time, do so and then call the function directly.
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.
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
t>
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.
using UnityEngine; using System.Collections; public class example : MonoBehaviour { public Transform target; void Update() { if (Vector3.Distance(transform.position, target.position) > 100) return; } }
Best solution is to use Triggers and OnBecomeVisible & OnBecomeInvisible.
Coroutines are your friends. Coroutines have only a tiny overhead and can be preferable to an Update method that is called all the time needlessly. For example, if you had a script to fade in and out a light on command, you could do the fading in a coroutine instead of in Update. That way, most of the time when the light is not fading, the script takes a minimum amount of performance. If the fading was done in the Update function, you would be inefficiently polling to see if there is fading to be done.
That’s about everything I’ve got. If anyone has anything else in scripting optimization I’d love to hear it!
Sources: unity3d.com, wiki.unity3d.com, image taken from here.