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