유니티(Unity) IObjectPool 을 사용한 오브젝트 풀링(Object Pooling)

개요

게임내에서 많은 오브젝트를 생성하고 파괴하는 과정은 많은 비용을 소모합니다. 비용을 최소화하기 위해 오브젝트 풀링(Object Pooling)을 사용합니다. 미리 오브젝트를 만들어 놓고 필요할 때마다 꺼내서 사용하는 개념으로 생각하면 됩니다.

오브젝트 풀링을 직접 구현할 수도 있고 애셋스토어에 있는 것을 사용해도 됩니다. 그러나 유니티에서 자체적으로 지원합니다. 2021 버전부터 지원합니다.

사용

가장 먼저 생각해 볼 수 있는 것이 플레이어나 적의 탄환입니다. 기본적으로는 탄환 오브젝트를 생성되고 파괴되는 방식으로 구현할 수 있습니다. 이렇게 하지 않고 IObjectPool 을 이용한 방법으로 구현해 보겠습니다.

게임 오브젝트(플레이어 탄환)를 하나 만들고 다음 스크립트를 생성한 후 연결해 줍니다.

public class PlayerBullet : MonoBehaviour
{
    private IObjectPool<PlayerBullet> playerBulletPool;

    public void SetPool(IObjectPool<PlayerBullet> objectPool)
    {
        playerBulletPool = objectPool;
    }

    private void OnBecameInvisible()
    {
        playerBulletPool?.Release(this);
    }
}

플레이어 게임 오브젝트와 연결된 스크립트에서 탄환을 발사하는 코드가 있다고 가정하고 다음과 같이 구현합니다.

public PlayerBullet playerBulletPrefabForPool; //PlayerBullet 클래스가 연결된 게임오브젝트
private IObjectPool<PlayerBullet> playerBulletPool;

private void Awake()
{
    playerBulletPool = new ObjectPool<PlayerBullet>(CreateBullet, OnGetBullet, OnReleaseBullet, OnDestroyBullet, maxSize: 10);
}

private PlayerBullet CreateBullet()
{
    PlayerBullet playerBullet = Instantiate(playerBulletPrefabForPool, playerTransform.position, Quaternion.identity);
    playerBullet.SetPool(playerBulletPool);
    return playerBullet;
}

private void OnGetBullet(PlayerBullet playerBullet)
{
    playerBullet.gameObject.SetActive(true);
    playerBullet.transform.position = playerTransform.position;
}

private void OnReleaseBullet(PlayerBullet playerBullet)
{
    playerBullet.gameObject.SetActive(false);
}

private void OnDestroyBullet(PlayerBullet playerBullet)
{
    Destroy(playerBullet.gameObject);
} 

1행은 PlayerBullet 클래스와 연결된 게임 오브젝트를 정의합니다. 이것을 유니티 에디터에서 연결해 줍니다.

6행은 실제 오브젝트 풀을 생성하고 필요한 메소드들을 정의합니다. 최대 숫자는 10으로 설정했습니다. 화면에 최대로 나타날 수 있는 개수를 고려하여 적절하게 조정합니다. 나머지 부분은 지정한 메소드의 이름으로 각각을 정의합니다.

탄환을 발사하는 부분에서는 다음과 같이 구현합니다. 탄환 게임 오브젝트를 Instantiate 로 생성하지 않고 오브젝트 풀에서 가져오도록 한 것이 가장 큰 차이점 입니다.

var playerBullet = playerBulletPool?.Get(); //오브젝트 풀에서 가져옴
//add your code
//GameObject bullet = Instantiate(playerBullet... //바로 생성

유니티 에디터에서 실행해서 보면 다음과 같이 활성화된 탄환(bullet-circle)과 비활성화된 탄환을 구별할 수 있습니다.

활성/비활성 플레이어 탄환

이렇게 오브젝트 풀링을 사용하면 탄환을 계속 생성/파괴하지 않고 효율적으로 구현할 수 있습니다. 메모리를 더 사용하게 되지만 생성/파괴되는 비용을 크게 낮출 수 있습니다.

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다

Time limit is exhausted. Please reload the CAPTCHA.