Performance is critical for mobile gaming, especially if it combines physics, AI (artificial intelligence), and fully animated characters from a 3D world.
A while ago, we made a game for iOS. The game had a good number of downloads, but there was one big problem. The game was very poorly optimized, and it would not run smoothly on budget devices. We had to make a lot of effort to optimize the game to run with a consistent framerate on every device. In this article, I will describe the approaches we have taken to optimize Unity-based games.
Note: This article is for those who have a know how of the Unity game development. If you are just starting out at as a Unity game developer and have no prior knowledge of the game development, you should first consider taking a unity game development course. There are certain ways you can learn Unity game development. You can either take admission in a school for game design or take an online game development course from Lynda.com and Udemy. Unity also has a great set of courses and tutorial which should get you started with Unity game development.
Using the Performance Profiler
The first place to look when you want to improve performance is the Unity Profiler. This functionality is available in Unity Pro and allows you to analyze problem areas. The profiler is a valuable tool. It can help you determine where frame rate issues are occurring. To use it, launch the game on your mobile device and the profiler on your PC. When you launch the game, the profiler starts loading performance data.
To use the profiler on mobile devices, make a build in Developer mode. From Unity documentation:
To be able to connect to the player, the player must be launched using the Development Build option found in the Build Settings dialog box.
Here you can also check the box to connect the editor and the player automatically. The profiler shows a graph of the CPU usage during the game. Just connect your mobile device to the development machine and play through the game. The profiler will show all problems in real time. It breaks down activities into Rendering, Scripts, Physics, Garbage Collector, VSync and others. Rendering issues are common in mobile games. Sometimes performance jumps occur in scripts when loading a scene, but this is not unusual. Some of the races are related to physics.
Physics and Artificial Intelligence
I will describe a few basic physics code optimization ideas and move on to the graph.
- Try to keep as few objects as possible moving at the same time. Sleeping facilities are much cheaper.
- The same goes for artificial intelligence. If the object is far from the main character or is not visible, do not run artificial intelligence scripts.
- Raycasts are very expensive. Don’t raycast every frame – try caching the results and skipping some frames.
- Try to avoid complex mesh colliders.
- Check the functions Update(). They fire every frame and are therefore expensive. Use Coroutines instead.
It is a Unity feature that saves a lot of CPU cycles. Every time an object is rendered, a Draw Call occurs – a command to the CPU or GPU that the object should be rendered. Unity launches multiple draw calls and stacks them on top of each other to form the scene. However, each Draw Call requires CPU resources, so we want to minimize their amount.
This is where Batching should be used. It is needed in order not to make unnecessary Draw Calls. Batching comes in two flavors: static and dynamic. Static gives the best performance, so we alwayCoroutiness try to use it.
To effectively apply Static Batching, use as few different elements as possible. To do this, combine all the elements into one large texture. The last step is to add a Lightmap to the scene. Since we practically do not use memory for the texture of objects, we can make a fairly detailed Lightmap, and there will be no memory problems.
To use Static Batching, check the Static checkbox in the object properties. It can only be used for objects that do not move, rotate or scale in the scene.
Dynamic Batching can be used for non-static objects. Dynamic Batching objects require certain resources per vertex, so it only applies to meshes with less than 900 vertices. Our shader uses Vertex Position, UV, and Colors. Thus, we can have up to 300 vertices per object.
Some helpful tips from the Unity manual:
- Dynamic batching involves additional load for each vertex, so it only applies to meshes with fewer than 900 vertices.
- If your shader uses Vertex Position, Normal, and a single UV, then you can batch up to 300 vertices, whereas if the shader uses Vertex Position, Normal, UV0, UV1, and Tangent, then only 180 vertices.
- Don’t scale. Objects with scale (1,1,1) and (2,2,2) will not be batched.
- Uniformly scaled objects will not batch with unevenly scaled objects.
- Using different materials will cause batching to fail.
- Objects with Lightmap have an additional (hidden) material parameter: offset/scale in Lightmap, so objects with Lightmap will not batch.
Note that if an object has animation but has a part that never moves, you can mark that part as static, and it will not interfere with the animation.