Skip to content

This repository will assist you in optimizing a mobile game in unity.

License

Notifications You must be signed in to change notification settings

GuardianOfGods/unity-mobile-optimization

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

71 Commits
 
 
 
 

Repository files navigation

unity-mobile-optimization

banner

👋 Hi there, I'm HoangVanThu. This repository discusses various ways to optimize your games on mobile devices, helping enhance overall performance. These techniques aim to improve the gaming experience by optimizing resource usage and performance on mobile platforms.

The article has been synthesized from various sources on the internet. If you find any inaccuracies or have any questions about the content, please submit an issue or provide direct feedback to me.

Table of optimization contents:


Scripting

Clean Code

  • Your game may have many code redundancy, so clean code could increase the performance for your game.
  • Here I found a good clean code topic.

Avoid Allocating Memory

Every time an object is created, memory is allocated. Very often in code, you are creating objects without even knowing it.

Situation 1: In Unity, the term "string" refers to a data type, not a variable name.

  • You want to debug log a content like this:
- Debug.Log("hello" + " " + "world");
  • This code above will create 3 difference string and located in the heap memory. So this should be:
+ Debug.Log("hello world");

Situation 2: Use classes and struct wisely.

  • Memory Allocation and Performance Comparison:
    • When you create a struct, its memory is allocated on the stack. This makes structs more efficient than classes, which are allocated on the heap. This means that structs are more suitable for functions that require high performance and low memory usage.
    • Due to their memory allocation differences, structs are generally faster than classes. If you’re working with a large amount of data, structs can be more efficient because they don’t require the overhead of heap memory allocation.
    • However, there are some cases where classes are faster than structs. For example, when copying large objects, classes can be more efficient because they only copy a reference to the object instead of the object itself.
  • When to Use Structs:
    • Structs are best used when you need to represent simple data types, such as integers, strings, or other basic data types. They are also useful when you need to work with large datasets, such as arrays or lists, where performance is critical.
    • You should also use a struct when you need to pass a small amount of data to a method, and you want to avoid the overhead of passing a reference to a class.
  • When to Use Classes:
    • Classes are best suited for representing complex objects like cars or people and for creating hierarchies of objects with inheritance. They are ideal for handling large amounts of data, such as working with databases.
    • Classes are useful when encapsulating functionality and data together, providing organized and maintainable code.
    • Additionally, classes support the implementation of interfaces, enhancing flexibility and modularity in your code.

Situation 3: Use C# Events instead of UnityEvents.

  • UnityEvent creates less garbage than C# events if you add more than two listeners to it, but creates more garbage otherwise. It creates garbage when dispatched (Update: the first time) where C# events do not. And it’s at least twice as slow as C# events.

Use Algorithm

  • The algorithm will significantly improve the performance of the game, apply it whenever possible.

Technical

Object Pooling

Example of Object Pooling

  • To prevent Garbage Collector issues (CPU Spikes) in games with many spawning and destroying objects, a method called Object Pooling can be used. Object Pooling refers to creating all necessary objects beforehand and disabling/enabling them when it necessary, instead of instantiating (Instantiate() function) and destroying (Destroy() function) objects during runtime.
  • These objects can also be spawned beforehand during a loading screen and kept hidden until needed. This way they won’t cause performance issues when spawned during gameplay.
  • You can also wrtie pooling script or use asset in store like LeanPool

Recyclable Scroll

Rycyclable scrollview

  • By creating a scrollview with 9999 items it causes a significant performance degradation for the game. So rycyclable scrollview is used to significantly increase the game's performance. Instead of creating 9999 items in a scrollview, recyclable scrollview creates a certain number of items that need to be displayed on the screen and reuses them.
  • Recyclable Scroll Rect - Optimized List/Grid View is my suggestion.

Assets Import

Texture

Texture import settings on Inspector

  • Most of your memory will likely go to textures, so the import settings here are critical. In general, try to follow these guidelines:
    • Lower the Max Size: Use the minimum settings that produce visually acceptable results. This is non-destructive and can quickly reduce your texture memory.
    • Use powers of two (POT): Unity requires POT texture dimensions for mobile texture compression formats (PVRCT or ETC).
    • Atlas your textures: Placing multiple textures into a single texture can reduce draw calls and speed up rendering. Use the Unity Sprite Atlas or the third-party TexturePacker to atlas your textures.
    • Toggle off the Read/Write Enabled option: When enabled, this option creates a copy in both CPU- and GPU-addressable memory, doubling the texture’s memory footprint. In most cases, keep this disabled. If you are generating textures at runtime, enforce this via Texture2D.Apply, passing in makeNoLongerReadable set to true.
    • Disable unnecessary Mip Maps: Mip Maps are not needed for textures that remain at a consistent size on-screen, such as 2D sprites and UI graphics (leave Mip Maps enabled for 3D models that vary their distance from the camera).
    • Compress Texture: For almost every mobile device today, format sould be RGBA Compressed ASTC. For older devices, you can choose ET2 or ETC compress.

Compress texture recommended

Texture compression format - Player Settings

Texture compression format in Player Settings

  • Texture compression format: Player Settings provide a global default for texture compression, affecting all textures unless overridden.
    • ETC (Default): ETC (Ericsson Texture Compression) is a common format used on Android devices.
    • ASTC: ASTC (Adaptive Scalable Texture Compression) is a modern texture compression format suitable for a variety of platforms, including newer mobile devices.

Audio

