using System.Collections.Generic;
using UnityEngine;
public class PoolManager : IManager
{
#region Pool
///
/// 개별 오브젝트 풀.
///
class Pool
{
// 이 풀이 관리하는 오브젝트의 원본 프리팹 경로
private string _path;
// 이 풀의 오브젝트들을 담아둘 부모 Transform
public Transform Root { get; private set; }
// 비활성화된 오브젝트(재고)를 담아두는 스택
private Stack _poolStack = new Stack();
///
/// 풀 초기화
///
public void Init(string path, int count)
{
_path = path;
GameObject original = Manager.Resource.Load(_path);
if(original == null)
{
Debug.LogError($"Pool Init Failed! Original prefab not found at path: {_path}");
return;
}
Root = new GameObject() { name = $"{original.name}_Root" }.transform;
for (int i = 0; i < count; i++)
{
Push(Create(original));
}
}
///
/// 새 오브젝트 생성. Poolable 컴포넌트를 추가하고 경로를 지정.
///
private GameObject Create(GameObject original)
{
GameObject go = Object.Instantiate(original);
go.name = original.name;
go.AddComponent().Path = _path;
return go;
}
///
/// 다 쓴 오브젝트를 풀에 반납 (비활성화 후 스택에 추가)
///
public void Push(GameObject go)
{
if (go == null) return;
go.transform.SetParent(Root);
go.SetActive(false);
_poolStack.Push(go);
}
///
/// 풀에서 오브젝트를 꺼냄 (재고가 있으면 재고 사용, 없으면 새로 생성)
///
public GameObject Pop(Transform parent)
{
GameObject go;
if (_poolStack.Count > 0)
{
go = _poolStack.Pop();
}
else
{
// 풀이 비었을 경우, 새로 5개를 생성하여 풀에 추가합니다.
GameObject original = Manager.Resource.Load(_path);
for (int i = 0; i < 5; i++)
{
Push(Create(original));
}
// 이제 풀이 채워졌으니, 하나를 꺼내서 사용합니다.
go = _poolStack.Pop();
}
go.SetActive(true);
// @DontDestroyOnLoad 해제 부
// if(parent == null)
// poolable.transform.parent = Managers.Scene.CurrentScene.transform;
go.transform.SetParent(parent);
return go;
}
}
#endregion
// 모든 풀들을 관리하는 딕셔너리. <프리팹 경로, 풀>
private Dictionary _pools = new Dictionary();
private Transform _root;
///
/// PoolManager 초기화. @Pool_Root 오브젝트 생성.
///
public void Init()
{
if (_root == null)
{
_root = new GameObject { name = "@Pool_Root" }.transform;
Object.DontDestroyOnLoad(_root);
}
}
///
/// 게임 시작 시 미리 풀을 생성해 둠.
///
public void CreatePool(string path, int count = 5)
{
if (_pools.ContainsKey(path))
{
Debug.LogWarning($"Pool already exists for path: {path}");
return;
}
Pool pool = new Pool();
pool.Init(path, count);
pool.Root.SetParent(_root);
_pools.Add(path, pool);
}
///
/// 풀에서 오브젝트를 꺼내 사용.
///
public GameObject Pop(string path, Transform parent = null)
{
// 요청한 풀이 없으면 새로 1개짜리 풀을 생성
if (!_pools.ContainsKey(path))
{
CreatePool(path, 1);
}
return _pools[path].Pop(parent);
}
///
/// 사용이 끝난 오브젝트를 풀에 반납.
///
public void Push(GameObject go)
{
// 오브젝트의 Poolable 컴포넌트에서 원본 경로를 찾아냄
string path = go.GetComponent()?.Path;
if (string.IsNullOrEmpty(path) || !_pools.ContainsKey(path))
{
Debug.LogWarning("Push failed! Check if object is poolable or if pool exists.");
Object.Destroy(go);
return;
}
// 경로에 맞는 풀에 오브젝트를 반납
_pools[path].Push(go);
}
///
/// 모든 풀의 오브젝트들을 파괴하고 풀 목록을 초기화.
///
public void Clear()
{
foreach (Transform child in _root)
{
GameObject.Destroy(child.gameObject);
}
_pools.Clear();
}
}