Business
2021-10-22
4 min. read

unity
game performance

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

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

contest-blog-list-mobile

Contents

When I was working on a game for one of our clients, 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 a few tools to find what's wrong with unity studio quickly.

If you want to know more about game development, be sure to check out our "What is gamification? Guide (2022)" article in which we go deep into the world of gamedev.

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

The profiler says the truth 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 depending on the 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 those 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 fixing 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 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 is 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 create, destroy and clean resources. It can be advantageous to manage bullets or other stuff that we often show and hide in-game.

About the author
Peter Koffer - Chief Technology Officer

With 13 years of experience in the IT industry and in-depth technical training, Peter could not be anything but our CTO. He had contact with every possible architecture and helped create many solutions for large and small companies. His daily duties include managing clients' projects, consulting on technical issues, and managing a team of highly qualified developers.

Piotr Koffer

Share this article


Contents


mDevelopers logo

Software development company

Clutch mDevelopers

We’ve been in the business for over 13 years and have delivered over 200 mobile and web projects. We know what it takes to be a reliable software partner.


Cookies.

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