If you want to use a separate manager for each type of prefab, you can make PoolManager an abstract generic class and then add concrete implementations. Here's an abbreviated example; for brevity, I won't rewrite the entire class (// [...] indicates where code has been omitted):
public class PoolManager<T> : MonoBehaviour where T : Component
{
[SerializeField] private T _prefab;
[SerializeField] private int _poolAmount;
[SerializeField] private bool _usePool = true;
private ObjectPool<T> pool;
// [...]
private T CreateInstance()
{
T instance = Instantiate(_prefab);
instance .transform.SetParent(_poolContainer.transform);
instance.gameObject.SetActive(false);
return instance;
}
// [...]
}
public class ProjectilePoolManager : PoolManager<Projectile> {
// This concrete implementation doesn't need any additional code!
}
public class EnemyPoolManager : PoolManager<Enemy> {
// This concrete implementation doesn't need any additional code!
}
This is the approach I typically use.
If you want one pool manager component to manage all of your pools, rather than having a separate pool manager for each type of pool, that gets more complicated. It would look something like this:
public class PoolManager : MonoBehaviour {
// Note that because `ObjectPool<T>` is a generic type, we can't use `ObjectPool<T>`
// as the value type of the dictionary, so we cast to `object`.
private Dictionary<Type, object> _pools;
private Dictionary<Type, object> pools {
get {
if (_pools == null) _pools = new Dictionary<Type, object>();
return _pools;
}
}
public void CreatePool<T>(T prefab, Transform parent) where T : Component {
var pool = new ObjectPool<T>(
() => CreateInstance<T>(prefab, parent),
instance => {
instance.gameObject.SetActive(true);
}, instance => {
instance.gameObject.SetActive(false);
}, instance => {
Destroy(instance.gameObject);
}, false, 10, 200);
pools.Add(typeof(T), pool);
}
private ObjectPool<T> GetPool<T>() where T : Component {
if (pools.TryGetValue(typeof(T), out var poolObj)) {
var pool = poolObj as ObjectPool<T>;
return pool;
} else {
return null;
}
}
public T GetInstance<T>() where T : Component {
var pool = GetPool<T>();
if (pool == null) return null;
return pool.Get();
}
public void Release<T>(T instance) where T : Component {
var pool = GetPool<T>();
if (pool == null) Debug.LogWarning($"Tried to release {instance}, but there's no pool of type {typeof(T).Name}");
else pool.Release(instance);
}
private T CreateInstance<T>(T prefab, Transform parent) where T : Component {
T instance = Instantiate(prefab);
instance.transform.SetParent(parent);
instance.gameObject.SetActive(false);
return instance;
}
}
This component lets you create a separate object pool for each type of prefab you want to spawn. However, take note that this particular implementation I just threw together only lets you have one spawn pool per type, which doesn't work if you have multiple prefabs with the same component type (e.g. multiple prefabs of type Enemy).
And, at the risk of going overboard on this answer, here's an implementation where pools are mapped by prefab, so you can have different pools for different prefabs with the same type:
public class PoolManager : MonoBehaviour {
// Note that because `ObjectPool<T>` is a generic type, we can't use `ObjectPool<T>`
// as the value type of the dictionary, so we cast to `object`.
private Dictionary<Component, object> _pools;
private Dictionary<Component, object> pools {
get {
if (_pools == null) _pools = new Dictionary<Component, object>();
return _pools;
}
}
public ObjectPool<T> CreatePool<T>(T prefab) where T : Component {
var pool = new ObjectPool<T>(
() => CreateInstance<T>(prefab),
instance => {
instance.gameObject.SetActive(true);
}, instance => {
instance.gameObject.SetActive(false);
}, instance => {
Destroy(instance.gameObject);
}, false, 10, 200);
pools.Add(prefab, pool);
return pool;
}
private ObjectPool<T> GetPool<T>(T prefab) where T : Component {
if (pools.TryGetValue(prefab, out var poolObj)) {
var pool = poolObj as ObjectPool<T>;
return pool;
} else {
return null;
}
}
public T GetInstance<T>(T prefab, Transform parent) where T : Component {
var pool = GetPool<T>(prefab);
if (pool == null) {
pool = CreatePool<T>(prefab);
}
var instance = pool.Get();
if (instance != null) instance.transform.SetParent(parent);
return instance;
}
public void Release<T>(T prefab, T instance) where T : Component {
var pool = GetPool<T>(prefab);
if (pool == null) Debug.LogWarning($"Tried to release {instance}, but there's no pool of type {typeof(T).Name}");
else pool.Release(instance);
}
private T CreateInstance<T>(T prefab) where T : Component {
T instance = Instantiate(prefab);
instance.gameObject.SetActive(false);
return instance;
}
}