Unity 입문 TopDown Shooting - 오브젝트 풀 구현

Amberjack·2024년 1월 19일
0

Unity

목록 보기
14/44

🏊‍♂️ 오브젝트 풀링?

게임 개발에 널리 사용되는 테크닉으로, 게임의 성능을 개선하기 위해 사용한다.

  • 오브젝트 풀링은 객체를 미리 생성해 두고 필요할 때 가져다 사용하고, 사용이 끝나면 다시 풀에 반납하는 방식을 말한다.
  • 오브젝트 풀링은 생성과 소멸이라는 비용이 큰 작업을 최소화 함으로써 성능을 향상시키는 데 중요한 역할을 한다!
  • 특히 빈번하게 생성하고 파괴되는 객체(ex. 총알, 입자 ...)에 대해 중요하며, 이런 객체들을 풀에 저장해 놓고 재사용함으로써 메모리 할당과 갈비지 컬렉션에 따른 성능 저하를 방지할 수 있다.
  • 오브젝트 풀링은 적절히 사용하면 큰 성능 개선을 가져올 수 있지만, 불필요한 메모리 사용을 증가시킬 수 있기 때문에 사용 시 신중해야 하며, 오브젝트 풀의 크기를 적절히 조절하는 것이 중요하다.

⌨️ 오브젝트 풀 만들기

Global 폴더에 ObjectPool.cs를 생성하자!

public class ObjectPool : MonoBehaviour
{
    [System.Serializable]
    public struct Pool
    {
        public string tag;
        public GameObject prefab;
        public int size;
    }

    public List<Pool> pools;    // Pool에 대한 리스트
    public Dictionary<string, Queue<GameObject>> poolDictionary;

    private void Awake()
    {
        poolDictionary = new Dictionary<string, Queue<GameObject>>();       // poolDictionary 생성

        foreach (var pool in pools)
        {
            Queue<GameObject> objectPool = new Queue<GameObject>();
            
            // 위에서 정해 놓은 pool의 사이즈만큼 미리 캐싱하기
            for(int i =0; i < pool.size; i++)
            {
                GameObject obj = Instantiate(pool.prefab);      // pool에 있는 prefab을 생성
                obj.SetActive(false);
                objectPool.Enqueue(obj);
            }
            poolDictionary.Add(pool.tag, objectPool);       // 특정 tag에 대한 프리팹을 사이즈만큼 미리 가지고 있는 것.
        }
    }

    // 풀에서 가져오기
    public GameObject SpawnFromPool(string tag)
    {
        if(!poolDictionary.ContainsKey(tag)) return null;

        // 오브젝트 풀에서 프리팹 꺼내기
        GameObject obj = poolDictionary[tag].Dequeue();
        // 꺼낸 프리팹을 다시 오브젝트 풀에 넣기
        poolDictionary[tag].Enqueue(obj);   // 꺼낸 프리팹을 다시 오브젝트 풀에 넣어 재사용한다.

        return obj;
    }
}

이제 이 오브젝트 풀을 ProjectileManager에게 추가해주자.

그리고 풀에 Arrow를 추가한다.

이후 ProjectileManager에서 코드를 수정한다. 기존에 있던 testObject를 변경해준다.

public class ProjectileManager : MonoBehaviour
{
    [SerializeField] private ParticleSystem _impactParticleSystem;

    public static ProjectileManager instance;

    private ObjectPool objectPool;      // 오브젝트 풀

    public void Awake()
    {
        instance = this;
    }

    void Start()
    {
        // 오브젝트 풀 가져오기
        objectPool = GetComponent<ObjectPool>();
    }

    public void ShootBullet(Vector2 startPosition, Vector2 direction, RangedAttackData attackData)
    {
        GameObject obj = objectPool.SpawnFromPool(attackData.bulletNameTag);

        obj.transform.position = startPosition;
        // 발사되는 코드
        RangedAttackController attackController = obj.GetComponent<RangedAttackController>();
        attackController.InitializeAttack(direction, attackData, this);
        
        obj.SetActive(true);
    }
}

해당 코드로 인해 bulletNameTag가 Object Pool에 등록되어 있는 것을 가져와 생성하게 된다.

오브젝트 풀이 동작하는 모습! ▼


Arrow가 20개가 미리 생성되어 있고 큐를 돌며 계속해서 재사용이 되는 것 까지 확인할 수 있다.

0개의 댓글