Optimize Your Games In Unity – The Ultimate Guide
November 5, 2021
Important Information Before We Start
Always Cache Your Components
and then in Awake get a reference to that variable
I know that we can also use the Start function for this purpose, even the OnEnable function, but I used the Awake function for this example because the Awake function is the first initialization function that is called when the game starts, and if I want to get a reference to variables or initialize variables I always do it in the Awake function as that will be the first thing that will be executed and then the game can start normally.
After that you can safely apply force to your Rigidbody variable:
Caching Components VS SerializeField
There is another way how we can get a reference to cached variables and that is by adding the SerializeField keyword above the variable declaration:
This will expose the variable in the Inspector tab and we can now drag the game object itself providing that it has the desired component attached on it, in the exposed variable field to get a reference to it:
Now which of the two methods is more optimized, the answer is SerializeField. Because you don’t need to use code to get a reference to the desired component, and this is very effective especially if you have a lot of game objects such as enemies or collectable items that need to get a certain component when they are spawned.
Now there will be times where you need to get a reference to a component via code, but whenever you can, try to get a reference to the component of a game object by using SerializeField and attaching the desired component in the appropriate slot in the Inspector tab.
Cache Your Non-Component Variables As Well
This is also a rule for any other variable types. It is always better to do
than
Don’t Use Camera.main
Avoid Repeated Access to MonoBehaviour Transform
Another thing that you need to be careful of is reusing the transform property of MonoBehaviour. This internally calls GetComponent to get the Transform component attached on the game object.
Again, the solution for this is to cache the transform variable:
Optimizing Strings
This is not the way to go. When you are checking the tag of the collided game object it is better to use CompareTag function
Another common mistake is when declaring an empty string people usually write:
A better way is to use string.Empty:
Strings And Text UI
When using strings and text UI you need to be careful when you are updating the text often, especially if that happens in the Update function.
This is something a lot of people do with timers, the usually write code that looks like this:
While this looks like a very simple operation, it is going to slow down your game significantly, especially a mobile.
The reason for that is because a string is an object type variable. Every time you concatenate a string like you see in the line 9 in the code above, you create a new object.
Now imagine doing this in the Update function which is called every frame. You are creating a new object that is stacked up memory every single frame and this is something mobile devices can’t handle.
The solution is to use StringBuilders.
Avoid Using Instantiate Function During Gameplay
When it comes to Instantiate function, which creates a copy of the provided prefab, you will find different opinions online. The majority say don’t use Instantiate during gameplay.
This is somewhat true. I say somewhat because I’ve used Instantiate during gameplay in one of my mobile games and when I profiled the game it was running smoothly never going below 60 FPS.
This goes to show that you should always revert back to the Profiler and the stats you see there.
That being said, it is always a better idea to use the pooling technique instead of relying on Instantiate, especially if you are spawning bullets, collectable items or any other game element that is often spawned in the game.
But sometimes there will be situations where you simply need to use Instantiate as that is the shortest solution, and there is no harm in using it if you see that the Profiler is not showing any issues, so keep that in mind.
Remove Empty Callback Functions
As you already know, Awake, Start, and OnEnable initialization functions are called when the game object is spawned.
Update and LateUpdate are called every frame and LateUpdate is called every fixed frame rate.
The issue with these functions is that they will be called even if they are empty because Unity doesn’t know that these functions are empty e.g. they don’t have any code inside.
As you saw from the example, just by having empty Start and Update functions in the class the spike on the Profiler skyrocketed when we created objects which had that class attached to them.
When Raycasting Use Zero Allocation Code
Avoid using raycast code that allocates memory. All raycast functions have their non memory allocation version: