using System.Collections.Generic; using UnityEngine; namespace KhawajjaGames.Utilities { /// /// High-performance, zero-garbage-collection Object Pooling System for Unity. /// Eliminates Instantiate/Destroy overhead for bullets, rockets, explosions, and UI blips. /// Created by Khawajja Games Studio (https://khawajjagames.com) /// public class ObjectPooler : MonoBehaviour { public static ObjectPooler Instance { get; private set; } [System.Serializable] public class PoolItem { [Tooltip("Unique pool identifier tag (e.g. 'Bullet', 'Missile', 'Explosion')")] public string tag; [Tooltip("Prefab to instantiate for this pool")] public GameObject prefab; [Tooltip("Initial number of objects to prewarm in memory")] public int initialSize = 20; [Tooltip("Allow pool to expand if all objects are in active use")] public bool shouldExpand = true; } [Header("Pool Configurations")] public List pools = new List(); private Dictionary> _poolDictionary; private Dictionary _poolConfigs; private void Awake() { if (Instance == null) { Instance = this; } else { Destroy(gameObject); return; } InitializePools(); } private void InitializePools() { _poolDictionary = new Dictionary>(); _poolConfigs = new Dictionary(); foreach (var pool in pools) { Queue objectPool = new Queue(); _poolConfigs[pool.tag] = pool; GameObject parentGroup = new GameObject($"Pool_{pool.tag}"); parentGroup.transform.SetParent(transform); for (int i = 0; i < pool.initialSize; i++) { GameObject obj = Instantiate(pool.prefab, parentGroup.transform); obj.SetActive(false); objectPool.Enqueue(obj); } _poolDictionary.Add(pool.tag, objectPool); } } /// /// Spawns a pooled object by tag at the given position and rotation. /// public GameObject SpawnFromPool(string tag, Vector3 position, Quaternion rotation) { if (!_poolDictionary.ContainsKey(tag)) { Debug.LogWarning($"ObjectPooler: Pool with tag '{tag}' doesn't exist."); return null; } Queue poolQueue = _poolDictionary[tag]; if (poolQueue.Count == 0) { if (_poolConfigs[tag].shouldExpand) { GameObject newObj = Instantiate(_poolConfigs[tag].prefab, transform.Find($"Pool_{tag}")); newObj.transform.position = position; newObj.transform.rotation = rotation; newObj.SetActive(true); return newObj; } else { Debug.LogWarning($"ObjectPooler: Pool with tag '{tag}' is exhausted and cannot expand."); return null; } } GameObject objToSpawn = poolQueue.Dequeue(); objToSpawn.transform.position = position; objToSpawn.transform.rotation = rotation; objToSpawn.SetActive(true); // Trigger IPooledObject interface if implemented var pooledInterface = objToSpawn.GetComponent(); if (pooledInterface != null) { pooledInterface.OnObjectSpawn(); } return objToSpawn; } /// /// Returns an active object back to its respective pool. /// public void ReturnToPool(string tag, GameObject obj) { if (!_poolDictionary.ContainsKey(tag)) { Destroy(obj); return; } obj.SetActive(false); _poolDictionary[tag].Enqueue(obj); } } /// /// Optional interface for objects that need custom initialization when spawned from pool. /// public interface IPooledObject { void OnObjectSpawn(); } }