ObjectPooling이란?
- 슈팅게임의 탄막이나 생존 게임의 자원 등 여러 개의 오브젝트가 생성되고 소멸되는 것이 반복되어야 하는 상황에서 적용하는 것이 유리
- 매번 오브젝트를 생성-소멸하는 것이 아닌 사용 중인 오브젝트는 활성화하고 사용하고 있지 않은 오브젝트를 비활성화해 매번 새로운 오브젝트를 만드는 비용을 줄임
public interface IPoolable
{
void Initialize(Action<GameObject> returnAction);
void OnSpawn();
void OnDespawn();
}
OnSpawn()
- 오브젝트를 사용해야 할 때 기존에 생성된 Queue에 있는 것을 활성화하거나 새로 생성한다.
OnDespawn()
- 오브젝트가 사용된 후 비활성화 상태로 바꾸고 Queue에 포함시킨다.
Initialize(Action<
GameObject> returnAction)
- 초기화시 오브젝트를 비활성화하고 Queue로 되돌려 보내는 Action을 연결한다.
public GameObject[] prefabs;
private Dictionary<int, Queue<GameObject>> pools = new Dictionary<int, Queue<GameObject>>();
public static ObjectPoolManager Instance { get; private set; }
private void Awake()
{
Instance = this;
for(int i = 0; i < prefabs.Length; i++)
{
pools[i] = new Queue<GameObject>();
}
}
public GameObject GetObject(int prefabIndex, Vector3 position, Quaternion rotation)
{
if(!pools.ContainsKey(prefabIndex))
{
Debug.Log($"프리팹 인덱스 {prefabIndex}에 대한 풀이 존재하지 않음");
return null;
}
GameObject obj;
if (pools[prefabIndex].Count > 0)
{
obj = pools[prefabIndex].Dequeue();
}
else
{
obj = Instantiate(prefabs[prefabIndex]);
obj.GetComponent<IPoolable>()?.Initialize(o => ReturnObject(prefabIndex, o));
}
obj.transform.SetPositionAndRotation(position, rotation);
obj.SetActive(true);
obj.GetComponent<IPoolable>()?.OnSpawn();
return obj;
}
GetObject()를 통해 외부에서 Queue에 있는 오브젝트를 가져올 수 있다.
int prefabIndex
- pools에서 오브젝트를 불러오기 위한 Queue를 찾을 수 있는 key 값
Vector3 position, Quaternion rotation
- 오브젝트를 불러와 초기화 할 때 요구되는 위치 및 회전 정보
prefabIndex에서 Queue를 찾을 수 없으면 디버그 로그를 띄워 알리고, 있다면 해당 키 값에 해당하는 Queue가 크기가 0보다 큰지 확인 후 해당 Queue에서 오브젝트를 가져와 활성화하고 OnSpawn을 실행한다.
만약 Queue가 크기가 0보다 작을 때는 프리팹을 이용해 새로운 오브젝트를 생성하고 해당 오브젝트를 초기화하면서 비활성화시 실행할 함수를 연결한다. 이후 과정은 동일하다.
void ReturnObject(int prefabIndex, GameObject obj)
{
if(!pools.ContainsKey(prefabIndex))
{
Destroy(obj);
return;
}
obj.SetActive(false);
pools[prefabIndex].Enqueue(obj);
}
public class ProjectileController : MonoBehaviour, IPoolable
{
private Action<GameObject> returnToPool;
...
void DestroyProjectile(Vector3 position, bool creatFx)
{
...
//Destroy(this.gameObject);
OnDespawn();
}
public void Initialize(Action<GameObject> returnAction)
{
returnToPool = returnAction;
}
public void OnSpawn()
{
}
public void OnDespawn()
{
returnToPool?.Invoke(gameObject);
}
}
public void ShootBullet(RangeWeaponHandler rangeWeaponHandler, Vector2 startPos, Vector2 dir)
{
//GameObject origin = projectilePrefabs[rangeWeaponHandler.BulletIndex];
//GameObject obj = Instantiate(origin, startPos, Quaternion.identity);
GameObject obj = objectPoolManager.GetObject(rangeWeaponHandler.BulletIndex, startPos, Quaternion.identity);
...
}
