using System; using System.Collections.Generic; using Core; using Sirenix.OdinInspector; using UnityEngine; namespace Systems { public enum ObjectList { Tile, } public class PoolSystem : SystemBase { [Serializable] private class Poolable { public ObjectList objectType; public GameObject prefab; public int initialSize = 1; [ReadOnly] public int totalInstances; private int _objectCount; private Queue _objectQueue; public void Initialize(Transform inParent) { totalInstances = initialSize; _objectCount = initialSize; _objectQueue = new Queue(); for (var i = 0; i < _objectCount; i++) { var go = Instantiate(prefab, inParent); go.SetActive(false); _objectQueue.Enqueue(go); } } public GameObject GetObject() { if (_objectCount == 0) { totalInstances++; return Instantiate(prefab); } _objectCount--; return _objectQueue.Dequeue(); } public void ResetObject(GameObject inObject) { inObject.SetActive(false); _objectCount++; _objectQueue.Enqueue(inObject); } public void ClearPoolable() { prefab = null; _objectQueue = null; } } [TableList] [SerializeField] private Poolable[] poolObjects; private Dictionary _poolDict; private Dictionary _spawnDict; protected override void ReleaseReferences() { _spawnDict = null; _poolDict = null; foreach (var poolable in poolObjects) poolable.ClearPoolable(); poolObjects = null; } public override void Initialize() { _poolDict = new Dictionary(); _spawnDict = new Dictionary(); foreach (var poolable in poolObjects) { poolable.Initialize(transform); _poolDict.Add(poolable.objectType, poolable); } } public T Spawn(ObjectList inType, bool autoEnable = true) where T : MonoBehaviour { if (!_poolDict.ContainsKey(inType)) { Debug.LogError($"inType [{inType.ToString()}] does not exist in the pool!"); return null; } var spawnedObject = _poolDict[inType].GetObject(); _spawnDict.Add(spawnedObject, inType); if (autoEnable) spawnedObject.SetActive(true); return spawnedObject.GetComponent(); } public T Spawn(ObjectList inType, Transform inParent, bool autoEnable = true) where T : MonoBehaviour { if (!_poolDict.ContainsKey(inType)) { Debug.LogError($"inType [{inType.ToString()}] does not exist in the pool!"); return null; } var spawnedObject = _poolDict[inType].GetObject(); _spawnDict.Add(spawnedObject, inType); if (autoEnable) spawnedObject.SetActive(true); // TODO: Verify spawn/reset positions. var spawnTransform = spawnedObject.transform; spawnTransform.SetParent(inParent, false); spawnTransform.localPosition = Vector3.zero; // spawnTransform.localRotation = inRotation; return spawnedObject.GetComponent(); } public T Spawn(ObjectList inType, Vector3 inPosition, Quaternion inRotation, Transform inParent, bool autoEnable = true) where T : MonoBehaviour { if (!_poolDict.ContainsKey(inType)) { Debug.LogError($"inType [{inType.ToString()}] does not exist in the pool!"); return null; } var spawnedObject = _poolDict[inType].GetObject(); _spawnDict.Add(spawnedObject, inType); if (autoEnable) spawnedObject.SetActive(true); var spawnTransform = spawnedObject.transform; spawnTransform.SetParent(inParent); spawnTransform.localPosition = inPosition; spawnTransform.localRotation = inRotation; return spawnedObject.GetComponent(); } public void Despawn(Transform objectTransform, Action onDespawn = null) { var despawnObject = objectTransform.gameObject; if (!_spawnDict.TryGetValue(despawnObject, out var poolKey)) { Debug.LogError("Object reference not found!", despawnObject); return; } onDespawn?.Invoke(); objectTransform.SetParent(transform); _poolDict[poolKey].ResetObject(despawnObject); _spawnDict.Remove(despawnObject); } } }