유니티에서 오브젝트 풀 만들기 Object Pool 1 – Pooled Object 정의하기

유니티에서 오브젝트 풀 만들기 Object Pool 1 – Pooled Object 정의하기

object pool

오브젝트 풀 시리즈 전체

오브젝트 풀 Object Pool

오브젝트 풀은 객체들을 미리 배열이나 리스트에 저장해두고 필요할 때 활성화해서 쓰고, 다 쓴 후에는 비활성화해서 반환하는 방식으로 객체를 재사용하는 것을 말합니다. 이렇게 관리하면 객체를 메모리에서 해제하지 않기 때문에 메모리 관리면에서 얻을 수 있는 이점이 많습니다.

특히 모노 .Net을 사용하는 유니티의 경우 가비지 컬렉션 Garbage Collection이 발생하면 성능에 무리를 줄 수 있기 때문에, 가비지 컬렉션이 자주 발생하지 않도록 하는 방향으로 메모리를 관리하는 것이 좋습니다. 하지만 자주 사용하는 객체들은 메모리의 할당과 해제가 반복되기 때문에 이 경우에 오브젝트 풀을 사용하면 가비지 컬렉션이 발생하는 것을 피할 수 있습니다.

유니티에서 자주 사용하는 객체가 많은 경우에 필수적으로 사용해야 하는 오브젝트 풀을 만들어 보겠습니다. 오브젝트 풀을 만들 때 구현할 수 있는 방법이 많지만, 기능을 최소한으로 해서 예제를 진행하겠습니다.

아래에 나열한 두 가지를 기본으로 해서 예제를 진행하겠습니다. 사실, 필요한 객체를 검색할 때 이름으로 검색하는 것 보다는 숫자로 검색이 가능하도록 테이블을 미리 만들어서 구현하는 방법이 속도면에서 더 좋겠지만 개념을 이해하기 위해서 이름으로 바로 검색하는 오브젝트 풀을 만들겠습니다.

  • 필요한 객체를 요청하고, 사용한 객체를 반환할 때 객체의 이름으로 검색
  • 여러 객체들을 저장할 때 리스트List 사용

PooledObject

이번 강좌에서는 재사용 될 객체를 정의하는 클래스를 작성해보겠습니다. Create->C# Script 메뉴를 이용해서 스크립트를 추가한 뒤 PooledObject로 이름을 지정합니다. 스크립트 생성이 완료되었으면 아래 내용을 추가합니다.

 
[System.Serializable] 
public class PooledObject 
{
    public string poolItemName = string.Empty;     
    public GameObject prefab = null;     
    public int poolCount = 0;     
    [SerializeField]     
    private List<GameObject> poolList = new List<GameObject>();     

    public void Initialize(Transform parent = null) { }     
    public void PushToPool(GameObject item, Transform parent = null) { }     
    public GameObject PopFromPool(Transform parent = null) { }     
    private GameObject CreateItem(Transform parent = null) { } 
} 

먼저 재사용 될 객체를 관리하는 데 필요한 변수들을 선언합니다. 각 변수들의 역할은 다음과 같습니다.

  • poolItemName : 객체를 검색할 때 사용할 이름
  • prefab : 오브젝트 풀에 저장할 프리팹
  • poolCount : 초기화할 때 생성할 객체의 수
  • poolList : 생성한 객체들을 저장할 리스트

변수 선언이 완료되었으면, 메소드를 추가해서 기능을 구현합니다. 위의 스크립트를 참고해서 필요한 함수들을 선언한 뒤 내용을 하나하나 채워보겠습니다. 먼저 Initialize 함수입니다.

public void Initialize(Transform parent = null) 
{     
    for (int ix = 0; ix < poolCount; ++ix)     
    {
          poolList.Add(CreateItem(parent));     
    }
}

이 함수는 PooledObject 객체를 초기화 할 때 처음 한번만 호출하고, poolCount에 지정한 수 만큼 객체를 생성해서 poolList 리스트에 추가하는 역할을 합니다. 이렇게 처음에 필요한 객체를 미리 생성해서 리스트에 저장해둡니다. Transform  타입의 parent 파라미터는 생성된 객체들을 정리하는 용도로 사용됩니다. 지정을 하지 않으면 ObjectPool 게임 오브젝트의 자식 게임 오브젝트로 기본 지정되고, parent에 다른 Transform 을 지정하면, 그 Transform의 자식 게임오브젝트로 지정됩니다.

