I tried to come up with my own generic pool and I wanted to hear your advices about it and what other kind of solution you came up.
I first tried to use generic type and interface like
public class Pool<T> : MonoBehaviour where T : MonoBehaviour, IPoolable
This would have allowed me to simply add the interface to any script to be able to use it in a pool.
But in the end I found out that I can’t have any generic Type to a child class of MonoBehaviour
So instead I made a public class BasicPoolObject : MonoBehaviour
Any object I wanted to be pooled will need to have this component or be its child.
In the end however I am quite happy at how well it work.
It pool a reference to any type of prefab
you can get an object by either sending the prefab or the name of the prefab if it is already prefab pooled.
The only issue I can see is if 2 different prefabs with the same name is sent to the pool, it won’t give any error but will always send the first one.
I am not an expert on benchmarking, I would like to know how efficient you think it is.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Pool : MonoBehaviour
{
private static Dictionary<string, BasicPoolObject> pooledPrefabs;
private static Dictionary<string, List<BasicPoolObject>> pool;
//singleton pattern implementation
private static Pool _pool;
public static Pool Instance
{
get
{
if (!_pool)
{
_pool = FindObjectOfType(typeof(Pool)) as Pool;
if (!_pool)
{
Debug.Log("Error, no Pool on scene");
}
}
else
{
_pool.Init();
}
return _pool;
}
}
private void Awake()
{
Instance.Init();
}
private void Init()
{
pooledPrefabs = new Dictionary<string, BasicPoolObject>();
pool = new Dictionary<string, List<BasicPoolObject>>();
}
public static BasicPoolObject GetObject(string prefabName)
{
BasicPoolObject prefab;
pooledPrefabs.TryGetValue(prefabName, out prefab);
return GetObject(prefab);
}
public static BasicPoolObject GetObject(BasicPoolObject prefab)
{
if (prefab == null)
return null;
BasicPoolObject value;
//try to find if this type of prefab is already pooled
if(!pooledPrefabs.TryGetValue(prefab.name,out value))
{//add the prefab to the pooled prefabs and init its pool list
pooledPrefabs.Add(prefab.name, prefab);
pool.Add(prefab.name, new List<BasicPoolObject>());
value = prefab;
}
BasicPoolObject inactiveObject = FindInactiveObjectInPool(pool[value.name]);
if(inactiveObject == null)
{//create object
int index = pool[value.name].Count;
pool[value.name].Add(CreateObject(value));
inactiveObject = pool[value.name][index];
inactiveObject.Init(pool[value.name].Count - 1, value.name);
}
inactiveObject.gameObject.SetActive(true);
inactiveObject.Reset();
return inactiveObject;
}
/// <summary>
/// return true if a new prefab is added
/// </summary>
/// <param name="prefab"></param>
/// <returns></returns>
public static bool AddPrefab(BasicPoolObject prefab)
{
if(pooledPrefabs.ContainsKey(prefab.poolName))
{
return false;
}
else
{
pooledPrefabs.Add(prefab.name, prefab);
pool.Add(prefab.name, new List<BasicPoolObject>());
return true;
}
}
public static bool DeactivateObject(BasicPoolObject poolObject)
{
List<BasicPoolObject> objList;
if (pool.TryGetValue(poolObject.poolName, out objList))
{
if(poolObject.index < objList.Count)
{
objList[poolObject.index].gameObject.SetActive(false);
return true;
}
}
return false;
}
private static BasicPoolObject FindInactiveObjectInPool(List<BasicPoolObject> poolList)
{
return poolList.Find(x => !x.gameObject.activeSelf);
}
private static BasicPoolObject CreateObject(BasicPoolObject prefab)
{
BasicPoolObject createdObject = Instantiate(prefab, prefab.transform.position, prefab.transform.rotation).GetComponent<BasicPoolObject>();
return createdObject;
}
}