Unity Pooling System (최적화 구웃!)

Pooling이란?

Unity의 풀링 시스템은 런타임 중에 게임 오브젝트를 효율적으로 관리하고 재사용하는 데 사용되는 기술로, 특히 총알, 적, 파티클과 같은 오브젝트를 자주 생성하고 소멸해야 할 때 유용합니다. 오브젝트를 지속적으로 생성하고 소멸하는 오버헤드를 줄여 성능을 개선하는 데 도움이 됩니다.

작동 방식에 대한 간단한 설명은 다음과 같습니다

작동 방식


초기화 : 특정 유형(예: 총알)의 게임 오브젝트 풀을 생성하는 것으로 시작합니다. 초기화된 게임오브젝트들은 시작과 동시에 비활성화됩니다.

오브젝트 요청: 오브젝트가 필요한 경우 새 오브젝트를 생성하는 대신 풀에서 오브젝트를 요청합니다. 풀은 사용 가능한 오브젝트를 계속 관리해 줍니다.

활성화 및 사용: 풀은 이미 초기화된 풀에서 오브젝트를 제공합니다. 개체를 활성화(표시 및 구성 요소 활성화)하고 사용하면 됩니다.

객체 반환하기: 객체 사용이 끝나면 풀에 반환합니다. 여기에는 비활성화(구성 요소 비활성화)하고 재사용할 수 있도록 표시하는 작업이 포함됩니다.



Unity에서 오브젝트 풀링을 사용하면 얻을 수 있는 몇 가지 이점은 다음과 같습니다

이점 설명
성능 향상 객체를 자주 생성하고 파괴하면 리소스가 많이 소모됩니다. 오브젝트 풀링은 오버헤드를 줄여 성능향상에 도움을 줍니다.
메모리 효율성 풀링된 객체는 재사용되므로 새 객체를 위한 메모리를 매번 할당할 필요가 없습니다.
가비지 컬렉션 회피 객체를 자주 생성하면 가비지 컬렉션을 유발할 수 있으며, 이는 성능 저하로 이어질 수 있습니다. 오브젝트 풀링은 가비지 컬렉션(CG)을 최소화합니다.

 


싱글톤 / 테스트 풀링 (1)

 

테스트를 위해 TestPooling을 싱글톤으로 만들어주었습니다. 

 

두고두고 써먹는 싱글톤(SingleTon) 코드

일반적인 싱글톤 패턴 using UnityEngine; public class Singleton : MonoBehaviour where T : MonoBehaviour { private static T instance; public static T Instance { get { instance = (T)FindObjectOfType(typeof(T)); if (instance == null) { var ob = new Ga

wlsdn629.tistory.com

 

Prefab

풀링 될 오브젝트는 poolPrefab을 통해 만들어낼 수 있습니다.

poolPrefab의 경우 Queue로 관리됩니다.

 


Init

Init함수를 이용하여 poolngQueue에 집어넣을 객체를 만들어냅니다.

 

 


CreateObject

Init함수에서 호출하는 함수입니다. Instantiate를 통해 poolPrefab을 생성함과 동시에 SetActive(false)로 비활성화해줍니다.

 


 

테스트 풀링 (2)

 

GetObject

GetObject 함수를 통해 Pool에서 사용가능한 객체를 끄집어냅니다.

 

Pool에 가져갈 객체가 있다면 Dequeue를 통해 빼낸 후, 게임오브젝트를 켜줍니다.

 

만약 Pool이 비어있다면 하나 생성해서 주면 됩니다.

 


ReturnObject

ReturnObject함수는 가져간 객체들을 다시 Pool로 갖고 오는 함수입니다.

 

 


 

위에 예시는 Object Pooling에 대한 간단한 설명일 뿐입니다.

 

필요에 따라 Object Pooling을 개조하시면 됩니다.


전체 코드

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

public class Pooling : Singleton<Pooling>
{
    public GameObject poolPrefab;

    private Queue<GameObject> poolingQueue = new Queue<GameObject>();

    private void Awake()
    {
        Init(10);   
    }

    void Init(int count)
    {
        for (int i = 0; i < count; i++)
        {
            poolingQueue.Enqueue(CreateObject());
        }
    }

    public void ReturnObject(GameObject obj)
    {
        obj.transform.SetParent(this.gameObject.transform, true);
        obj.SetActive(false);
        poolingQueue.Enqueue(obj);
    }

    public GameObject CreateObject()
    {
        var obj = Instantiate(poolPrefab, transform);
        obj.gameObject.SetActive(false);
        return obj;
    }

    private GameObject GetObject()
    {
        if (poolingQueue.Count > 0)
        {
            var obj = poolingQueue.Dequeue();
            obj.transform.SetParent(null);
            obj.SetActive(true);
            return obj;
        }
        else
        {
            var obj = CreateObject();
            obj.transform.SetParent(null);
            obj.SetActive(true);
            return obj;
        }
    } 
}