오브젝트를 재사용 하기 위해 pool을 사용한다(소규모 게임에서는 굳이 필요 없으나, 규모가 커지고 성능을 높여야 할 때 유용)
풀링할 객체 vs 안 할 객체 구분법 : 특정 컴포넌트의 존재 여부로 판단한다
Assets > Scripts > Managers > Poolable.cs
public class Poolable : MonoBehaviour
{
public bool isUsing;
}
객체를 구별하는 용도의 컴포넌트로 사용한다
Assets > Scripts > Managers > PoolManager.cs (Resource Manager를 보조하는 역할로 사용)
public class PoolManager
{
class Pool
{
public GameObject Original { get; private set; }
public Transform Root { get; set; }
Stack<Poolable> _poolStack = new Stack<Poolable>();
public void Init(GameObject original, int count = 5)
{
Original = original;
Root = new GameObject().transform;
Root.name = $"{original.name}_Root";
for (int i = 0; i < count; i++)
Push(Create());
}
Poolable Create()
{
GameObject go = Object.Instantiate<GameObject>(Original);
go.name = Original.name;
return go.GetOrAddComponent<Poolable>();
}
public void Push(Poolable poolable)
{
if (poolable == null)
return;
poolable.transform.parent = Root;
poolable.gameObject.SetActive(false);
poolable.IsUsing = false;
_poolStack.Push(poolable);
}
public Poolable Pop(Transform parent)
{
Poolable poolable;
if (_poolStack.Count > 0)
poolable = _poolStack.Pop();
else
poolable = Create();
poolable.gameObject.SetActive(true);
// DontDestoryOnLoad 해제 용도
if (parent == null)
poolable.transform.parent = Managers.Scene.CurrentScene.transform;
poolable.transform.parent = parent;
poolable.IsUsing = true;
return poolable;
}
}
Dictionary<string, Pool> _pool = new Dictionary<string, Pool>();
Transform _root;
public void Init()
{
if (_root == null)
{
_root = new GameObject { name = "@Pool_Root" }.transform;
Object.DontDestroyOnLoad(_root);
}
}
public void CreatePool(GameObject original)
{
Pool pool = new Pool();
pool.Init(original, count);
pool.Root.parent = _root;
_pool.Add(original.name, pool);
}
public void Push(Poolable poolable)
{
string name = poolable.gameObject.name;
if (_pool.ContainsKey(name) == false)
{
GameObject.Destory(poolable.gameObject);
return;
}
_pool[name].Push(poolable);
}
public Poolable Pop(GameObject original, Transform parent = null)
{
if (_pool.ContainsKey(original.name) == false)
CreatePool(original);
return pool[original.name].Pop(parent);
}
public GameObject GetOriginal(string name)
{
if (_pool.ContainsKey(name) == false)
return null;
return _pool[name].Original;
}
public void Clear()
{
foreach (Transform child in _root)
GameObject.Destory(child.gameObject);
_pool.Clear();
}
}
#region Pool
// 코드
#endregion
+) 위 명령어로 쉽게 접었다 폈다 할 수 있다
매니저 스크립트에 연결 후, Init 함수와 Clear 함수도 각각 연결해준다
PoolManager _pool = new PoolManager;
public static PoolManager Pool { get { return Instance._pool; } }
Pool Manager에서 작성하였던 함수들을 Resource Manager에서 아래와 같이 추가해준다
public class ResourceManager
{
public T Load<T>(string path) where T : Object
{
if (typeof(T) == typeof(GameObject))
{
string name = path;
int index = name.LastIndexOf('/');
if (index >= 0)
name = name.Substring(index + 1);
GameObject go = Managers.Pool.GetOriginal(name);
if (go != null)
return go as T;
}
return Resources.Load<T>(path);
}
public GameObject Instantiate(string path, Transform parent = null)
{
GameObject original = Load<GameObject>($"Prefabs/{path}");
if (original == null)
{
Debug.Log($"Failed to load prefab : {path}");
return null;
}
if (original.GetComponent<Poolable>() != null)
return Managers.Pool.Pop(original, parent).gameObject;
GameObject go = Object.Instantiate(original, parent);
go.name = original.name;
return go;
}
public void Destory(GameObject go)
{
if (go == null)
return;
Poolable poolable = go.GetComponent<Poolable>();
if (poolable != null)
{
Managers.Pool.Push(poolable);
return;
}
Object.Destory(go);
}
}
'강의, 책 > [Unity] C#과 유니티로 만드는 MMORPG 게임 개발 시리즈' 카테고리의 다른 글
Section 12. Data - Data Manager (0) | 2024.02.04 |
---|---|
Section 11. Coroutine (0) | 2024.02.03 |
Section 9. Sound - Sound Manager(2) (0) | 2024.02.03 |
Section 9. Sound - Sound Manager(1) (0) | 2024.02.02 |
Section 8. Scene - Scene Manager (0) | 2024.01.31 |