
오브젝트 풀링(Object Pooling)은 게임 개발에서 성능 최적화를 위해 자주 사용되는 기법 중 하나다. 게임 내에서 오브젝트를 자주 생성하거나 파괴할 경우 메모리 할당과 해제로 인해 성능 저하가 발생할 수 있다. 이를 방지하기 위해 오브젝트 풀이라는 개념을 사용한다.
오브젝트 풀링의 핵심 아이디어는 미리 오브젝트를 일정량 생성해 두고, 필요할 때 재활용하는 것이다. 게임에서 특정 오브젝트가 필요할 때마다 새로 생성하는 대신, 오브젝트 풀에서 비활성화된 오브젝트를 찾아 재활성화하여 사용하는 방식이다. 이를 통해 오브젝트 생성과 삭제에 따른 성능 부담을 크게 줄일 수 있다.
오브젝트 풀링의 주요 과정:
오브젝트 풀 초기화: 다양한 오브젝트(적, 총알, 아이템 등)를 미리 생성하여 풀에 저장한다.
오브젝트 요청: 필요할 때 풀에서 비활성화된 오브젝트를 찾아 재활성화하여 반환한다.
오브젝트 반환: 더 이상 사용되지 않는 오브젝트는 비활성화하여 다시 풀에 돌려놓는다.
장점:
성능 최적화: 오브젝트를 재사용함으로써 매번 메모리를 할당하고 해제하는 작업을 줄인다.
메모리 관리 개선: 게임 내에서 빈번하게 생성 및 삭제되는 오브젝트들(예: 총알, 적 캐릭터)을 효율적으로 관리할 수 있다.
유의점:
초기 설정 시, 풀의 크기를 적절히 조정해야 한다. 너무 작으면 풀 안의 오브젝트가 부족해 매번 새로운 오브젝트를 생성해야 하고, 너무 크면 불필요한 메모리를 차지할 수 있다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ObjectPool : MonoBehaviour
{
public GameObject[] enemy;
List<GameObject>[] pools;
private void Awake()
{
pools = new List<GameObject>[enemy.Length];
for(int index = 0; index < pools.Length; index++)
{
pools[index] = new List<GameObject> ();
}
}
public GameObject Get(int index)
{
GameObject select = null;
foreach(GameObject item in pools[index])
{
if(!item.activeSelf)
{
select = item;
select.SetActive(true);
break;
}
}
if (!select)
{
select = Instantiate(enemy[index], transform);
pools[index].Add(select);
}
return select;
}
}
스크립트를 작성해주고 적(Enemy)프리팹을 만들어준다음 오브젝트풀 스크립트가 붙어있는 객체에 게임오브젝트 배열에 적(Enemy)프리팹을 넣어준다.

이렇게 넣어주고나서 이제 이 적(Enemy)를 소환을 시켜야하니 다시 스크립트를 작성해야한다.
몹 소환 방식 선택에 대한 고민과 결론
이 적(Enemy)를 소환로직을 짜려고 생각을 하는중에 2가지 방법이 생각이났다.
플레이어 주변에 미리 오브젝트(스폰 포인트)를 만들어서 몹을 소환하는 방법.
스크립트를 통해 플레이어 주변 랜덤 위치를 계산하여 몹을 소환하는 방법.
스폰 포인트 방식은 정확한 위치 제어가 가능하고, 특정 패턴이나 환경에 맞춰 몹을 소환하는 데 유리할 것 같았다. 그러나 오브젝트 관리가 필요하고, 랜덤성이 떨어질 수 있어 정적인 소환 방식이 될 가능성이 높았다.
스크립트 방식은 코드를 통해 동적으로 플레이어 주변에서 몹을 랜덤으로 소환할 수 있어 유연성이 높고 자원 효율적이다. 또한 특정 거리를 유지하면서 플레이어 근처에 적절한 위치에서 몹이 나타날 수 있어 간단한 구조로도 다양한 연출이 가능했다.
결론:
나는 스크립트를 통해 랜덤 위치에서 몹을 소환하는 방식이 더 적합하다고 판단하였고, 이 방식이 간단하고 다양한 위치에서 몹을 유연하게 스폰할 수 있기 때문에 동적인 게임플레이에 더 적합하다고 생각하였다. 또한, 별도의 오브젝트를 관리할 필요 없이 코드 내에서 위치와 거리를 쉽게 조절할 수 있어 더 효율적이라고 생각하였다.
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using UnityEngine;
public class Spawn : MonoBehaviour
{
public Transform player;
float spawnTimer;
[Header("SpawnDistance")]
public float spwanRadius = 10f;
public float minSpawnDistance = 5f;
private void Update()
{
spawnTimer += Time.deltaTime;
if(spawnTimer > 0.2f)
{
spawnTimer = 0;
SpawnEnemy();
}
}
void SpawnEnemy()
{
// 랜덤한 각도를 계산
Vector2 randomDirection = Random.insideUnitCircle.normalized;
// 스폰 위치 계산 (랜덤 방향으로 반경 내에서)
float spawnDistance = Random.Range(minSpawnDistance, spwanRadius);
Vector3 spawnPosition = player.position + new Vector3(randomDirection.x, randomDirection.y, randomDirection.y) * spawnDistance;
// 몹을 해당 위치에 소환
GameObject enemy = GameManager.Instance.ObjectPool.Get(0);
enemy.transform.position = spawnPosition;
}
}
