Humility

아무리 노력해도 최고가 되지 못할 수 있다⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀그럼에도 노력하는자가 가장 겸손한 것 아닌가

공부하는 블로그

유니티/디자인패턴

[Unity] 유니티 C#) ObjectPool 패턴

새벽_글쓴이 2024. 12. 4. 10:55
반응형

오브젝트 풀

게임에서 자주 생성되고 파괴되는 오브젝트들을 미리 생성해두고 재활용하는 디자인 패턴

 

기본 구현 방법

public class ObjectPool : MonoBehaviour
{
    public GameObject prefab;        // 풀링할 프리팹
    public int poolSize = 20;       // 풀 크기

    private List<GameObject> pool;   // 풀 리스트

    void Start()
    {
        // 풀 초기화
        pool = new List<GameObject>();
        for (int i = 0; i < poolSize; i++)
        {
            CreateNewObject();
        }
    }

    // 새 오브젝트 생성
    private GameObject CreateNewObject()
    {
        GameObject obj = Instantiate(prefab);
        obj.SetActive(false);
        pool.Add(obj);
        return obj;
    }

    // 오브젝트 가져오기
    public GameObject GetObject()
    {
        // 비활성화된 오브젝트 찾기
        for (int i = 0; i < pool.Count; i++)
        {
            if (!pool[i].activeInHierarchy)
            {
                pool[i].SetActive(true);
                return pool[i];
            }
        }

        // 없으면 새로 생성
        return CreateNewObject();
    }
}

 

사용방법

// 오브젝트 풀 사용 예시
public class BulletSpawner : MonoBehaviour
{
    private ObjectPool bulletPool;

    void Start()
    {
        bulletPool = GetComponent<ObjectPool>();
    }

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            // 총알 발사
            GameObject bullet = bulletPool.GetObject();
            bullet.transform.position = transform.position;
        }
    }
}

 

핵심개념

1. 기본 원리

  • 오브젝트를 미리 생성하여 풀(Pool)에 보관
  • 오브젝트가 필요할 때 Instantiate 대신 풀에서 가져옴
  • 사용이 끝난 오브젝트는 Destroy 대신 풀로 반환
  • 반환된 오브젝트는 다시 재사용

2. 핵심동작

  • 초기화: 시작 시 필요한 만큼 오브젝트를 미리 생성
  • 대여(Spawn): 풀에서 비활성화된 오브젝트를 찾아 활성화
  • 반환(Despawn): 사용이 끝난 오브젝트를 비활성화하여 풀로 반환
  • 재활용: 반환된 오브젝트를 다시 사용

 

사용 목적

 

  • 메모리 효율성 향상
  • 성능 최적화 (잦은 생성/파괴 방지)
  • 가비지 컬렉션 부하 감소
  • 일관된 메모리 사용량 유지

 

 

오브젝트 풀 패턴의 장점

1. 성능 향상

  • 잦은 Instantiate/Destroy 호출 감소
  • 가비지 컬렉션 부하 감소
  • 메모리 할당/해제 최소화

2. 메모리관리

  • 사전 할당으로 메모리 사용량 예측 가능
  • 런타임 중 메모리 단편화 감소

3. 자원 재활용

  • 오브젝트 재사용으로 효율성 증가
  • 동적 할당 오버헤드 감소

 

주요 사용 사례

 

  • 총알, 파티클 효과
  • 적 캐릭터
  • 아이템, 수집품
  • UI 요소
  • 프로젝타일

 

 

사용 사례 예시

총알

public class BulletPool : MonoBehaviour 
{
    [SerializeField] private GameObject bulletPrefab;
    private Queue<GameObject> bullets = new Queue<GameObject>();

    private void Start() 
    {
        // 총알 30개 미리 생성
        for (int i = 0; i < 30; i++) 
        {
            GameObject bullet = Instantiate(bulletPrefab);
            bullet.SetActive(false);
            bullets.Enqueue(bullet);
        }
    }

    public GameObject GetBullet() 
    {
        if (bullets.Count > 0) 
        {
            GameObject bullet = bullets.Dequeue();
            bullet.SetActive(true);
            return bullet;
        }
        return null;
    }
}

 

파티클

public class ParticlePool : MonoBehaviour 
{
    private Queue<ParticleSystem> particles = new Queue<ParticleSystem>();

    public ParticleSystem GetParticle() 
    {
        ParticleSystem particle = particles.Count > 0 ? particles.Dequeue() : null;
        if (particle != null) 
        {
            particle.gameObject.SetActive(true);
            particle.Play();
        }
        return particle;
    }
}

 

적 캐릭터

public class EnemyPool : MonoBehaviour 
{
    private Queue<Enemy> enemies = new Queue<Enemy>();
    
    public Enemy SpawnEnemy(Vector3 position) 
    {
        Enemy enemy = enemies.Count > 0 ? enemies.Dequeue() : null;
        if (enemy != null) 
        {
            enemy.transform.position = position;
            enemy.gameObject.SetActive(true);
            enemy.ResetEnemy(); // 적 상태 초기화
        }
        return enemy;
    }
}

 

UI 요소 ( 데미지 텍스트 등 )

public class DamageTextPool : MonoBehaviour 
{
    private Queue<TextMeshProUGUI> damageTexts = new Queue<TextMeshProUGUI>();

    public void ShowDamageText(Vector3 position, int damage) 
    {
        if (damageTexts.Count > 0) 
        {
            var text = damageTexts.Dequeue();
            text.text = damage.ToString();
            text.transform.position = position;
            text.gameObject.SetActive(true);
            StartCoroutine(HideText(text, 1f));
        }
    }
}

 

 

결론

1. 주요 사용 이유

  • 성능 최적화: Instantiate/Destroy 호출 감소로 성능 향상
  • 메모리 관리: 일관된 메모리 사용으로 가비지 컬렉션 부하 감소
  • 리소스 효율성: 오브젝트 재사용으로 시스템 자원 절약

2. 적합한 상황

  • 자주 생성/파괴되는 오브젝트가 있을 때
  • 동시에 많은 오브젝트가 필요할 때
  • 실시간 성능이 중요한 게임에서

3. 주의사항

  • 초기 메모리 사용량 증가 고려
  • 풀 크기의 적절한 설정 필요
  • 오브젝트 재사용 시 상태 초기화 관리
오브젝트 풀 패턴은 게임의 성능과 리소스 관리를 최적화하는데
매우 효과적인 디자인 패턴이다
모바일 게임이나 많으 객체를 다루는 뱀서류 같은

게임에서는 필수적인 최적화 도구일 것이다.
반응형