주녘공부일지

[더 챌린저스] 오브젝트 풀링 본문

GameDevelopment/[Unity] Project

[더 챌린저스] 오브젝트 풀링

주녘 2024. 12. 27. 16:50

1) 오브젝트 풀링

- 게임 플레이 중에 반복적으로 생성/파괴되며 사용되는 비용(가비지, 등) 부담을 줄이기 위해 사용

- ResourceMgr에게 생성/파괴 요청된 오브젝트가 풀링 대상이 되는 오브젝트라면 ObjectPoolMgr에게 위탁

public class ObjectPoolMgr
{
    class Pool { ... }

    Dictionary<string, Pool> pools = new Dictionary<string, Pool>();
   
    Transform root;

    int poolCount = 5;

    public void Init()
    {
        if (root == null)
        {
            root = new GameObject { name = "@Pool_Root" }.transform;
        }

        PhotonPrefabPool.Init();
    }

    public void CreatePool(GameObject original, int count)
    {
        Pool pool = new Pool();
        pool.Init(original, count);
        pool.Root.parent = root;

        pools.Add(original.name, pool);
    }

    public void Push(Poolable poolable)
    {
        string name = poolable.gameObject.name;

        if(pools.ContainsKey(name) == false) // 이 경우엔 파괴
        {
            GameObject.Destroy(poolable.gameObject);
            return;
        }

        pools[name].Push(poolable);
    }

    public Poolable Pop(GameObject original, Transform parent = null)
    {
        if (pools.ContainsKey(original.name) == false)
            CreatePool(original, poolCount); // poolCount만큼 생성

        return pools[original.name].Pop(parent);
    }

    public void GeneratePool(GameObject original, int count, Transform parent = null)
    {
        if (pools.ContainsKey(original.name) == true)
        {
            pools.TryGetValue(original.name, out var _pool);
            _pool.Add(original, count);
            return;        
        }

        CreatePool(original, count);
    }
}

 

- 이펙트 사운드를 재생하기 위한 오브젝트들은 사운드매니저에서 게임이 시작될 때 따로 풀링하고 관리

 -> 한번 생성되면 게임을 종료할 때까지 사용하므로 DontDestroyOnLoad로 생성 후 게임 종료 시까지 존재


+ Audio Source 컴포넌트의 3D Sound Setting 메뉴를 활용해 방향에 따라 사운드 방향 및 크기를 조절함

2) 오브젝트 풀링에 의한 끊김 시점 조절 및 개선

- 풀링 시점 제어 ( 캐릭터 소환 시점 -> 로딩 시점에서 플레이할 대상만 풀링 )

- 로딩 후 게임에 들어가면서 끊겨, 로딩 시점에 풀링함으로써 유저 편의성을 높임

 

- BattleScene : 배틀 씬으로 이동 로딩 상태에서 플레이 되는 캐릭터(나, 상대)에 대해서만 풀링

- TrainingScene : 씬 이동 로딩 상태에서 모든 캐릭터 이펙트들을 풀링

public class ObjectPoolMgr
{
    ... // ObjectPool Logic
    
    #region CharacterPool
    
    private bool isCharacterCommonPoolState = false;
    public bool[] isCharacterPoolStates = new bool[(int)ENUM_CHARACTER_TYPE.Max];

    public void GenerateCharacterPoolAll()
    {
        for (int i = 1; i < (int)ENUM_CHARACTER_TYPE.Max; i++)
            GenerateCharacterEffectPool((ENUM_CHARACTER_TYPE)i);
    }

    public void GenerateCharacterEffectPool(ENUM_CHARACTER_TYPE characterType)
    {
        if (isCharacterCommonPoolState == false)
        {
            isCharacterCommonPoolState = true;
            GenerateCommonEffectPool();
        }

        if (isCharacterPoolStates[(int)characterType] == false)
        {
            isCharacterPoolStates[(int)characterType] = true;

            switch (characterType)
            {
                case ENUM_CHARACTER_TYPE.Knight:
                    GenerateKnightEffectPool();
                    break;
                case ENUM_CHARACTER_TYPE.Wizard:
                    GenerateWizardEffectPool();
                    break;
                default:
                    Debug.LogWarning($"없는 캐릭터 : {characterType}");
                    break;
            }
        }
    }

    private static void GenerateCommonEffectPool() { ... }
    private static void GenerateKnightEffectPool() { ... }
    private static void GenerateWizardEffectPool() { ... }
    
    #endregion // << CharacterPool

    public void Clear()
    {
        if (root != null)
        {
            foreach (Transform child in root)
                GameObject.Destroy(child.gameObject);
        }
        pools.Clear();

        isCharacterCommonPoolState = false;
        for (int i = 0; i < isCharacterPoolStates.Length; i++)
            isCharacterPoolStates[i] = false;
    }
}

풀링 시점 개선 전

개선 전

 

 

풀링 시점 개선 후