Unity - 오브젝트 풀링(Object Pooling)

김도현·2023년 9월 21일
0

TIL

목록 보기
39/76

1. 오브젝트 풀링이란?

Object Pool이란 Object를 필요한 만큼 미리 생성, 보관해 있다가 필요시 꺼내서 사용, 파괴하지 않고 사용한 오브젝트를 맨 뒤에 넣고 재활용 하는 것이다.

2. 오브젝트 풀링이 필요한 이유

게임에서 오브젝트를 생성과 파괴를 할 때 많은 리소스를 사용됩니다. 하지만 소량일 때에는 컴퓨터 성능에 문제가 되지 않지만 대량이 될 경우 가비지 컬렉팅으로 인한 프레임 드랍이 발생합니다.
(가비지 컬렉터(Garbage Collector)이란 C#에서 제공되는 자동 메모리 관리이다. 참조 되어있지 않은 메모리를 찾아 해당 공간의 할당 해제 및 정리를 한다.)

이러한 문제를 해결하기 위해 나타난 것이 Object Pool입니다.

3. 사용 방법

전체 코드

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

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

    public List<pool> pools;
    public Dictionary<string, Queue<GameObject>> poolDictionary;

    private void Awake()
    {
        poolDictionary = new Dictionary<string, Queue<GameObject>>();
        foreach (var pool in pools)
        {
            Queue<GameObject> objectPool = new Queue<GameObject> ();
            for(int i = 0; i < pool.size; i++)
            {
                GameObject obj = Instantiate(pool.prefab);
                obj.SetActive(false);
                objectPool.Enqueue (obj);
            }
            poolDictionary.Add (pool.tag, objectPool);
        }
    }
    public GameObject SpawnFromPool(string tag)
    {
        if (!poolDictionary.ContainsKey(tag))
        {
            return null;
        }
        GameObject obj = poolDictionary[tag].Dequeue();
        poolDictionary[tag].Enqueue (obj);

        return obj;
    }
}

해설

인스펙터상에 값을 입력할 수 있도록 구조체를 직렬화

[System.Serializable]
public struct pool
{
  public string tag;
  public GameObject prefab;
  public int size;
}

인스펙터상에 입력한 pool구조체를 저장할 리스트 pools을 선언
pool의 tag(Key) pool의 sige만큼의 Queue에 객체를 담은(Value) Dictionary인 poolDictionary를 선언

public List<pool> pools;
public Dictionary<string, Queue<GameObject>> poolDictionary;

Awake()에서 인스펙터상에 입력된 값만큼 객체를 생성 및 타입 설정 그리고 SetActive(false)를 통해 화면보이지 않게 합니다.

foreach (var pool in pools)
{
  Queue<GameObject> objectPool = new Queue<GameObject> ();
  for(int i = 0; i < pool.size; i++)
  {
    GameObject obj = Instantiate(pool.prefab);
    obj.SetActive(false);
    objectPool.Enqueue (obj);
  }
  poolDictionary.Add (pool.tag, objectPool);
}

보관되어 있는 객체를 활용하기 위한 메서드
tag를 입력받아 해당 tag가 있는지 확인하여 없으면 null을 반환 있으면 해당 Key에 맞는 Value(큐)의 맨 앞 값을 삭제와 동시에 맨 뒤에 추가, 그리고 그 값을 반환하여 활용 할 수 있게 합니다.

public GameObject SpawnFromPool(string tag)
{
  if (!poolDictionary.ContainsKey(tag))
  {
    return null;
  }
  GameObject obj = poolDictionary[tag].Dequeue();
  poolDictionary[tag].Enqueue (obj);

  return obj;
}

4. 실행하기

위의 스샷처럼 발사된 객체만 활성화 되어 있습니다.

하지만 이러한 Object Pooling에도 문제가 있습니다.

생성된 객체보다 많은 화살을 발사하면 중간에 되돌아 오는 문제가 있다.
이를 해결할려면 size를 늘리던가 아니면 초과한 객체를 추가로 생성하여 보관 하던가 삭제하는 방법을 이용해야 된다.

0개의 댓글