/*
* ================================================================================================
* 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;
}
}