Audio import settings in Inspector

  • Alway enable Force to mono to reduce the file size, use less memory and many other advantages.
  • Reduce the size of your clips and memory usage with compression:
    • Use Vorbis for most sounds (or MP3 for sounds not intended to loop).
    • Use ADPCM for short, frequently used sounds (e.g., footsteps, gunshots). This shrinks the files compared to uncompressed PCM, but is quick to decode during playback.
  • Sound effects on mobile devices should be 22,050 Hz at most. Using lower settings usually has minimal impact on the final quality; use your own ears to judge.
  • The setting varies by clip size.
    • Small clips (< 200 kb) should Decompress on Load. This incurs CPU cost and memory by decompressing a sound into raw 16-bit PCM audio data, so it’s only desirable for short sounds.
    • Medium clips (>= 200 kb) should remain Compressed in Memory.
    • Large files (background music) should be set to Streaming, or else the entire asset will be loaded into memory at once.

Mesh

Audio import settings in Inspector

  • Much like textures, meshes can consume excess memory if not imported carefully. To minimize meshes’ memory consumption:
    • Compress the mesh: Aggressive compression can reduce disk space (memory at runtime, however, is unaffected). Note that mesh quantization can result in inaccuracy, so experiment with compression levels to see what works for your models.
    • Disable Read/Write: Enabling this option duplicates the mesh in memory, which keeps one copy of the mesh in system memory and another in GPU memory. In most cases, you should disable it (in Unity 2019.2 and earlier, this option is checked by default).
    • Disable rigs and BlendShapes: If your mesh does not need skeletal or blendshape animation, disable these options wherever possible.
    • Disable normals and tangents: If you are absolutely certain the mesh’s material will not need normals or tangents, uncheck these options for extra savings.

Animation

Animation import settings in Inspector

  • By clicking on a model containing animation in the project, you can open the animation import settings.
  • You can change properties such as rotation error, position error, and scale error to reduce file size. However, keep in mind that these parameters introduce errors to the animation, so you should be cautious when adjusting them. You can refer to the documentation for more details on compression and animation

Tips and Tricks

Staying with Unity LTS

  • You should stay with Unity LTS (Long-term support) versions only. Versions that do not support LTS often have unexpected errors.
  • As you dive in, keep in mind that while each Tech Stream release is supported with weekly updates until the next version, there is no guarantee of long-term support for new features.

Use original uncompressed WAV files as your source assets when possible.

  • If you use any compressed format (such as MP3 or Vorbis), Unity will decompress it, then recompress it during build time. This results in two lossy passes, degrading the final quality.

Use the minimum Audio Source you can in your game.

  • Each active audio source requires CPU resources for playback, which can strain the device's processing capabilities. Active audio sources consume memory, and mobile devices typically have limited RAM.

Customize Linear vs Gamma color space.

Linear vs Gamma color space

  • Gamma has better performance (~10-30%) than Linear. However, the display is a bit worse.
  • You can find this option in Player Setting -> Other Settings.

Try using incremental GC (Garbage collection)

Use incremental GC settings

  • Sometimes enable use incremental GC option can improve game's performance and sometimes it's not, you should see profiler for the impact. You can find it in Player Setting.

Using LOD technical

Level of details example

  • Level of detail (LOD) is a technique that reduces the number of GPU operations that Unity requires to render distant meshes.
  • When a GameObject in the Scene is far away from the Camera, you see less detail compared to when the GameObject is close to the Camera. However, by default, Unity uses the same number of triangles to render it at both distances. This can result in wasted GPU operations, which can impact performance in your Scene.

Bake Mesh

Merging.many.objects.into.one.object.in.Unity.mp4

Youtube short for example of baking mesh

  • Bake mesh is the process of combining meshes to reduce draw calls, which also means increasing game performance. Unity does not provide mesh baking, however there are quite a few assets on the store that provide mesh baking, such as Mesh Baker or ProBuilder.
  • Here are some assets you can choose: Bake Mesh, Simplest Mesh Baker

Fake Shadow

Lighting properties in Mesh Renderer

  • The computation of shadows in Unity incurs a significant performance cost, especially on mobile devices. It is advisable to disable shadow casting and receiving if not absolutely necessary, substituting them with fake shadows as an alternative to improve performance.
  • You can also create fake shadows using a blurred texture applied to a simple mesh or quad underneath your characters. Otherwise, you can create blob shadows with custom shaders.

Pack texture

Create and settings a sprite atlas

  • Combine textures into a sprite atlas within the same popup or scene in Unity to enable batching draw call. This will help improve performance, although it may slightly increase the game's file size.
  • Attach asset objects to pack and note that you should disable tight packing if you don't want to wrong display.

Enable GPU Instancing

Create and settings a sprite atlas

  • GPU instancing is a draw call optimization method that renders multiple copies of a mesh with the same material in a single draw call. Each copy of the mesh is called an instance. This is useful for drawing things that appear multiple times in a scene, for example, trees or bushes.
  • GPU instancing renders identical meshes in the same draw call. To add variation and reduce the appearance of repetition, each instance can have different properties, such as Color or Scale. Draw calls that render multiple instances appear in the Frame Debugger as Render Mesh (instanced).

Disable Vsync

Linear vs Gamma color space

  • Enable Vsync in mobile game might cause lag, faster battery drain and also limit the frame rate to the monitor's refresh rate.

Choose Suitable Graphics API

Graphics API

  • In Player Setting. You can check the list of graphics APIs supported by the current version of Unity by unchecking Auto Graphics API and clicking on the plus sign to view all API.
  • For Android, there are 3 API graphics: GLES2, GLES3 and Vulkan base on Unity version.
    • GLES3 is the best choise for popular mobile devices that you shouldn't remove.
    • If you want to target on old devices, you should have GLES2.
    • Vulkan is good option for modern devices but sometime it's causing crash and lag for lower devices.
  • My recommend is using GLES2, GLES3 for optimizing.

Others

Support

  • If you like this topic, you can give this repository a star ⭐
  • I would greatly appreciate it if you could support me with a cup of coffee