Skip to main content

Object Pooling system for unity - Technoob Technology

As a game developer, you might have experienced performance issues when instantiating new game objects in a game. This is a very usual thing as instantiating an object in the middle of the game costs a severe amount of CPU power. Professional game developers use various methods to avoid instantiating objects like this. Pooling is the most popular method to do this. We gonna target unity engine in this tutorial and this class is created in C# language. 




A pool is a set of instantiated game objects but disabled. When a class or method requires a game object of that type pool simply takes one of the game objects from the pool and returns it. We can create pools within each class and that is going to be very hard to manage and time wasting as you have to rewrite the same code again and again. To avoid this we are going to create a custom class called Pool and implement all the functions a pool should contain within it. 


As we mentioned above the class is named as pool and we need the constructor to create the pool when an instance of this class is created.


private Queue<GameObject> poolingObjectsQueue = new Queue<GameObject>();


public Pool(GameObject poolingObject, int requiredAmount)
        {
            for (int i = 0; i < requiredAmount; i++)
            {
                GameObject spawnedObject = Object.Instantiate(poolingObject);
                spawnedObject.SetActive(false);
                poolingObjectsQueue.Enqueue(spawnedObject);
            }
                _poolingObject = poolingObject;
        }


The class contains a Queue variable which contains game Objects. When this constructor is called what it does is it loops for the number of times passed into the constructor and Instantiate new GameObjects of the given type and Enqueue them in the Queue. And all the game objects are set deactivated. We create a variable of the type of GameObject named as _poolingObject in the class and assign the given game object to the constructor to that variable for future use. 

Now our pool is ready. What we need now are some methods to get GameObjects from the pool and return the game objects to the pool.



The first method we need is a function to get a game object from the pool. This is a simple method. What we do is Dequeue a game object from Queue and return it. We add an extra parameter to the function to activate the game object when returning and this parameter is set to false in default. If the Queue is empty this function throws an Exception.




public GameObject GetObject(bool activateOnReturn = false)
        {
            if (poolingObjectsQueue.Count > 0)
            {
                GameObject go = poolingObjectsQueue.Dequeue();
                if (activateOnReturn)
                {
                    go.SetActive(true);
                }

                return go;
            }

            throw new Exception("Queue is empty");
        }



Now what we need is a function to add a used game object again to the pool. This method has a parameter of type GameObject and what this does is Enqueue the game object to the Queue again. If the GameObject is active this method deactivates it before the process.



public void ReturnGameObject(GameObject gameObject)
        {
            if (gameObject.activeSelf)
            {
                gameObject.SetActive(false);
            }

            poolingObjectsQueue.Enqueue(gameObject);
        }



Now our pool is fully functional. We can create a pool and use it. But to make this class more useful we can add some more methods. 




We gonna create 4 additional methods and those are


  • A method to add a game object to the pool after a delay
  • A method to get the number of game objects remaining in the pool
  • A method to increase the pool size
  • A method to clear the pool


1. Delaying the ReturnGameObject method is easy and what we gonna use here is the Task class, and copy the same code of that method. We name this method as "ReturnGameObjectAfterDelay"
and this method takes two parameters. First one is the game object and the second one is the delay we want in milliseconds. We use a lambda expression in this method to the callback function.



public void ReturnGameObjectAfterDelay(GameObject gameObject , int delayInMiliSeconds)
        {
            Task.Delay(delayInMiliSeconds).ContinueWith(t =>
            {
                if (gameObject.activeSelf)
                {
                    gameObject.SetActive(false);
                }

                poolingObjectsQueue.Enqueue(gameObject);
            });
        }



2. This method simply returns the number of remaining game objects in the pool. It's very simple and returns the Queue.Count as the value.



public int GetRemainingObjectsAmount()
        {
            int amount = poolingObjectsQueue.Count;
            return amount;
        }


3. This method is used to increase the pool size at any moment we want. We gonna use the _poolingObject variable to instantiate more objects of that type. This parameter takes one parameter of type int and increases the pool by instantiating new game objects and enqueue them in the Queue. 


public void IncreasePool(int amount)
        {
            for (int i = 0; i < amount; i++)
            {
                GameObject spawnedObject = Object.Instantiate(_poolingObject);
                spawnedObject.SetActive(false);
                poolingObjectsQueue.Enqueue(spawnedObject);
            }
        }


4. This is very simple and what it does is call the Clear method of the Queue.


