Initial Commit
This commit is contained in:
@@ -0,0 +1,135 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using Zenject;
|
||||
|
||||
namespace FlappyBird.Core
|
||||
{
|
||||
public class ObjectPoolManager : IObjectPoolManager, IInitializable
|
||||
{
|
||||
private readonly DiContainer _container;
|
||||
|
||||
private readonly Dictionary<Type, Queue<Component>> _pools = new Dictionary<Type, Queue<Component>>();
|
||||
private readonly Dictionary<Type, GameObject> _prefabs = new Dictionary<Type, GameObject>();
|
||||
private readonly Dictionary<Type, Transform> _poolRoots = new Dictionary<Type, Transform>();
|
||||
|
||||
private Transform _mainPoolRoot;
|
||||
|
||||
[Inject]
|
||||
public ObjectPoolManager(DiContainer container)
|
||||
{
|
||||
_container = container;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the main root transform to keep the scene hierarchy clean.
|
||||
/// </summary>
|
||||
public void Initialize()
|
||||
{
|
||||
_mainPoolRoot = new GameObject("ObjectPools").transform;
|
||||
UnityEngine.Object.DontDestroyOnLoad(_mainPoolRoot);
|
||||
}
|
||||
|
||||
public void RegisterPool<T>(GameObject prefab, int initialSize = 0) where T : Component, IPoolable
|
||||
{
|
||||
Type type = typeof(T);
|
||||
|
||||
if (_pools.ContainsKey(type))
|
||||
{
|
||||
Debug.LogWarning($"[ObjectPoolManager] Pool for type {type.Name} is already registered.");
|
||||
return;
|
||||
}
|
||||
|
||||
_prefabs[type] = prefab;
|
||||
_pools[type] = new Queue<Component>();
|
||||
|
||||
// Create a specific parent transform for this type
|
||||
GameObject rootGo = new GameObject($"{type.Name}_Pool");
|
||||
|
||||
// Check if prefab is a UI element (RectTransform)
|
||||
if (prefab.transform is RectTransform)
|
||||
{
|
||||
// UI elements need to stay under a Canvas even when pooled,
|
||||
// or be moved to a hidden Canvas to stay "initialized"
|
||||
rootGo.AddComponent<RectTransform>();
|
||||
}
|
||||
|
||||
Transform typeRoot = rootGo.transform;
|
||||
typeRoot.SetParent(_mainPoolRoot);
|
||||
_poolRoots[type] = typeRoot;
|
||||
|
||||
// Pre-warm the pool
|
||||
for (int i = 0; i < initialSize; i++)
|
||||
{
|
||||
T instance = CreateInstance<T>();
|
||||
instance.gameObject.SetActive(false);
|
||||
_pools[type].Enqueue(instance);
|
||||
}
|
||||
}
|
||||
|
||||
public T Get<T>() where T : Component, IPoolable
|
||||
{
|
||||
Type type = typeof(T);
|
||||
|
||||
if (!_pools.TryGetValue(type, out Queue<Component> pool))
|
||||
{
|
||||
throw new InvalidOperationException($"Pool for type {type.Name} is not registered.");
|
||||
}
|
||||
|
||||
T instance = (pool.Count == 0) ? CreateInstance<T>() : pool.Dequeue() as T;
|
||||
|
||||
instance.gameObject.SetActive(true);
|
||||
instance.OnSpawned();
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns an item to its respective pool.
|
||||
/// Automatically handles UI parenting back to the pool root.
|
||||
/// </summary>
|
||||
public void Return<T>(T item) where T : Component, IPoolable
|
||||
{
|
||||
if (item == null) return;
|
||||
|
||||
Type type = typeof(T);
|
||||
|
||||
if (!_pools.TryGetValue(type, out Queue<Component> pool))
|
||||
{
|
||||
// Fallback for cases where T might be an interface or base class
|
||||
type = item.GetType();
|
||||
if (!_pools.TryGetValue(type, out pool))
|
||||
{
|
||||
Debug.LogError($"[ObjectPoolManager] No pool registered for {type.Name}");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
item.OnDespawned();
|
||||
|
||||
// Re-parent to the specific pool root to keep Hierarchy clean
|
||||
item.transform.SetParent(_poolRoots[type], false);
|
||||
item.gameObject.SetActive(false);
|
||||
|
||||
pool.Enqueue(item);
|
||||
}
|
||||
|
||||
private T CreateInstance<T>() where T : Component, IPoolable
|
||||
{
|
||||
Type type = typeof(T);
|
||||
GameObject prefab = _prefabs[type];
|
||||
Transform root = _poolRoots[type];
|
||||
|
||||
// Zenject InstantiatePrefab ensures [Inject] works inside the prefab (needed for ScorePopupView)
|
||||
GameObject instance = _container.InstantiatePrefab(prefab, root);
|
||||
T component = instance.GetComponent<T>();
|
||||
|
||||
if (component == null)
|
||||
{
|
||||
component = instance.AddComponent<T>();
|
||||
}
|
||||
|
||||
return component;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user