using System.Collections.Generic; using Core; using UnityEngine; namespace Pooling { /// /// Abstract base class for object pools. /// Provides common functionality for creating, retrieving, and returning pooled objects. /// /// The type of component to pool public abstract class BaseObjectPool : MonoBehaviour where T : Component { [Tooltip("Initial number of objects to pre-instantiate")] public int initialPoolSize = 10; [Tooltip("Maximum number of objects to keep in the pool")] public int maxPoolSize = 30; protected Stack pooledObjects = new Stack(); protected T prefab; protected int totalCreated = 0; protected int totalReturned = 0; /// /// Initialize the pool with the specified prefab /// /// The prefab to use for this pool public virtual void Initialize(T prefabToPool) { prefab = prefabToPool; // Pre-instantiate objects for (int i = 0; i < initialPoolSize; i++) { CreateNew(); } Logging.Debug($"[{GetType().Name}] Initialized with {initialPoolSize} objects"); } /// /// Creates a new instance and adds it to the pool /// protected virtual T CreateNew() { if (prefab == null) { Debug.LogError($"[{GetType().Name}] Prefab is null! Call Initialize first."); return null; } T obj = Instantiate(prefab, transform); obj.gameObject.SetActive(false); // Initialize IPoolable components if present IPoolable poolable = obj.GetComponent(); if (poolable != null) { poolable.OnDespawn(); } pooledObjects.Push(obj); totalCreated++; return obj; } /// /// Gets an object from the pool, or creates a new one if the pool is empty /// /// An object ready to use public virtual T Get() { T obj; if (pooledObjects.Count > 0) { obj = pooledObjects.Pop(); } else { obj = CreateNew(); pooledObjects.Pop(); // Remove from pool since we're returning it } obj.gameObject.SetActive(true); // Call OnSpawn for IPoolable components IPoolable poolable = obj.GetComponent(); if (poolable != null) { poolable.OnSpawn(); } return obj; } /// /// Returns an object to the pool /// /// The object to return public virtual void Return(T obj) { if (obj == null) return; // Call OnDespawn for IPoolable components IPoolable poolable = obj.GetComponent(); if (poolable != null) { poolable.OnDespawn(); } // Only add to pool if we're under the maximum size if (pooledObjects.Count < maxPoolSize) { obj.gameObject.SetActive(false); obj.transform.SetParent(transform); pooledObjects.Push(obj); totalReturned++; } else { Destroy(obj.gameObject); } } /// /// Logs pool statistics /// public virtual void LogPoolStats() { Logging.Debug($"[{GetType().Name}] Pooled objects: {pooledObjects.Count}/{maxPoolSize} (Created: {totalCreated}, Returned: {totalReturned})"); } #if UNITY_EDITOR private float _lastLogTime = 0f; protected virtual void Update() { // Log pool stats every 5 seconds if in the editor if (Time.time - _lastLogTime > 5f) { LogPoolStats(); _lastLogTime = Time.time; } } #endif } }