using FirstVillain.Singleton; using System; using System.Collections; using System.Collections.Generic; using System.IO; using UnityEngine; using UnityEngine.Pool; namespace FirstVillain.ObjectPool { //GameObject Pooling public class PoolManager : UnitySingleton { [SerializeField] private int _capacity = 10; [SerializeField] private int _maxSize = 1000; [SerializeField] private bool _collectionCheck = true; //À½... Ŭ·¡½º ŸÀÔº°·Î Ç®À» ¸¸µå´Â°Ç? private Dictionary _poolDict = new(); public GameObject Spawn(string path, Transform parent = null) { string name = Path.GetFileName(path); if(!_poolDict.ContainsKey(name)) { CreatePoolItem(path); } var pooledObj = _poolDict[name].Pool.Get(); if (parent != null) { pooledObj.transform.Reset(parent); } return pooledObj; } public T Spawn(string path, Transform parent = null) { return Spawn(path, parent).GetComponent(); } public void ReleaseGameObject(GameObject obj) { if (_poolDict.ContainsKey(obj.name)) { try { obj.transform.Reset(); try { _poolDict[obj.name].Pool.Release(obj); } catch { obj.SetActive(false); } } catch (Exception ex) { Debug.LogError($"Exception has occured!!! Object : {obj.name} === {ex.Message}"); } } else { Debug.LogWarning($"Object[{obj.name}] does not exist in pool dictionary. But it's been destroyed anyway :D"); Destroy(obj); } } #region Create Pool //ÇöÀç Resources.Load ±â¹ÝÀ¸·Î ±¸Çö... public void CreatePoolItem(string path) { string resourceName = Path.GetFileName(path); if(!_poolDict.ContainsKey(resourceName)) { var resource = LoadAssetOnResources(path); var pool = new PoolItem(path, CreateNewObjectPool(resource, resourceName)); _poolDict.Add(resourceName, pool); } } private ObjectPool CreateNewObjectPool(GameObject prefab, string resourceName) { return new ObjectPool( () => { GameObject obj = Instantiate(prefab); obj.name = resourceName; return obj; }, OnGetItem, OnReleaseItem, OnDestroyItem, _collectionCheck /* Collection checks will throw errors if we try to release an item that is already in the pool.*/, _capacity/*defalut capacity*/, _maxSize ); } private void OnGetItem(GameObject obj) { obj.SetActive(true); } private void OnReleaseItem(GameObject obj) { obj.SetActive(false); } private void OnDestroyItem(GameObject obj) { Destroy(obj); } #endregion Create Pool #region Resource Load //¸®¼Ò½º °ü¸®·Î ÀÌÀü ¿¹Á¤ public T LoadAssetOnResources(string resourcePath) where T : UnityEngine.Object { var resourceObj = Resources.Load(resourcePath); if (resourceObj == null) { throw new ResourceCriticalException($"Cannot Load Resources Object [{resourcePath}]"); } return resourceObj; } #endregion Resource Load #region AssetBundle Refresh Shader private void RefreshShader(UnityEngine.Object obj) { //AssetBundleÀº custom shader¸¦ Æ÷ÇÔÇÏÁö ¾ÊÀ¸¹Ç·Î ºÒ·¯¿Ã ½ÃÁ¡¿¡ shader¸¦ Àç¼³Á¤ÇØÁØ´Ù. if (typeof(GameObject) == typeof(T)) { GameObject go = obj as GameObject; if (go.GetComponents() != null) { RefreshShader(go.GetComponents()); } if (go.GetComponentsInChildren(true) != null) { RefreshShader(go.GetComponentsInChildren(true)); } } else if (typeof(Material) == typeof(T)) { RefreshShader(obj as Material); } } private void RefreshShader(Material material) { Shader shader = Shader.Find(material.shader.name); if (shader != null) { material.shader = shader; } else { Debug.LogWarning(string.Format("unable to refresh shader: [{0}] in material [{1}]", material.shader.name, material.name)); } } private void RefreshShader(Renderer[] renderers) { if (null == renderers) { return; } for (int i = 0; i < renderers.Length; i++) { Material[] materials = renderers[i].sharedMaterials; for (int j = 0; j < materials.Length; j++) { if (materials[j] == null) { continue; } RefreshShader(materials[j]); } } } #endregion AssetBundle Refresh Shader } }