/* * ================================================================================================ * Author - Ben Schuster * Date Created - March 27th, 2023 * Last Edited - March 27th, 2023 by Ben Schuster * Description - Individual pool object. Does not contain any unique functionality as that * will be handled by concrete pool managers * ================================================================================================ */ using System.Collections; using System.Collections.Generic; using System.Drawing; using UnityEngine; [System.Serializable] public class Pool { /// /// Primary key for this pool /// private GameObject key; /// /// Hashcode of the key object /// private int keyID; /// /// Queue of current objects in pool /// private Queue currentPool; /// /// Current size of the queue /// private int size; /// /// Maximum size of this pool /// private int maxSize; /// /// Increment rate to increase size by when pool is empty /// private int incrementRate; /// /// Whether this pool recycles the oldest object at max /// private bool recycle; /// /// Root gameobject to store pooled objects under /// private Transform container; /// /// Constructor for pool /// /// Key for this pool /// starting size for this pool /// max size of this pool /// increment rate for this pool /// root to store pooled objects under public Pool(GameObject key, int size, int maxSize, int incrementRate, bool recycle, Transform container) { // prepare variables this.key = key; this.keyID = key.name.GetHashCode(); this.size = size; this.maxSize = maxSize; this.incrementRate = incrementRate; this.recycle = recycle; this.container = container; // create pool queue, populate to requested size currentPool = new Queue(); // Init pool with starting values Init(); } /// /// Initialize the pool with new values /// protected void Init() { // if no queue, create it if(currentPool == null) { currentPool = new Queue(); } // populate buffer with current size size for (int i = 0; i < size; i++) { Spawn(); } } /// /// Extend the pool by its increment rate. Return a new object from the extended pool /// /// A newely pooled object. If null, then pool is maxed. protected GameObject ExtendPool() { // make sure the pool exists first if(currentPool == null) { currentPool = new Queue(); } // check if going out of bounds if(size >= maxSize) { Debug.Log($"[POOL] Pool of {key} is maxed out!"); return null; } // increase size, clamp it int newSize = Mathf.Clamp(size + incrementRate, 0, maxSize); // fill queue with the new amount of objects. Keep same name for hashcode reasons for (int i = 0; i < (newSize - size); i++) { Spawn(); } // update size, return one of the new objects // do this because this will only ever be called when attempting to pull an object size = newSize; return currentPool.Dequeue(); } /// /// Actually spawn the object into the pool /// private void Spawn() { GameObject spawnBuffer; spawnBuffer = MonoBehaviour.Instantiate(key, container); spawnBuffer.SetActive(false); IPoolable poolRef = spawnBuffer.GetComponent(); if(poolRef != null) { poolRef.PoolInit(); spawnBuffer.name = key.name; currentPool.Enqueue(spawnBuffer); } else { Debug.Log($"Error trying to initialize {key.name} in pool, excluding from pool"); return; } } /// /// Pull an object from the pool /// /// A pooled object. If null, the pool is maxed. public GameObject Pull() { GameObject o; // Get an object from the pool if (currentPool.Count > 0) { o = currentPool.Dequeue(); } // Otherwise extend the pool else { o = ExtendPool(); } // If set to recycle, make sure to reset it just incase. // Add to end of pool queue if (recycle && o != null) { o.SetActive(false); o.GetComponent().PoolPush(); currentPool.Enqueue(o); } if(o != null) { o.GetComponent()?.PoolPull(); o.SetActive(true); } return o; } /// /// Return an object reference to this current pool /// /// Reference to the key object public void Return(GameObject objectRef) { // make sure pool is used if (currentPool == null) { currentPool= new Queue(); } // add object back to queue objectRef.transform.localPosition= Vector3.zero; objectRef.GetComponent().PoolPush(); objectRef.SetActive(false); // Recycled pools should already have this in it // so double check if(!currentPool.Contains(objectRef)) currentPool.Enqueue(objectRef); } /// /// The key for this pool /// /// Key for this pool as a hashcode of the name public int Key() { return keyID; } }