using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using OHM.UnityToolkit; namespace OHM.UnityToolkit.Pooling { public class PoolsManager : UniqueInstance { [SerializeField] private Transform poolsContainer; [SerializeField] private List preloadPrefabs; private Dictionary pools; public static T InstantiatePrefab(T prefab, Transform parent, Vector3 position, Quaternion rotation, bool startActive = false) where T : Component { PooledObject pooledPrefab = prefab.GetComponent(); if (pooledPrefab != null && Instance != null) { PooledObject instance = Instance.GetObjectFromPrefab(pooledPrefab, parent, position, rotation, startActive); return (instance != null) ? instance.GetComponent() : null; } T plain = UnityEngine.Object.Instantiate(prefab, position, rotation, parent); plain.gameObject.SetActive(startActive); return plain; } public static void ReleasePooledObject(PooledObject pooledObject) { if (pooledObject != null) { pooledObject.Release(); UnityEngine.Object.Destroy(pooledObject.gameObject); } } public static void ReleaseObject(GameObject obj) { if (obj != null) { UnityEngine.Object.Destroy(obj); } } public static IEnumerator DelayReleaseObject(GameObject go, float delay) { yield return new WaitForSeconds(delay); ReleaseObject(go); } public static void ReleaseAllPooledChildren(Transform parent) { if (parent == null) { return; } PooledObject[] pooled = parent.GetComponentsInChildren(true); for (int i = 0; i < pooled.Length; i++) { ReleasePooledObject(pooled[i]); } } protected override void AwakeInstance() { pools = new Dictionary(); if (preloadPrefabs == null) { return; } foreach (PreloadPrefab preload in preloadPrefabs) { Pool pool = GetPoolFromPrefab(preload.prefab); GrowPool(pool, preload.prefab, preload.preloadCount); } } private int GetPrefabPoolId(PooledObject prefab) { return prefab.gameObject.GetInstanceID(); } private Pool GetPoolFromPrefab(PooledObject prefab) { int id = GetPrefabPoolId(prefab); Pool pool; if (!pools.TryGetValue(id, out pool)) { pool = new Pool(); pool.id = id; pool.prefab = prefab; pools[id] = pool; } return pool; } private Pool GetPoolId(int poolId) { Pool pool; pools.TryGetValue(poolId, out pool); return pool; } private PooledObject GetObjectFromPrefab(PooledObject prefab, Transform parent, Vector3 position, Quaternion rotation, bool startActive = false) { Pool pool = GetPoolFromPrefab(prefab); PooledObject obj = null; if (pool.freeObjects.Count >= 1) { obj = pool.freeObjects[pool.freeObjects.Count - 1]; pool.freeObjects.RemoveAt(pool.freeObjects.Count - 1); pool.usedObjets.Add(obj); obj.transform.SetParent(parent); } if (obj == null) { obj = InstantiateObjectForPool(pool, prefab, parent, startActive); } if (obj == null) { return null; } obj.transform.position = position; obj.transform.rotation = rotation; obj.gameObject.SetActive(startActive); obj.Use(); return obj; } private PooledObject InstantiateObjectForPool(Pool pool, PooledObject prefab, Transform parent, bool startActive = false) { bool wasActive = prefab.gameObject.activeSelf; if (wasActive) { prefab.gameObject.SetActive(false); } PooledObject obj = UnityEngine.Object.Instantiate(prefab, parent); if (wasActive) { prefab.gameObject.SetActive(true); } obj.AddToPool(pool.id); obj.name = prefab.name + "_" + pool.totalObjectsCount; pool.totalObjectsCount++; pool.usedObjets.Add(obj); if (startActive) { obj.gameObject.SetActive(true); } return obj; } private void GrowPool(Pool pool, PooledObject prefab, int num) { for (int i = 0; i < num; i++) { ReleaseObject(InstantiateObjectForPool(pool, prefab, poolsContainer)); } } private void ReleaseObject(PooledObject pooledObject) { if (pooledObject == null) { return; } if (!pooledObject.Used) { Debug.LogWarning("Releasing a non used object"); return; } Pool pool = GetPoolId(pooledObject.PoolId); if (pool == null) { Debug.LogWarning("Releasing used object but no pool found"); return; } if (pool.usedObjets.Contains(pooledObject)) { pool.usedObjets.Remove(pooledObject); } pool.freeObjects.Add(pooledObject); pooledObject.Release(); pooledObject.gameObject.SetActive(false); pooledObject.transform.SetParent(poolsContainer); } private void OnApplicationQuit() { Clear(); } private void OnDestroy() { Clear(); } private void Clear() { if (pools == null) { return; } foreach (KeyValuePair entry in pools) { foreach (PooledObject free in entry.Value.freeObjects) { if (free != null) { free.RemoveFromPool(); } } entry.Value.freeObjects.Clear(); foreach (PooledObject used in entry.Value.usedObjets) { if (used != null) { used.RemoveFromPool(); } } entry.Value.usedObjets.Clear(); } pools.Clear(); } public void SaveCurrentToPreloading() { preloadPrefabs.Clear(); foreach (KeyValuePair entry in pools) { var preload = new PreloadPrefab(); preload.prefab = entry.Value.prefab; preload.preloadCount = entry.Value.totalObjectsCount; preloadPrefabs.Add(preload); } } [Serializable] public class PreloadPrefab { public PooledObject prefab; public int preloadCount; } private class Pool { public int id = -1; public PooledObject prefab; public List freeObjects = new List(); public HashSet usedObjets = new HashSet(); public int totalObjectsCount; } } }