149 lines
4.5 KiB
C#
149 lines
4.5 KiB
C#
|
|
using System.Collections.Generic;
|
|||
|
|
using UnityEngine;
|
|||
|
|
|
|||
|
|
namespace Pooling
|
|||
|
|
{
|
|||
|
|
/// <summary>
|
|||
|
|
/// Abstract base class for object pools.
|
|||
|
|
/// Provides common functionality for creating, retrieving, and returning pooled objects.
|
|||
|
|
/// </summary>
|
|||
|
|
/// <typeparam name="T">The type of component to pool</typeparam>
|
|||
|
|
public abstract class BaseObjectPool<T> : 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<T> pooledObjects = new Stack<T>();
|
|||
|
|
protected T prefab;
|
|||
|
|
protected int totalCreated = 0;
|
|||
|
|
protected int totalReturned = 0;
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Initialize the pool with the specified prefab
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="prefabToPool">The prefab to use for this pool</param>
|
|||
|
|
public virtual void Initialize(T prefabToPool)
|
|||
|
|
{
|
|||
|
|
prefab = prefabToPool;
|
|||
|
|
|
|||
|
|
// Pre-instantiate objects
|
|||
|
|
for (int i = 0; i < initialPoolSize; i++)
|
|||
|
|
{
|
|||
|
|
CreateNew();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
Debug.Log($"[{GetType().Name}] Initialized with {initialPoolSize} objects");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Creates a new instance and adds it to the pool
|
|||
|
|
/// </summary>
|
|||
|
|
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<IPoolable>();
|
|||
|
|
if (poolable != null)
|
|||
|
|
{
|
|||
|
|
poolable.OnDespawn();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
pooledObjects.Push(obj);
|
|||
|
|
totalCreated++;
|
|||
|
|
return obj;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Gets an object from the pool, or creates a new one if the pool is empty
|
|||
|
|
/// </summary>
|
|||
|
|
/// <returns>An object ready to use</returns>
|
|||
|
|
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<IPoolable>();
|
|||
|
|
if (poolable != null)
|
|||
|
|
{
|
|||
|
|
poolable.OnSpawn();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return obj;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Returns an object to the pool
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="obj">The object to return</param>
|
|||
|
|
public virtual void Return(T obj)
|
|||
|
|
{
|
|||
|
|
if (obj == null) return;
|
|||
|
|
|
|||
|
|
// Call OnDespawn for IPoolable components
|
|||
|
|
IPoolable poolable = obj.GetComponent<IPoolable>();
|
|||
|
|
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);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Logs pool statistics
|
|||
|
|
/// </summary>
|
|||
|
|
public virtual void LogPoolStats()
|
|||
|
|
{
|
|||
|
|
Debug.Log($"[{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
|
|||
|
|
}
|
|||
|
|
}
|