Looking for great developers Looking for great developers [email protected]
Facebook Linkedin Dribbble Behance Cluth

Five tricks and one design pattern to kick your unity game performance

22-10-2021 3 min read

Five tricks and one design pattern to kick your unity game performance

When I was working on our game, the performance on Android devices sucked. The performance of UNITY depends on too many things to say all in one article. This blog post should give us a quick checklist of what to do to boost performance. Even the best game idea cannot engage players without feeling smooth and responsive on mobile devices. Each game is different, but we have few tools to find what's wrong with unity studio quickly.

The first of them is the unity profiler. Use them. 

Profiler told as a lot as I can finish this blog post here. The profiler says true about performance and what unity does in each millisecond. But I would like to show you one of the best design patterns to use in unity.

Second. Check up your update methods. 

They call in each frame (or more than once per frame like the update Physics() method). Sometimes we do some resources depends on action in an update. Remember to set up all on start or invoke. Don't search by tag in an update.

Third. Lights' complicated lights mean a lot of calculating.

Use Baked light mode. Move objects with attached rigid body and collision detection by rigid body position in updatePhysics method.

Fourth. Fonts on canvas.

It can be tough to find but in my experience. It causes me that hate programming feelings. Default font causes a lot of performance drop when updating text. And to check how the game looks like on an actual device, I create some fps counter. And after fix all of the performance bugs, it still sucks because of the fps counter with the default font. It is updating in each frame, causing canvas rendering. After changing it to update once per some period and changing the font to different works like a charm.

Fonts on canvas.

The fifth and most exciting point is the object pooling design pattern.

One thing we can see in the profiler is that Instantiate and Destroy methods are slow. So when they are called often after some time, the garbage collector has to clear resources which causes a lot of performance drop and profiler line show spike on this time. 

How to handle it? By preparing a pool of the object that it can be used in the game later.  Instead of Instantiate and Destroy, we only activate and deactivate it. So we can reuse things later. Firstly we need to know what to pool. 

Show me the code

So create a class:

[System.Serializable]
public class ObjectPoolItem
{
    public int AmountToPool;
    public GameObject ObjectToPool;
    public bool ShouldExpand;
}
   

It is serializable to use this in the editor easily. These names are so prominent they don't need explanation. Pooler is a singleton and inherits from MonoBehaviour.

public class ObjectPooler : MonoBehaviour
{
    public static ObjectPooler Instance;
    public List itemsToPool;
    public List pooledObjects;

    void Awake()
    {
        Instance = this;
    }
   

On Awake, I set up an Instance of it. There a list of ObjectPoolItem where we set up things we need to pool. And the list of pooled objects. All of them we later use in-game.

 void Start()
    {
        pooledObjects = new List();
        foreach (ObjectPoolItem item in itemsToPool)
        {
            for (int i = 0; i < item.amountToPool; i++)
            {
                GameObject obj = Instantiate(item.objectToPool);
                obj.SetActive(false);
                pooledObjects.Add(obj);
            }
        }
    }
   

Pooled object

At the start, we fill up pooled objects list by Instantiate each game object. We can add some ObjectPoolItem dynamically by code too.

ObjectPooler.Instance.itemsToPool.Add(new ObjectPoolItem {
amountToPool = 15, 
objectToPool = PlayerDependsBullet, 
shouldExpand = true 
});
   

Using game objects is by the GetPooledObject method with a tag in an argument.

 public GameObject GetPooledObject(string tag)
    {
        for (int i = 0; i < pooledObjects.Count; i++)
        {
            if (pooledObjects[i].activeInHierarchy || !pooledObjects[i].CompareTag(tag)) continue;
            return pooledObjects[i];
        }
        foreach (ObjectPoolItem item in itemsToPool)
        {
            if (!(item.objectToPool.CompareTag(tag) && item.shouldExpand)) continue;
            GameObject obj = Instantiate(item.objectToPool);
            obj.SetActive(false);
            pooledObjects.Add(obj);
            return obj;
        }
        return null;
    }
   

Script looking for a nonactive object with the tag we are looking for and returning it. If this for loop, don't produce any of them. The second for each check expand flag is set up to true and then create a new object and assign it to the pooledObject list.

In the script, we get objects instead of creating them and set up position, setActive, and all relative stuff we need.

By object pooling, we save a lot of resources needed to creating, destroying and cleaning resources. It can be advantageous to manage bullets or other stuff that we often show and hide in-game.

Contents

Would you like to discuss the challenges in your project on this topic?

Let's talk

Let our people take your business to the next level.

Sounds interesting? Give us some details and get your free estimation.

Cookies.

By using this website, you automatically accept that we use cookies. What for?

Understood