그 다음에 PushToPool 함수를 작성하겠습니다.

 
public void PushToPool(GameObject item, Transform parent = null) 
{     
    item.transform.SetParent(parent);     
    item.SetActive(false);     
    poolList.Add(item); 
}

이 함수는 사용한 객체를 다시 오브젝트 풀에 반환할 때 사용할 함수입니다. 반환할 게임 오브젝트를 item 파라미터로 전달하고, 부모 Transform 정보가 필요한 경우 함께 전달합니다. 이 함수 역시 parent를 지정하지 않으면 기본으로 ObjectPool 게임 오브젝트의 자식으로 지정됩니다.

이어서 PopFromPool 함수를 작성합니다.

 
public GameObject PopFromPool(Transform parent = null) 
{     
    if (poolList.Count == 0)         
        poolList.Add(CreateItem(parent));     
    GameObject item = poolList[0];     
    poolList.RemoveAt(0);     
    return item; 
}

이 함수는 객체가 필요할 때 오브젝트 풀에 요청하는 용도로 사용할 함수입니다. 먼저 저장해둔 오브젝트가 남아있는 지 확인하고, 없으면 새로 생성해서 추가합니다. 그리고 미리 저장해 둔 리스트에서 하나를 꺼내고 이 객체를 반환합니다.

PopFromPool 함수 작성까지 완료했으면, 객체를 생성하는 데 사용할 CreateItem 함수를 작성하겠습니다.

 
private GameObject CreateItem(Transform parent = null) 
{     
    GameObject item = Object.Instantiate(prefab) as GameObject;     
    item.name = poolItemName;     
    item.transform.SetParent(parent);     
    item.SetActive(false);     
    return item; 
}

이 함수는 prefab 변수에 지정된 게임 오브젝트를 생성하는 역할을 합니다. PooledObject 클래스 안의 여러 곳에서 객체 생성이 필요할 때 마다 사용합니다. 내용을 살펴보면, prefab에 지정한 정보를 바탕으로 게임오브젝트를 새로 생성하고, poolItemName에 지정한 이름을 새로 생성한 게임오브젝트 이름으로 지정합니다. 이어서 부모 계층을 지정한 뒤에, 생성한 게임오브젝트를 비활성화시켜서 나중에 사용할 수 있도록 준비합니다.

CreateItem 함수까지 작성이 완료되면 PooledObject 클래스의 작성이 완료되었습니다. 다음 강좌에서, 열심히 작성한 PooledObject 클래스를 사용하는 오브젝트 풀 시스템을 만들어 보겠습니다.

내용 끝까지 읽어주셔서 감사합니다.
배너 클릭은 저에게 많은 힘이 됩니다.
감사합니다 🙂

RonnieJ

프리랜서 IT강사로 활동하고 있습니다. 게임 개발, 웹 개발, 1인 기업, 독서, 책쓰기에 관심이 많습니다.

4 Responses

  1. 야르르야 댓글:

    발사기능때문에 들어왔는데 무작정 따라하기엔 좀 어렵네요 그냥 타이핑해도 존재하지않는 문맥의 무언가를 작성하는건지 비쥬얼스튜디오 죄다 빨간줄 ..

    • RonnieJ 댓글:

      안녕하세요~블로그 방문 감사드립니다.
      코드가 웹에 올라가면서 이상한 문자로 바뀐 부분이 좀 있네요.
      (코드를 올리다 보면 간혹 발생하는 문제입니다ㅠ)
      수정했으니 이제 문제 없을 거에요~

  2. ㅇㅇ 댓글:

    잘 보았습니다. 그런데 pooledobject가 모노비헤이비어를 상속하지 않도록 하는 이유가 무엇인가요?

    • RonnieJ 댓글:

      게임 오브젝트에 추가되어 동작하는 클래스(컴포넌트)는 모노비헤이비어를 상속해야 하는데,
      PooledObject 클래스는 그럴 필요가 없어 상속하지 않았습니다.

      블로그 방문 감사합니다.
      배너 클릭은 저에게 큰 도움이 됩니다 🙂

댓글 남기기

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다