끝이 보인다~~(아님)
PoolManager - 2
어제는 PoolManager의 내부 클래스 Pool 에 대해 작성했다.
그렇다면 PoolManager 자체에선 어떤 역할을 하는지 오늘 작성해보자.
일단 내부클래스에 Pool 이 있다는것은... PoolManager 에서 각 오브젝트에 대해 모든 Pool 을 관리한다는 뜻이고
이 Pool 들을 관리하기 위해선 어떠한 자료구조가 필요한데 Dictionary를 쓰도록한다.
private Dictionary<string, Pool> _poolDict = new Dictionary<string, Pool>();
Key 로 string을 사용한다.
그럼 string은 어떤것이 들어가는 것일까?
바로 프리팹 원본의 이름이다.
public void CreatePool(GameObject origin, int count = 5)
{
Pool pool = new Pool();
pool.Init(origin, count);
pool.Root.parent = _root;
_poolDict.Add(origin.name, pool);
}
최초에 Pool 이 생성이 될 때, 원본이 되는 프리팹 origin 과 Pool 에 미리 담아놓을 5개의 count를 받아 Pool 생성을 한다.
Pool 을 생성하고 Init 함수로 Pool 을 만들어 준다.
Pool 의 Root 의 parent 는
Pool Root에 하위에 대기중인 미리 생성된 프리팹 들이 있다.
그리고 그 Pool Root 또한 어떤 부모의 하위에 있다.
그 parent 를 의미하고 이는 _root 이다.
마지막으로 Dictionary 에 Pool을 저장한다. Key 는 origin.name이다.
그렇다면 _root 는 어디서 나온걸까?
private Transform _root;
public void Init()
{
if(_root == null)
{
_root = new GameObject("@Pool_Root").transform;
Object.DontDestroyOnLoad(_root);
}
}
바로 매니저가 처음 만들어지고 실행되는 Init 함수에서 생성을 한다.
Pooling 자체는 어느 씬에서나 적용이 될 수 있기 때문에 _root 가 비어있으면 새로운 Root 오브젝트를 만들어주고
DontDestoryOnLoad를 통해 씬을 넘어가도 파괴 되지 않도록 한다.
다음은 실제로 Scene 에서 쓰였던 오브젝트를 Pool 에 반환을 할 때, 어제 작성한 내부클래스 Pool 에 접근하려면
반드시 PoolManager의 어떤 함수를 거쳐서 반환을 하게 된다.
이는 Push 함수를 이용한다.
public void Push(Poolable poolable)
{
if (_poolDict.ContainsKey(poolable.name) == false)
{
Object.Destroy(poolable.gameObject);
return;
}
_poolDict[poolable.name].Push(poolable);
}
먼저 Push를 할 Poolable을 넘겨준다.
Pooling 대상은 모두 Poolable 스크립트를 컴포넌트로 들고 있으니 직관적으로 받아올 수 있다.
그 다음 Dictionary 에 poolable.name 의 키, 즉 보관할 오브젝트의 이름을 확인해 해당하는 키가 Dictionary에 있는지
체크한다.
참고로 이번에 쓰인 오브젝트들은 Instantiate 로 생성되었지만 이름을 수정했기 때문에 (clone) 이 없는 상태로,
원본 프리팹과 이름이 동일하다.
만약 Poolable 이 있지만 해당 오브젝트 이름의 키가 없다면 바로 삭제 시키도록 한다.
하지만 이런 경우는 거의 없다고 보면 된다.
해당하는 키가 있다면 Pool 에 Push를 해줘서 보관하도록 한다.
다음은 PoolManager를 이용해 오브젝트를 꺼내쓰는 작업이다.
Pop 함수를 이용한다.
public Poolable Pop(GameObject origin, Transform parent = null)
{
if(_poolDict.ContainsKey(origin.name) == false)
CreatePool(origin);
return _poolDict[origin.name].Pop();
}
Poolable 을 반환하는 Pop 함수는 실제로 꺼내 쓸 오브젝트의 원본과, 부모가 될 Transform을 받는다.
딱히 부모를 지정할 필요가 없을 수도 있으니 null 을 기본값으로 둔다.
만약 Pop을 했는데 씬에 있지도 않은 오브젝트를 꺼내 쓰려고 하면 해당 오브젝트에 대한 새로운 Pool 을 생성한다.
만약 Pool을 새로 생성했다면 origin 의 name 키로 Dictionary 에 추가 되었으니
바로 Dictionary 의 Pool에서 꺼내 쓰면 된다.
다음은 Resources.Load 남용을 피하기 위한 함수 GetOrigin 이다.
public GameObject GetOrigin(string name)
{
if (_poolDict.ContainsKey(name) == false)
return null;
return _poolDict[name].Origin;
}
Pop을 실행 시키기 전 실제 원본 프리팹을 가져올 때,
이미 Pool 이 존재한다면 Resources.Load 를 이용해 매번 프리팹을 새로 불러올 필요 없이
Dictionary 에 있는 Pool 에서 원본을 가져오면 된다.
이 코드는 ResourceManager 와 연계되는데
public GameObject Instantiate(string path, Transform parent = null)
{
GameObject origin = Load<GameObject>($"Prefabs/{path}");
if (origin == null)
{
Debug.Log($"오브젝트 불러오기에 실패했습니다. : {path}");
return null;
}
if(origin.GetComponent<Poolable>() != null)
return Managers.Pool.Pop(origin, parent).gameObject;
GameObject go = Object.Instantiate(origin, parent);
go.name = origin.name;
return go;
}
ResourceManager (이하 RM) 에서 Instantiate 를 통해 GameObject를 생성할 때,
원본 GameObject 를 Load 라는 함수를 통해(Resources.Load 가 아니다.) 받아와
이후 절차를 진행하게 되는데
여기서 Load 함수를 통해 Pooling이 되어있는 오브젝트인지 확인 후 불필요한 Load를 줄여준다.
public T Load<T>(string path) where T : UnityEngine.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.GetOrigin(name);
if (go != null)
return go as T;
}
return Resources.Load<T>(path);
}
GameObject go 가 PoolManager 의 GetOrigin 함수를 통해 불러올 수 있는 오브젝트이면 바로 PoolManager 에서 꺼낸다.
즉 불필요한 소요를 줄이는 함수 GetOrigin 이다.
마지막으로 Pool_Root 의 모든 자식들을 지우는 Clear 함수이다.
public void Clear()
{
foreach (Transform child in _root)
Object.Destroy(child.gameObject);
_poolDict.Clear();
}
Clear 를 해주는 이유는
씬을 전환했을 때 DontDestoryOnLoad 에 의해 Pool_Root의 자식이 남아있으면
A 씬에서 쓰던 오브젝트가 B 씬에서는 안 쓰일 수도 있지만 그대로 남아있게 되므로
씬이 넘어갈 때 모든 하위 Root 들을 지워준다.
그 후 Dictionary도 Clear 로 말끔히 지워준다.
'스파르타 내배캠' 카테고리의 다른 글
스파르타 내배캠 Unity 3기 39일차 (0) | 2024.02.19 |
---|---|
스파르타 내배캠 Unity 3기 38일차 (1) | 2024.02.18 |
스파르타 내배캠 Unity 3기 36일차 (0) | 2024.02.13 |
스파르타 내배캠 Unity 3기 35일차 (0) | 2024.02.09 |
스파르타 내배캠 Unity 3기 34일차 (1) | 2024.02.08 |