Skip to main content
added 2094 characters in body
Source Link
Kevin
  • 7k
  • 1
  • 12
  • 32
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;
    }
}

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;
    }
}
public class PoolManager : MonoBehaviour {
    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;
    }
}
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;
    }
}

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;
    }
}
added 1771 characters in body
Source Link
Kevin
  • 7k
  • 1
  • 12
  • 32
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 ;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!
}

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. I don't have time at the moment to writeIt would look something like this:

public class PoolManager : MonoBehaviour {
    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 full exampleseparate 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).

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!
}

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. I don't have time at the moment to write a full example for that.

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!
}

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 {
    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).

deleted 2 characters in body
Source Link
Kevin
  • 7k
  • 1
  • 12
  • 32

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 CreateProjectileCreateInstance()
    {
        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. I don't have time at the moment to write a full example for that.

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 CreateProjectile()
    {
        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. I don't have time at the moment to write a full example for that.

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. I don't have time at the moment to write a full example for that.

Source Link
Kevin
  • 7k
  • 1
  • 12
  • 32
Loading