Notice
Recent Posts
Recent Comments
Link
«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
Tags
more
Archives
Today
Total
관리 메뉴

zyeon's 작심삼일 코딩 공부

오브젝트 풀링 (오브젝트 풀 패턴) 본문

unity

오브젝트 풀링 (오브젝트 풀 패턴)

젼뀨 2024. 8. 24. 01:24

오브젝트 풀링은 객체 생성과 소멸에 따른 비용을 줄이기 위해, 객체들을 미리 생성한 후 사용하는 디자인 패턴이다.

나는 반복적으로 나오는 장애물과 아이템에 이 오브젝트 풀링을 사용하였다.


오브젝트 풀링은 코드의 유연성, 재사용성, 유지보수성을 높이기 위해 일반적으로 두 개 이상의 클래스를 사용하는 경우가 많다.

 

Poolable 클래스

풀에서 관리될 개별 오브젝트의 동작을 정의한다.

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

public class Poolable : MonoBehaviour
{
    //자신이 속한 풀 참조, 상속을 통한 다양한 오브젝트 타입 구현 가능 
    protected ObjectPool m_pool;

    //오브젝트 풀을 할당하고 오브젝트를 비활성화함
    public virtual void Create(ObjectPool pool)
    {
        m_pool = pool;
        gameObject.SetActive(false);
    }

    //오브젝트를 다시 풀로 반환
    public virtual void Push()
    {
        m_pool.Push(this);
    }
}

풀에서 사용할 수 있도록 초기화 및 반환 메서드를 구현해준다.

 

향후 풀에 들어갈 오브젝트들은 이 Poolable 클래스를 상속한다.

Create()와 Push() 기능은 virtual 키워드에서도 알 수 있듯이 오버라이딩을 통해 향후 기능 확장이 가능하다.


ObjectPool 클래스

오브젝트 풀의 상태와 동작을 관리한다.

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

/* 오브젝트 풀을 관리하는 클래스 */
public class ObjectPool : MonoBehaviour
{
    //풀에 들어갈 오브젝트
    public Poolable m_poolObj; 

    // 미리 할당할 오브젝트의 수
    public int m_allocateCount; 
    public int allocateCount { get { return m_allocateCount; } set { m_allocateCount = value; } }

    //오브젝트를 담고 있는 스택
    Stack<Poolable> m_poolStack = new Stack<Poolable>();

    void Start()
    {
        Allocate();
    }

    //오브젝트 생성
    public void Allocate()
    {
        //count 만큼 생성 후 스택에 담음
        for(int i = 0; i<m_allocateCount; i++)
        {
            Poolable allocateObj = Instantiate(m_poolObj, gameObject.transform);
            allocateObj.Create(this);
            m_poolStack.Push(allocateObj);
        }
    }

    //스택에서 오브젝트를 활성화 시킨 후 반환
    public GameObject Pop()
    {
        Poolable obj = m_poolStack.Pop();
        obj.gameObject.SetActive(this);
        return obj.gameObject;
    }

    //오브젝트를 다시 비활성화 한 후 풀에 반납
    public void Push(Poolable obj)
    {
        obj.gameObject.SetActive(false);
        m_poolStack.Push(obj);
    }
}

 

Allocate()로 원하는 만큼 미리 오브젝트를 생성한 뒤 스택에 쌓아 둔다.

 

사용할 땐  Pop()으로 스택에서 오브젝트를 꺼내 활성화 시키면 되고,

사용이 끝난 후엔 Push()로 오브젝트를 다시 비활성화 한 뒤 다시 스택에 쌓아둔다.


오브젝트 풀링 사용시 설정 방법이다. 

Trap Pool

 

씬에 empty object 생성 후 Object Pool 스크립트 추가 후 원하는 프리팹과 생성 원하는 개수를 넣어준다.

이 때 프리팹에 Poolable을 상속한 코드가 포함되어 있어야한다.

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

public class Trap : Poolable // Poolable 상속
{
    /* 코드 생략 ... */
        
    void Update()
    {
        /* 코드 생략 ... */
        if (this.transform.position.x <= -2.5f)
            Push();
    }

    /* 코드 생략 ... */
}

Push()를 사용하여 오브젝트를 다시 반환해 줄 수 있다.

 

나는 방금 생성 된 empty object에 장애물을 생성해주는 코드도 추가해 주었다.

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

public class CreatingObstacle : MonoBehaviour
{
    // 장애물이 스폰될 위치
    Vector3[] m_posIdx = { new Vector3(1.0f, 1.0f, 1.0f), 
                           new Vector3(10.0f, 1.0f, 1.0f), 
                           new Vector3(20.0f, 1.0f, 1.0f) };
    Coroutine m_coroutine = null;

    void Update()
    {
        if(게임 플레이 중인 조건) m_coroutine = StartCoroutine(SpawnRepeat());
    }

    private IEnumerator SpawnRepeat()
    {
        /* 랜덤 위치 장애물 생성 코드 생략 ... */
        this.GetComponent<ObjectPool>().Pop().transform.position = m_posIdx[randPos1]; 
        m_coroutine = null;
    }
}

ObjectPool 에서 Pop()을 호출하여 오브젝트를 가져올 수 있다.


 

실행 영상

게임 실행 시 하이어라키에 오브젝트가 일괄 생성되는 것을 볼 수 있다. 

생성된 오브젝트들은 사용할 땐 활성화 되고, 사용하지 않을 땐 비활성화 된다.


메모리에 오브젝트를 미리 할당해 놓기 때문에 사용되지 않는 오브젝트가 풀에 존재하는 경우 메모리 사용량이 증가할 수 있으며 초기 로딩 시간도 길어질 수 있다는 점도 유의하자.

'unity' 카테고리의 다른 글

플레이어 상태, 상태 머신  (0) 2024.09.12
2.5D 게임에서 캐릭터 이동 구현  (0) 2024.08.28
싱글톤 패턴  (0) 2024.08.22
WorldToScreenPoint, ScreenToWorldPoint  (0) 2024.08.20
Camera.main 오류 (CS1061)  (0) 2024.08.09