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(); } }