public void ClearPool()
        {
            poolingObjectsQueue.Clear();
        }




Final Code should look like this. Leave your ideas and opinions in the comment section.

You can clone the script from GitHub.


public class Pool
    {
        private Queue<GameObject> poolingObjectsQueue = new Queue<GameObject>();

        private GameObject _poolingObject;

public Pool(GameObject poolingObject, int requiredAmount)
        {
            for (int i = 0; i < requiredAmount; i++)
            {
                GameObject spawnedObject = Object.Instantiate(poolingObject);
                _poolingObject = poolingObject;
                spawnedObject.SetActive(false);
                poolingObjectsQueue.Enqueue(spawnedObject);
            }
        }

public GameObject GetObject(bool activateOnReturn = false)
        {
            if (poolingObjectsQueue.Count > 0)
            {
                GameObject go = poolingObjectsQueue.Dequeue();
                if (activateOnReturn)
                {
                    go.SetActive(true);
                }

                return go;
            }

            throw new Exception("Queue is empty");
        }

public void ReturnGameObject(GameObject gameObject)
        {
            if (gameObject.activeSelf)
            {
                gameObject.SetActive(false);
            }

            poolingObjectsQueue.Enqueue(gameObject);
        }

public void ReturnGameObjectAfterDelay(GameObject gameObject , int delayInMiliSeconds)
        {
            Task.Delay(delayInMiliSeconds).ContinueWith(t =>
            {
                if (gameObject.activeSelf)
                {
                    gameObject.SetActive(false);
                }

                poolingObjectsQueue.Enqueue(gameObject);
            });
        }

public int GetRemainingObjectsAmount()
        {
            int amount = poolingObjectsQueue.Count;
            return amount;
        }

public void IncreasePool(int amount)
        {
            for (int i = 0; i < amount; i++)
            {
                GameObject spawnedObject = Object.Instantiate(_poolingObject);
                spawnedObject.SetActive(false);
                poolingObjectsQueue.Enqueue(spawnedObject);
            }
        }

public void ClearPool()
        {
            poolingObjectsQueue.Clear();
        }
    }
}


Related Articles



Comments

Popular posts from this blog

How to make a first person character controller - Unity

A first-person character controller script is the starting point of any fps shooter game. Even new Unity game developers tend to write their own fps controller script before learning anything else as it is challenging and very exciting. In this article, we gonna create two simple fps controllers from scratch and will guide you step by step on how it works. First, let's understand the basic concept of an fps controller. You should have a rotating camera that rotates in the x-axis to look up and down and the character should rotate on the y-axis to look around. There are two ways to create an fps controller in the Unity Engine.  Using Character controller component Using the RigidBody component Both have different advantages and disadvantages when using them. It depends on your game to select the best fps controller according to your needs.  Character controller based fps controller Pros: Is grounded check is built-in Has its own methods to move the chara

Unity Get Post web requests - Technoob Technology

Web requests in unity are super easy to use. We gonna use the UnityWebRequest class as the WWW class is deprecated now. UnityWebRequest class can be used for both Get and Post methods. The 'UnityEngine.Networking' namespace is required to work with UnityWebRequests.  This tutorial is made with some simple UI elements. First Let's see how the GET method works. 01. UnityWebRequest.GET We use this method to receive data from the server as normal get requests. Using coroutines in web requests is mandatory as we have to wait until the download is complete before showing the results, and the coroutines make this much easier. A simple button calls the method and a text element will show the result. The script contains a reference to the text element and the string URL of your PHP file.  When the button is pressed the button executes the ButtonGetData method and that method simply starts the GetData coroutine. We use the using keyword as this data

How to make an Advanced Audio Manager for Unity - Technoob Technology

Unity engine gives us a good control on audio clips we use, But the problem is when we add several audio sources for several audio clips it's gonna get hard to control them all. And if you want to make some changes to only one audio source you have to find it first.  This will become a mess if you gonna work with more than 10 audio clips. In this case, we can Create an AudioManager and include all the audio clips in it and make some static methods to play, pause the audio from other scripts. This Audio Manager is written in C# and if you use unity-script you have to convert this into unity script first. In this tutorial, we gonna create an audio manager which contains 7 methods. 1.Play 2.Pause 3.Unpause 4.Stop 5.FadeIn 6.FadeOut 7.lower volume for a duration First, we need a Custom class which contains some strings, floats, bools and an audio clip. This class is not derived from unity mono behavior so we should add [System.Serializable] to mak