Game/Unity

[유니티] 오브젝트 풀링(Object Pooling)

nowkoes 2023. 4. 13. 16:50

개요

 게임에서 오브젝트를 생성하고 삭제하는 작업은 메모리 사용량이 늘어나는 문제와 성능 저하의 원인이 된다. 예를 들어 FPS 게임에서 플레이어가 총을 쏠 때 매번 탄환을 생성하는 것은 성능적으로 봤을 때 비효율적이다. 이러한 문제점을 해결하기 위해 생긴 개념이 오브젝트 풀링이다.


개념

 오브젝트 풀링게임 오브젝트를 필요한 만큼 미리 생성해 두고 풀에 쌓아두는 기법으로, 오브젝트를 매번 생성하고 삭제하는 것보다 메모리 사용량과 성능 저하를 줄일 수 있다. 다만, 초기에 더 많은 메모리를 사용한다는 단점이 있다. 이 방식은 풀에 오브젝트를 생성한 후, 새로운 오브젝트가 필요할 때 풀에 있는 오브젝트를 가져다 사용하며, 필요가 없어지면 오브젝트를 비활성화하고 풀에 반환하는 방식으로 동작한다.

 

 이해를 돕기 위해, 기존에 Instantiate() 메서드를 이용해 오브젝트를 생성하는 것과 오브젝트 풀링을 이용해 오브젝트를 생성하는 것을 비교해 보겠다.

 

 

 일반적으로 Instantiate() 메서드를 사용하여 GameObject를 생성하고, 메모리 최적화를 위해 Destory를 사용하여 GameObject를 파괴한다. 그러나 오브젝트 풀링을 사용한다면, 미리 컨테이너에 오브젝트를 생성해 놓은 후, 필요할 때 SetActive(true)를 이용해 사용하고, 필요하지 않을 때 SetActive(false)를 이용해 반환한다.


예제

 배운 내용을 바탕으로 Player를 기준으로 Spawn Point에서 정해진 시간마다 오브젝트를 생성하는 예제를 공부해 보자.

 

 먼저 다음과 같이 Cube Object를 생성하고 이름을 Player로 짓는다. 그 후 탄환일 생성된 지점을 빈 오브젝트로 만들고 Player의 자식으로 둔다.

 

 

 Sphere Object를 생성하고 이름을 Bullet으로 지은 후, 프로젝트 창으로 드래그 & 드랍을 하여 프리팹으로 만들어준다.

 

 

 이제 PlayerController라는 스크립트를 만들고 다음과 같이 작성해 보자.

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

public class PlayerController : MonoBehaviour
{
    public GameObject bulletPrefab; // 프리팹화된 탄환
    public GameObject spawnPoint; // 생성 지점
    private int poolSize = 100; // 풀 크기
    private float coolDown = 2f, coolDownCounter; // 생성 쿨타임
    private List<GameObject> pools = new List<GameObject>(); // 풀

    void Start()
    {
        for (int i = 0; i < poolSize; i++)
        {
            GameObject bullet = Instantiate(bulletPrefab);
            bullet.gameObject.SetActive(false);
            pools.Add(bullet);
        } // 풀 초기화

        coolDownCounter = coolDown;
    }

    void Update()
    {
        coolDownCounter -= Time.deltaTime;

        if (coolDownCounter < 0)
        {
            for (int i = 0; i < poolSize; i++)
            {
                if (!pools[i].activeInHierarchy) // 하이라키 창에 pools[i]가 비활성화일 때
                {
                    pools[i].AddComponent<Rigidbody>(); // 속도를 주기 위해 RigidBody 추가
                    pools[i].transform.position = spawnPoint.transform.position;
                    pools[i].transform.rotation = spawnPoint.transform.rotation;
                    pools[i].SetActive(true); // 탄환 사용
                    pools[i].GetComponent<Rigidbody>().velocity = -transform.right; // 방향
                    break;
                }
            }
            coolDownCounter = coolDown;
        }
    }
}

 물론 RigidBody 속성만 추가하여 중력에 의해 떨어지는 등 문제가 많지만, 우리의 목적은 오브젝트 풀링을 구현하는 것이기 때문에 러프하게 작성하였다.

 

2초마다 오브젝트 기준 오른쪽에서 생성되어, 왼쪽으로 떨어짐


요약

오브젝트 풀링
1. 정의: 게임 오브젝트를 필요한 만큼 미리 생성해 두고 풀에 쌓아두는 기법
2. 동작
 a. 풀에 오브젝트를 필요한 만큼 생성
 b. 필요할 때 사용, 필요 없을 때 반환
3. 특징
 a. 메모리 사용량 효율적
 b. 성능 개선
 c. 초기에 메모리를 다소 많이 사용
반응형