If you’re looking to increase performance in Unity and improve the frame rate of your game, this is the right place. You’ll find a ton of tips and useful insights to finally achieve the so ambitious 60 frame per seconds in your game.
I started to gather information on how to improve the performance of my Unity games some time ago and I decided to share it with you. I suggest that you bookmark this article and come back sometime to check if there are some updates.
Also, if you want to share your tips and help other developers to increase performance in their games, please leave me a comment with your tips at the end of the article.Beginner part: how to start to increase the performance of your Unity game?
Let’s start with the basics. What should I do to improve the performance of my game?
The answer is:
- Analyze your game
- Analyze the profile data
- Make a change
- Profile the effect of that change
So, how can you analyze your game? Unity offers some instruments, like the amazing profiler, which will help you to understand what happens in each frame of your game.It’s a must to learn how to use the Profiler.
Before getting into the profiler, these are the common reasons that can make a single frame of your game slow:
- Trying to do too much (obvious)
- Bottlenecks
- CPU-bound: the CPU takes too long to execute his tasks.
- GPU-bound: the GPU takes too long to execute his tasks.
Let’s cut to the cheese and see how the Unity profiler can help us solve the problems above:
The profiler will tell you what is happening in every frame of your game and you must analyze that data to understand where the problems are.
Profiler tips: You should use the profiler not directly in the Unity editor because this can add unwanted information. Instead, profile your game directly from the build in order to have only the information strictly connected to the game. For example, if you’re making a mobile game, try to profile it directly from your mobile device in order to have the most accurate results.
When analyzing your game with the profiler, most of the time you can see exactly which function is taking too much time, and if you are the guy who wrote that function, try to understand what is causing the problems.
Otherwise, google it or ask on the web what part of your code is causing this behavior, and what are the common solutions to that problem.
Profiler tips: To gather even more information, you can turn on the deep profiler options which will give you information of what operations are slowing down the game. The downside is that the deep profiler only works in editor mode.
Unity API
Here are some tips to avoid the common overhead caused by the Unity API’s.
When you call an API that returns an array, you’re actually getting a new copy of that array and not a reference to it. So to improve the performance, use the appropriate API that avoids this behavior, like
- Input.GetTouch instead of Input.Touches
- Use non-allocating physics APIs instead of Physics.RaycastAll & e other “All” casts
- Instead of GetComponents and GetComponentsInChildren use a version of the API that accepts a pre allocated List<T>
In general, try to minimize calls that return Arrays
Materials
If you use a string to get or set properties like GetFloat, SetFloat, GetTexture, SetTexture, etc. on materials and shaders, that property will be hashed (the string will be mapped into an integer). Instead, directly use an integer ID to access them.
An example of a correct usage of integer ID:
For the properties that use string-methods like Material.color, Material.mainTexture etc., you have two solutions:
- Use the standard method, example:
- Material.GetColor, Material.SetColor
- Get a cache property id yourself:
- Property name: “_Color.”
Camera!!
Camera.main actually calls Object.findGameObjectWithTag”MainCamera” every single time you call it. So, you should store a reference to the camera and use that instead.
Increase Performance in Unity by Optimizing the data structures
Use the appropriate data structure,
- If you iterate a lot through a List, use an Array instead.
- If you need to constantly add or remove objects, use a Dictionary or an HashSet
- If you’re mostly indexing by keys, use a Dictionary
- Iterating through a HashTable or a Dictionary is expensive because the compiler has to check all the elements, instead use a struct or a tuple, and store a list or an array of that struct or that tuple.
When choosing a data structure to use in our update system, we may have concerns about which one is the best to use. With that, here are some data structures recommended for certain scenarios:
- Won’t allow duplicates
- Dictionary or HashSet ( we can have character run twice as fast)
- Constant-time insertion
- List, Dictionary, HashSet
- Need low-overhead iteration
- Array or List
The problem is that there is no data structure that would meet all the 3 requirements. The solution is to use two of them. You can use a List for iteration and a Dictionary to perform a check before changing the list. If removal is your concern, you can use a linked list or an intrusive-linked list.
The downside is that it has higher memory cost because we have to maintain two data structures instead of one.
Comparing objects in dictionaries:
If you use the default comparer Object.Equals, keep in mind that this will cause a call to the UnityEngine.Object.ComparerBaseObject that in turn, will also call the C# method Object.ReferenceEquals. All of these calls will cause a little overhead in the system. You can use the UnityID property, which is unique to every GameObject: myobject.GetInstaceID().
Method call overhead
Every time you call a method in C#, there is a small amount of overhead involved to maintain the variables and the pointers in the stack. Usually the cost of this operation is very small, but if the method is called thousands of times per seconds, then there is a chance to introduce a significant overhead. Instead, we can use inline functions.
What the inline operator does is basically, cut the body of that method and paste it where the method is called.
In C# we can ask the compiler to use an inline function with the following signature:
This will work only if you use the new 4.6.NET runtime version.
Accessing and settings properties
public int MyProperty { get; set; } should be converted into a public field:
public int MyProperty;
Increase your unity game performance by fixing the Unity UI
The Unity UI system can have a huge impact on the performance of your game and here is why:
The canvas generates the mesh and draws them.
The drawing of the canvas happens once per frame but the generation happens when something changes. Changes means even small modifications in a single UI element in the entire canvas. For example, applying a change to a single text in the UI, will force to regenerate the whole canvas.
Another thing to keep in mind when using the Unity UI system is that when the canvas is generated, all the vertices for all the meshes on the screen will be generated, even those where the alpha is set to zero or even the ones that are not on the screen.
So, the simplest solution to this problem is to divide your big canvas into multiple canvases and try to group them based on when they get updated. For example, if there are 2 elements that need to be updated at the same time, put them together on the same canvas.
UI Tips: If you have dynamic UI elements like a Scroll Rect with a lot of elements to visualize, a good practice is to turn off the pixel perfect check box on the canvas that contains the list and disable the items that aren’t visible on the screen.
UI Tips: Another best practice is to clamp the scroll velocity. That’s because even when the scroll has finished, Unity continues to move the rest view for 3/400 pixel and this will still invalidate the canvas. A good solution is to clamp the scroll velocity to something like 0.1 in order to avoid this problem.
UI Tips: If there are elements that are not interactive, remember to turn off the raycast target checkbox
UI Tips: Always assign a world camera to the canvas. Otherwise, Unity will be looking for the main camera at every frame.
Limit the camera visible frustum and select the blocking mask to cast against 2D/3D geometry.
Unity Layouts
Layout elements are also Images, ScrollRect, layout groups (vertical and horizontal) etc.
But what marks the layout as dirty?
- OnEnable or OnDisable
- Reparenting
- Twice, once for old parent and once for new parent
- OnDidApplyAnimatiomProperties
- OnRectTransformDimensionsChanged
- Resizing
- Basically everything
Possible Solutions:
UI Tips: Don’t use animations on UI because animations will dirty their elements every frame. If you need an animation, use your own code or a tweening system, use UI animations only on events that really need to be animated every frame, otherwise, if the animation has to occur only a few times, use other systems.
Use Static Batching
Static Batching allows you to reduce the number of draw calls in your game, which reduces CPU cycles.
To use static batching, the Unity GameObject must be marked as “Static”. Note that this could be possible only in objects never move. E.g terrain, buildings etc.
Use object pooling to increase the performance of your game
Of course, we couldn’t go away without speaking about Object pooling. This is one of the most used best practice to avoid overhead in your game and drastically increase the performance of it.
If you want to know more, here is a full article about object polling. But remember to adopt this technique every time you can in your Unity Games.
Improve the performance in Unity conclusion.
As you have seen, there are a lot of solutions to improve the performance of your Unity game. But if I can give you one last advice, build games takes a lot of time and efforts, so instead of writing perfect code and waste a lot of time, make your game first and then optimize it if necessary, in fact maybe your game will just run at 60 FPS “out of the box” without have to adopt any of this solutions.
One last important thing, if this article was helpful to you, please share it. It will only take a few seconds of your time but it means a lot to me. Thank you!