Develop, Debug, and Optimize Unity Mobile Games for Maximum Performance
For Programmers
As a programmer, you want to achieve the fastest performing, highest quality games that do not overheat and that run smoothly without bugs.
There are a wide range of methods that you can use, reduce, remove, or avoid to improve the performance of your games on the Unity platform. All involve lowering the processing load and power consumption, while saving time and costs.
Use coroutines, which are a function of type IEnumerator that can return control to Unity with a special yield return statement. Coroutines are perfect for relaxed updates where a game requires a repeated action at a specific time period. This is an alternative to performing the action every time through the MonoBehaviour.Update () callback, and saves time and costs.
Use the StringBuilder class, such as System.Text.StringBuilder, to concatenate complex strings, which is faster than the string.Format() method and uses less memory than concatenation with the plus operator.
Use the CompareTag() method, as it is faster and does not allocate extra memory in comparison to the GameObject.tag property.
Use object pools, which avoids the performance penalty of allocating and freeing many objects of the same kind that are created and destroyed at runtime.
Use OnBecameVisible() and OnBecameInvisible() callbacks that notify your scripts if the associated game objects become visible or invisible on screen. This then enables you to disable computationally heavy code routines or effects when a game object is not rendered on screen.
Use sqrMagnitude for comparing vector magnitudes, as other calls use a computationally expensive square root for calculations.
Use built-in arrays if you know the size of an array in advance, as these are faster than ArrayList and List classes.
Use planes as collision targets if the gaming scene only requires particle collisions with planar objects like floors or walls, as this reduces the required computations.
Use compound primitive colliders that combine shapes like boxes, capsules, or spheres into a compound collider to produce similar results to mesh colliders but with a far lower computational overhead.
Reduce the number of physics calculations, with most taking place at a fixed time step that can add to the computational load.
Remove empty callbacks, which include empty definitions like Awake(), Start() or Update(), as there is a performance overhead associated with these empty functions, with the engine trying to access them even though they are empty.
Avoid hard-coded values for tags, which restrict the scalability and robustness of your game. For example, with tag names, if you refer to the names directly by strings then you cannot easily modify them.
Avoid using GameObject.Find() in every frame, as it is a function that iterates through every object in the scene, which can cause a significant increase in the main thread size if it is used in an incorrect part of your code.
For more information on the above and the many different optimization opportunities in Unity, check out this documentation on developer.arm.com.
You can also watch this on-demand video from the Arm Developer Hub explaining how to profile your games using the Unity engine when rendering on Mali GPUs.
There are also additional Unity based tools and methods that you can use to optimize performance and deliver longer, more complex gaming experiences, including Unity Adaptive Performance and Unity ML-Agents.
Adaptive Performance, which can be downloaded here, is a package from Unity that allows you to fine-tune your games to improve the overall performance. This also saves time and costs during the game development process.
Adaptive Performance can be integrated with a device simulator, which means you can test various scenarios rather than waiting for the device to heat up before benchmarking tests. It also allows you to set any bottlenecks to the CPU, GPU, or a target frame rate, and you can set CPU and GPU levels to simulate the frequency of game performance to help establish any performance issues.
For more information on how to implement Unity Adaptive Performance in your game, read this blog.
Unity ML-Agents, which can be downloaded from GitHub, allow you to train intelligent game AI agents within games and simulations, with the game characters “learning” through reinforcement learning (RL). There are many different elements when using Unity-ML agents on Arm-based mobile devices, but below are two broad considerations when getting started.
1. Consider how the ML-Agents in the game are designed and what the generated neural network (NN) models look like through the following items:
Input to the agent and what information it needs.
Outputs from the agent and which actions it needs to take to accomplish a target task in the game.
The NN model structure and how the brain should process information.
The reward function and how the agent will be trained.
2. Consider the training strategy for the ML-Agents and how the game runs on Arm-based devices. Two key aspects of the training strategy are:
Training the agent using multiple instances.
Applying different training metrics to track learning progress.
For more information about how to create games using Unity ML-Agents on Arm, read this three part blog series and check out the video:
Part 1
Part 2
Part 3
On-demand video on the Arm Developer Hub.
Away from the Unity tools and methods, you can also optimize the performance and efficiency of your games through Arm Performance Studio, which can be downloaded for free here.
This is a suite of optimization tools for mobile games that provide you with early and frequent testing around gaming and graphics performance. This quickly identifies areas that can be optimized to reduce profiling time, helping you predict and improve game performance and efficiency. Each tool targets a different stage in the profiling workflow for gaming applications:
Performance advisor: This generates an easy-to-read performance report from an annotated Streamline capture and gives actionable suggestions about how to optimize the gaming application.
Streamline: This captures a performance profile for deep-dive analysis, using all of the CPU, GPU, and memory system performance data. All of these metrics allow game developers to target optimizations to the areas that matter most.
Graphics Analyzer: This investigates the OpenGL ES and Vulkan API calls made by the application and how the GPU reacted to them to identify rendering defects and performance inefficiencies. The tool uses diagnostic tooling, such as overdraw and shader usage maps, to explore the frames of the application draw-by-draw and find opportunities for optimization.
Mali Offline Compiler: This compiles the application’s shader programs and checks how they will perform across any Arm GPU. Performance reports from this tool give game developers information on shader register usage and thread occupancy, an estimated cycle cost breakdown for the target GPU, and other stage-specific performance feedback.
For further information about Arm Performance Studio visit developer.arm.com for additional resources and our learning path on getting started with Arm Performance Studio.