무민은귀여워

[유니티] 오브젝트 풀링 본문

IT/Unity

[유니티] 오브젝트 풀링

moomini 2022. 5. 24. 19:27
반응형

1. 오브젝트 풀링

2-1. Poolable.cs

2-2. PoolManager.cs

1. 오브젝트 풀링

오브젝트 풀링은 개체의 생성 삭제 등으로 인한 메모리 부하를 막기 위해, 미리 준비가 된 개체 풀을 만들어 놓고 필요시에 개체를 꺼내쓰고 사용한 개체는 다시 반납하는 방법이다. 

 

오브젝트 풀링 사용 예

@Pool_Root 를 최상위 루트로 하여, 아래에 개체별 개별 풀 {개체이름}_Root 를 만들어 관리한다.

풀 내에 만들어지는 개체들은 비활성 상태로 들어간다.

로그인씬

사용시에는 풀에서 꺼내어 활성상태로 바꿔준다. (ex. UnityChan_Root 에 있던 UnityChan 개체들이 활성 상태로 위로 올라왔다.

game씬

2-1. Poolable.cs

Poolable 인 객체들만을 오브젝트 풀링 대상으로 하기 위함

사용할 프리팹 등에 이 스크립트를 추가한다.

public class Poolable : MonoBehaviour
{
    public bool IsUsing;
}

2-2. PoolManager.cs

Pool 클래스

풀매니저로 관리할 작은 단위의 개별 Pool 이다.

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

            // DontDestroyOnLoad 해제 용도
            if (parent == null)
                poolable.transform.parent = Managers.Scene.CurrentScene.transform;

            poolable.transform.parent = parent;
            poolable.IsUsing = true;

            return poolable;
        }
    }

참고 GetOrAddComponent()

    public static T GetOrAddComponent<T>(GameObject go) where T : UnityEngine.Component
    {
        T component = go.GetComponent<T>();
        if (component == null)
            component = go.AddComponent<T>();
        return component;
    }

PoolManager 구현

    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, int count = 5)
    {
        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.Destroy(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.Destroy(child.gameObject);

        _pool.Clear();
    }
반응형
Comments