Unity C# Performance Cheat Sheet

Feel free to add suggestions as comments

Math:

  • If multiplying vectors and floats, make sure the vectors are the LAST parameters

    • Consider v = Vector3(a,b,c):

    • If your multiplication looks like: v * speed * Time.deltaTime, the operation is broken down into:

      • a) v = v * speed (or v.a * speed, v.b * speed, v.c * speed)

      • b) v = v * Time.deltaTime (or v.a * Time.deltaTime, v.b * Time.deltaTime, b.c * Time.deltaTime);

      • This results in 6 multiplications

    • If you reorder it to: speed * Time.deltaTime * v, it looks like this:

      • a) newSpeed  =  speed * Time.deltaTime

      • b) (a * newSpeed, b * newSpeed, c * newSpeed)

      • This results in 4 multiplications

  • When comparing distances, use Vector3.sqrMagnitude, and check against (target distance)^2

    • Vector3.Distance uses the square root function, which is very processing intensive. By comparing sqrMagnitude against your target distance at the power of two, you’re essentially doing the same thing, except with no calls to Square Root

  • Avoid doing Vector Math

Unity:

  • Avoid calling transform (cache transform refs)

    • Any calls to Unity native code has to go through mono or IL2CPP, and that’s not good for performance. Find out more by watching this

  • Avoid using transform.position. Use transform.localPosition instead

    • Using transform.position loops through each parent transform recursively and applies the offsets so you get the worldPosition of something. LocalPosition does not. Find out more by watching this

  • Avoid engine calls (Time.deltaTime). Cache the values instead

    • Any calls to Unity native code has to go through mono or IL2CPP, and that’s not good for performance. Find out more by watching this

  • Don't call Play on a particle system with the withChildren parameter set to true.

    • This does recursive GetComponent calls. Cache all children ParticleSystems and call Play on each one. Find out more by watching this

  • Don't use Camera.main

    • Internally this is just a FindObjectWithTag

  • Break down your UI into multiple Canvases, ideally separating static UI elements into a dedicated static Canvas

    • The canvas rebuilds ALL of its children every time a UI element is updated. By separating static from animated objects, you avoid having to rebuild something that did not change

  • Don’t use the Animator to animate UI elements.

    • The animator updates properties of animated objects every frame, triggering a new Canvas rebuild. Write custom tweens instead, that run through code

  • Cache results from native properties that return an Array (ex.: Mesh.vertices)

    • Usually, a native property that returns an array will actually create (allocate) a new array, with the values copied from the original. For that reason, calling it only once per use avoids multiple allocations that will generate Garbage.

  • (5.5 or older) Don’t use foreach

    • In Unity, a foreach generates garbage because of boxing. Find out more here.

  • When assigning Animator parameters, don’t use strings for variable names

    • The Animator gives you the option of setting a parameter by ID. Cache the IDs, and use them instead, in order to prevent frequent string comparisons. You can find the ID by calling Animator.StringToHash(variable name);

C#

  • Don't iterate over Dictionaries or HashSets, iterate over Lists or Arrays

    • Find out more by watching this

  • Whenever possible, use ints or other built in types as Dictionary keys

    • Find out more by watching this

  • Cache results from List.ToArray()

    • Any IEnumerable.ToArray() call will create (allocate) a new array, with the values copied from the original. For that reason, calling it only once per use avoids multiple allocations that will generate Garbage.

Leave a Comment

Your email address will not be published. Required fields are marked *