Sunday, 7 November 2021

Unity Implementint Object Pool

  Object pooling is a great way to  optimize your game and avoid memory leak you should implement this method on games in which you instantiate and destroy a lot of game objects this  approach  creates a game object pool and  does not destroy this object  only disables it and calls the same object when needed

it's a very modular reusable system in any kind of game


First of All Create A folder for Pooler like "ObjPooler" and ad those scripts

"CreateGameObjects" Script;


 
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;

    public class CreateGameObjects : MonoBehaviour
    {
        public Transform Parent;
        
        [SerializeField]
        public List&ltPool> gameObjectList;
        private PoolDictionary poolDic;
        [SerializeField]
        private List&ltGameObject> gmSelectedGameObjects;
        private Transform destinatinTransform;private static CreateGameObjects _instance;
        public static CreateGameObjects Instance { get { return _instance; } }
        void Awake()
        {
        // Makes object singleton so you can reach easily
        if (_instance != null && _instance != this)
        {
            Destroy(this.gameObject);
        }
        else
        {
            _instance = this;
        }
        StartPooling();
        }
        public void StartPooling()
        {
            destinatinTransform = this.GetComponent&ltTransform>();
            poolDic = GetComponent&ltPoolDictionary>();
            poolDic.ResetPool();
            poolDic.setPool(gameObjectList, Parent);
        }

        public GameObject CreateGameObject(string TagName, Vector3 pos, Transform parent)
        {
            return poolDic.SpawnFromPool(TagName, pos, parent);
        }
        public GameObject InstantiateObject(string TagName, Vector3 pos)
        {
            Pool item = gameObjectList.Where(x => x.tag == TagName).FirstOrDefault();
            if (item != null)
            {
                return Instantiate(item.prefab, pos, Quaternion.identity);
            }
            return null;

        }

        public int AddOnScreenSelectedGameObject(GameObject gmObj)
        {
            gmSelectedGameObjects.Add(gmObj);
            return gmSelectedGameObjects.IndexOf(gmObj); // last insterted index
        }
        public void RemoveOnScreenSelectedGameObject()
        {
            gmSelectedGameObjects.Clear();

        }


    }

 

"Pool" Script


    [System.Serializable]
    public class Pool
    {
        public string tag;
        public GameObject prefab;
        public int size;
    }

 
"PoolDictionary" Script;

using System.Collections;
using System.Collections.Generic;
using UnityEngine;


    public class PoolDictionary : MonoBehaviour
    {
        //game objects queue
        [HideInInspector]
        public Dictionary&ltstring, Queue&ltGameObject>> poolDictionary;

        private List&ltPool> _pool;
        public void ResetPool()
        {
            _pool = new List&ltPool>();

        }
        // starts objectpool
        public void setPool(List&ltPool> pool, Transform parent)
        {
            _pool = pool;
            poolDictionary = new Dictionary&ltstring, Queue&ltGameObject>>();
            foreach (Pool item in _pool)
            {
                Queue&ltGameObject> objectPool = new Queue&ltGameObject>();
                for (int i = 0; i &lt item.size; i++)
                {
                    GameObject gmObj = Instantiate(item.prefab);
                    gmObj.SetActive(false);
                    //  gmObj.transform.SetParent(parent);
                    objectPool.Enqueue(gmObj);
                }
                poolDictionary.Add(item.tag, objectPool);
            }

        }
        private void activateAllChildren(GameObject gm)
        {
            gm.SetActive(true);
            for (int j = 0; j &lt gm.transform.childCount; j++)
            {
                gm.transform.GetChild(j).gameObject.SetActive(true);
            }

        }

        // calls object from pool
        public GameObject SpawnFromPool(string tag, Vector3 position, Transform parent)
        {
            if (!poolDictionary.ContainsKey(tag))
            {
                Debug.Log("Obj tag is not Found:" + tag);
                return null;
            }
            GameObject spawnObj = poolDictionary[tag].Dequeue();
            //makes selected gameobject active
            activateAllChildren(spawnObj);
            if (parent != null)
            {
                spawnObj.transform.SetParent(parent);
            }
            else
            {
                //  transform.SetParent(parent);
            }
            spawnObj.transform.position = position;
            spawnObj.transform.rotation = Quaternion.identity;

            poolDictionary[tag].Enqueue(spawnObj);
            return spawnObj;


        }



    }

you can implement those classes in any kind of project always the same to showcase an example I have created a player  and you can shoot with "space" button

Here is my "PlayerShooter" Script;

 using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerShooter : MonoBehaviour
{
    [SerializeField]
    Transform shootingPoint;

    GameObject currentGameObj;
    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
           currentGameObj= CreateGameObjects.Instance.CreateGameObject("Bullet", this.transform.position, null);
            currentGameObj.transform.position = shootingPoint.transform.position;
        }
    }
}

  


 And to Shoot Bullets here is my "BulletScript";

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class BulletScript : MonoBehaviour
{
    
    void Update()
    {
        // speed can be a serializefield its for demostration.
        this.transform.position += Vector3.forward * 30F * Time.fixedDeltaTime;
    }
    private void OnCollisionEnter(Collision collision)
    {
        Debug.Log("Bullet Collision");
        this.gameObject.SetActive(false);
    }
}

   

 and to start pooling you have to add Pool object to scene




 as You see There is a Bullet object  prefab it's a sphere  with nothing fancy only a collider and rigid body added with all axes constraint  as you see there is a very simple scene   you  need to add "PlayerShooter" Script to the player and "BulletScript" to Bullet and set Bullet tag"Bullet" 
you may set bullet pool size any count you like based on your game needs and you can add any kind of object  to the pool system





 So that's all for now if you have difficulties with implementation please mail me I can send you the whole project or don't hesitate to ask questions :)

happy coding :)









No comments:

Post a Comment