일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
- Flyweight Pattern
- binary search
- PrefixSum
- Gold
- dirtyflag pattern
- level1
- programmers
- algorithm
- 프로그래머스
- 8-Puzzle
- trie
- solid 원칙
- Euclidean
- LEVEL2
- level3
- SWEA
- Modern C++
- Zenject
- effective C++
- BFS
- 프로세스 상태
- stack
- 3D RPG
- Project
- knapsack Problem
- Silver
- BOJ
- Bronze
- Unity
- two pointer
- Today
- Total
Patrick's Devlog
[Unity] Object Pool Pattern 본문
Object Pool
수많은 오브젝트를 다루는 개념이며, 오브젝트의 풀을 생성하고 필요할때 꺼내서 사용하면 된다. GoF의 디자인 패턴에서는 Object Pool을 따로 설명하지 않았다. 현대에서는 많이 쓰이는 개념이 되다보니 디자인 패턴으로 취급하는 경향이 있다. 전통적인 디자인 패턴하고는 컨셉이 다를 수 있으므로, 디자인 패턴보다는 최적화 기법으로 생각하면 된다.
특징
"Pool"에서 준비된 상태로 대기 중인 초기화된 오브젝트 세트를 사용한다. 그리고 오브젝트가 필요할 때 새로 인스턴스화하는 대신 풀에서 오브젝트를 활성화하여 사용한다. 해당 객체의 사용이 끝나면 Destroy 대신 비활성화하고 풀에 반환한다. 객체 생성 및 삭제로 인한 가비지 급증으로 발생할 수 있는 끊김 현상(Hiccup, GC spike)을 예방할 수 있다. 주로 로딩 화면에서 미리 생성한다.
오브젝트가 부족할 땐 어느정도 생성이 되나, 오브젝트가 많아지면 더이상 생성되지 않고 있는 오브젝트를 활성화, 비활성화한다. 오브젝트 풀을 생성할 때, Set Parent를 통해 부모 자식관계를 가지게 되면 위험할 수 있으므로 권장하지 않는다.
예시
public class ObjectPool : MonoBehaviour {
[SerializeField] private uint initPoolSize;
[SerializeField] private PooledObject objectToPool;
private Stack<PooledObject> stack; // Pool Object를 뺐다 넣는 자료구조
private void Start() {
SetupPool();
}
private void SetupPool() { // 로딩 화면에서 미리 생성
stack = new Stack<PooledObject>();
PooledObject instance = null;
for (int i = 0; i < initPoolSize; i++) {
instance = Instantiate(objectToPool);
instance.Pool = this;
instance.gameObject.SetActive(false);
stack.Push(instance);
}
}
// 오브젝트를 가져옴
public PooledObject GetPooledObject() {
if (stack.Count == 0) { // 풀에 없을 때
PooledObject newInstance = Instantiate(objectToPool); // 새로 생성
newInstance.Pool = this;
return newInstance;
}
PooledObject nextInstance = stack.Pop();
nextInstance.gameObject.SetActive(true); // 생성이 아닌 활성화
return nextInstance;
}
// 오브젝트를 반환
public void ReturnToPool(PooledObject pooledObject) {
stack.Push(pooledObject);
pooledObject.gameObject.SetActive(false); // Destroy가 아닌 비활성화
}
}
// ---
public class PooledObject : MonoBehaviour { // 오브젝트 풀 관리 대상
private ObjectPool pool;
public ObjectPool Pool { get => pool; set => pool = value; }
public void Release() {
pool.ReturnToPool(this); // 풀에 들어갈 수 있도록 구현
}
}
오브젝트 풀에 대한 예시 코드이다. 오브젝트 풀을 생성하고, Stack에 저장하여 해당 오브젝트를 Stack에서 가져오거나 저장하는 방식으로 진행된다.
ObjectPool API
오브젝트 풀은 많이 사용되다보니 Unity 2021부터 API를 제공한다. 해당 API의 링크를 참조하면 된다.
작동 원리는 똑같지만 직접 구현하는 것보다는 API를 이용해서 구현하는 것이 수월하다. ObjectPool API를 사용했을 때의 코드 예시이다.
public class RevisedGun : MonoBehaviour {
...
[SerializeField] private RevisedProjectile projectilePrefab;
private IObjectPool<RevisedProjectile> objectPool;
private void Awake() {
objectPool = new ObjectPool<RevisedProjectile>(CreateProjectile, OnGetFromPool
, OnReleaseToPool, OnDestroyPooledObject, collectionCheck, defaultCapacity, maxSize);
// new ObjectPool<T>(list, create function, action on get, action on release, action on destroy)
}
private RevisedProjectile CreateProjectile() { // 오브젝트 생성
RevisedProjectile projectileInstance = Instantiate(projectilePrefab);
projectileInstance.ObjectPool = objectPool;
return projectileInstance;
}
private void OnGetFromPool(RevisedProjectile pooledObject) { // 풀에서 가져올 때
pooledObject.gameObject.SetActive(true);
}
private void FixedUpdate() {
RevisedProjectile bulletObject = objectPool.Get();
// 오브젝트를 가져옴
...
}
}
public class RevisedProjectile : MonoBehaviuor {
private IObjectPool<RevisedProjectile> objectPool;
public IObjectPool<RevisedProjectile> ObjectPool { set => objectPool = value; }
public void Deactivate() {
...
objectPool.Release(this);
// 오브젝트를 반환
}
}
참고 문서
'Unity > Design Pattern' 카테고리의 다른 글
[Unity] MVC, MVP, MVVM Pattern (1) | 2024.10.08 |
---|---|
[Unity] Singleton Pattern (1) | 2024.10.04 |
[Unity] Factory Pattern (0) | 2024.10.01 |
[Unity] Command Pattern (0) | 2024.09.30 |
[Unity] Observer Pattern (0) | 2024.09.27 |