Contents
접기
728x90
구현 목표
설계편에서 정의한 내용을 바탕으로,
Unity에서 오브젝트 풀링 시스템과 적 생성 시스템을 직접 구현
- 효율적인 리소스 관리: 오브젝트 풀링
- 적 몬스터 스폰: 다양한 적 패턴 관리
- IPoolable 인터페이스: 오브젝트 상태 관리
- PoolManager 싱글톤: 풀 통합 관리
✅ IPoolable 인터페이스
public interface IPoolable
{
void OnSpawned(); // 오브젝트가 풀에서 나올 때 호출
void OnDespawned(); // 오브젝트가 풀로 돌아갈 때 호출
}
오브젝트 풀에 들어가는 모든 오브젝트는
OnSpawned(), OnDespawned() 메서드를 구현해
초기화와 정리 작업을 할 수 있다.
✅ ObjectPool 클래스
Object Pool 전체 흐름
[초기화]
1. ObjectPooL<T> 생성 시 프리과 개수 받음
2. Instantiate()로 T 오브젝트들을 생성해서 Queue에 보관
3. 모두 SetActive(false) 상태로 비활성화
[꺼내기]
4. Get() 호출 시 -> Queue에서 꺼내고 SetActive(true)
5. OnSpawned() 호출 (초기화 콜백)
[반환하기]
6. Return() 호출 시 - SetActive(false)
7. OnDespawned () 호출
8. 다시 Queue에 넣음
Object Pool 구현
public class ObjectPool<T> where T : MonoBehaviour, IPoolable
{
private Queue<T> pool = new Queue<T>();
private T _prefab;
private Transform _parent;
public ObjectPool(T prefab, int size, Transform parent = null)
{
_prefab = prefab;
_parent = parent;
for (int i = 0; i < size; i++)
{
T obj = Object.Instantiate(_prefab, _parent);
obj.gameObject.SetActive(false);
pool.Enqueue(obj);
}
}
public T Get()
{
if (pool.Count == 0)
{
T objTemp = Object.Instantiate(_prefab, _parent);
objTemp.gameObject.SetActive(true);
return objTemp;
}
T obj = pool.Dequeue();
obj.gameObject.SetActive(true);
obj.OnSpawned();
return obj;
}
public void Return(T obj)
{
obj.OnDespawned();
obj.gameObject.SetActive(false);
pool.Enqueue(obj);
}
}
- 제네릭 타입 T를 사용해 모든 풀링 오브젝트에 대응할 수 있다.
- 풀에 오브젝트가 부족하면 동적 생성도 지원한다.
✅ PoolManager 클래스 (싱글톤)
PoolManager 전체 흐름
[초기화]
1. PooLManager는 싱글톤으로 존재하며 게임 시작 시 생성됨
2. CreatePooLcT>(key, prefab, count, parent) 호출로 풀 생성
3. 각 key마다 objectPooL<T>를 생성해서 Dictionary에 저장
[꺼내기]
4. Get<T>(key) 호출 시 -> 해당 key의 0bjectPooL<T>에서 Get()
5. 오브젝트를 꺼내고 SetActive(true)
6. OnSpawned() 호출 (초기화 콜백)
[반환하기]
7. Return<T>(key, obj) 호출 시 -> SetActive(false)
8. OnDespawned() 호출
9. 다시 해당 ObjectPooL<T>에 obj를 Enqueue
PoolManager 구현
public class PoolManager : Singleton<PoolManager>
{
private Dictionary<string, object> pools = new();
protected override void Awake()
{
base.Awake();
// 적 오브젝트 풀 생성 예시
CreatePool<Boss>("Boss", _bossPrefab, 10, _bossParent);
CreatePool<MoveEnemy>("MoveEnemy", _movePrefab, 20, _enemyParent);
}
public void CreatePool<T>(string key, T prefab, int count, Transform parent) where T : MonoBehaviour, IPoolable
{
var pool = new ObjectPool<T>(prefab, count, parent);
pools.Add(key, pool);
}
public T Get<T>(string key) where T : MonoBehaviour, IPoolable
{
return ((ObjectPool<T>)pools[key]).Get();
}
public void Return<T>(string key, T obj) where T : MonoBehaviour, IPoolable
{
((ObjectPool<T>)pools[key]).Return(obj);
}
}
- 풀 생성: CreatePool()
- 오브젝트 꺼내오기: Get()
- 오브젝트 반환: Return()
모든 풀은 Dictionary로 관리되어,
다양한 적/탄환 종류를 쉽게 추가하고 관리할 수 있다.
적 스폰 로직
// 몬스터 생성
MoveEnemy enemy = PoolManager.Instance.Get<MoveEnemy>("MoveEnemy");
enemy.transform.position = spawnPoint.position;
// 몬스터 제거
PoolManager.Instance.Return("MoveEnemy", enemy);
필요한 순간 풀에서 꺼내서 위치를 잡고, 다 쓰면 풀에 다시 반납하는 방식
코드 흐름
게임 시작
↓
PoolManager가 오브젝트 풀 생성
↓
필요 시 ObjectPool에서 Get() 호출
↓
사용 후 Return() 호출로 재사용
↓
Room 입장 시 적 스폰, 체력 관리, FSM 패턴 적용
📖 결과
항목 | 결과 |
오브젝트 생성/제거 비용 | 감소 |
메모리 사용 | 최적화 |
게임 퍼포먼스 | 개선 (프레임 드랍 방지) |
스폰 시스템 | 방마다 몬스터 랜덤 등장 |
💡 직접 해보며 느낀 점
- 풀 크기(초기 생성 수)를 상황에 맞게 조정하는 것도 중요했다.
- IPoolable 패턴 덕분에 다양한 오브젝트를 깔끔하게 관리할 수 있었다.
- 오브젝트 풀에 오브젝트가 부족한 경우를 처음에 고려하지 않았는데 이후 그러한 경우를 알게되어 동적 생성을 추가하였다. 구현시에는 다양한 예외상황을 생각하고 구현해야 하는 것 같다.
- 특히, 로그라이크 같은 적/탄환 스폰이 많은 게임에서는 오브젝트 풀링은 선택이 아니라 필수라고 느꼈다.
728x90
'GameDevelop > Unity팀프로젝트' 카테고리의 다른 글
Unity FSM – 적을 3초 보이고 1초 숨기기 (0) | 2025.05.29 |
---|---|
[TeamProject2_2025.05.16] Unity 2D 팀 프로젝트 Oblivia 회고(1등!) (2) | 2025.05.16 |
[TeamProject2_2025.05.13] 로그라이크 게임 설계 정리 (설계편) (0) | 2025.05.13 |
[TeamProject2_2025.05.12] 제네릭 싱글톤(Singleton<T>) 유틸리티 (0) | 2025.05.12 |
[TeamProject2_2025.05.11] 프로젝트 기획, 우리팀 규칙 (0) | 2025.05.11 |