2024. 5. 23. 20:45ㆍUnity/Unity 학습정리
게임을 진행하면서 많은 오브젝트들을 생성하고 파괴하는 과정을 거친다. 특히 반복적으로 이 행동을 해야하는 경우가 있는데 발사체를 쏠때 발사체를 여러개 생성하고 또 범위 밖으로 나가면 생성되어있던것을 파괴해야하는 경우가 있다. 오브젝트를 만들때 Instantiate(), 파괴할때 Destroy()를 자주 사용하는데 이 메서드들은 비용을 굉장히 많이 먹는 작업이다. 메모리를 새로 할당하고 초기화하는 과정 및 파괴 후 가비지 컬렉션같은 과정들을 거친다.
위 과정을 더 효율적으로 만들어주는것이 Object Pool이다. 과거버전 유니티에서는 오브젝트 풀을 공식적으로 지원하지 않아, 개발자가 직접 코드로 구현하여 사용했다고 한다. 지금은 공식적으로 지원하고 있고 직접 만든 오브젝트 풀과 유니티의 오브젝트 풀 둘 다 알아보았다.
목차
- Object Pool 원리
- 직접구현
Object Pooling 원리
생성과 파괴가 빈번하게 발생하는 오브젝트에 대해서 매번 Instantiate, Destroy를 할 수 없다. 이는 게임 성능에 영향을 미친다. 그래서 미리 다수의 오브젝트들을 만들어놓고 필요할 때 가져다쓰고, 사용이 끝나면 반납하는 방식으로 구현된다.
- 생성(Instantiate)와 소멸(Destroy)이라는 큰 비용을 드는 작업을 최소화하여 성능향상을 할 수 있게 한다.
- 특히 빈번하게 생성되고 소멸되는 오브젝트에 대해서 유용하다.
- 개발자가 스스로 오브젝트의 양을 예측해서 사용해야한다. 실제로는 20~30개 정도 사용되는데 오브젝트를 미리 몇 백개나, 몇 천개를 만들어 넣어놓으면 메모리 사용이 많다. 이는 결국 성능 저하로 이어진다. 그래서 오브젝트 풀의 크기를 적절하게 조절해야 한다.
직접구현
[System.Serializable]
public class Pool
{
public string tag;
public GameObject prefab;
public int size;
}
필드
- tag : 프리팹의 태그
- prefab : Object Pool을 이용해 미리 생성해둘 오브젝트
- size : 오브젝트 풀의 크기
해당 pool 클래스를 생성하고 게임 오브젝트를 Pool클래스로 만든다.
public List<Pool> pools = new List<Pool>();
public Dictionary<string, Queue<GameObject>> PoolDictionary;
리스트
리스트에 들어가있는 pool들은 모두 오브젝트 풀링의 대상 객체들이 된다. 나중에 foreach를 이용해 모두 탐색하면서 PoolDcitionary에 등록한다.
딕셔너리
- key : pool.tag 오브젝트풀의 태그를 키값으로 둔다.
- Value : pool에 들어있는 GameObject 프리팹으로 생성한 게임오브젝트들의 Queue를 Value로 넣어준다.
이렇게 구현해놓으면 우린 Key값(tag)로 오브젝트 풀의 Queue를 사용할 수 있다.
private void Awake()
{
PoolDictionary = new Dictionary<string, Queue<GameObject>>();
foreach (var pool in pools)
{
Queue<GameObject> queue = new Queue<GameObject>();
for (int i = 0; i < pool.size; i++)
{
GameObject obj = Instantiate(pool.prefab,transform);
obj.SetActive(false);
queue.Enqueue(obj);
}
PoolDictionary.Add(pool.tag, queue);
}
}
- 리스트안에있는 pool후보들을 탐색한다.
- 해당 pool후보 size만큼 Instantiate(생성)하고 비활성화를 시켜 queue에 집어넣어준다.
- 해당 pool 태그와 queue를 딕셔너리에 등록해주면서 Object Pool을 완성시킨다.
public GameObject SpawnFromPool(string tag)
{
if (!PoolDictionary.ContainsKey(tag))
{
return null;
}
GameObject obj = PoolDictionary[tag].Dequeue();
PoolDictionary[tag].Enqueue(obj);
obj.SetActive(true);
return obj;
}
사용방법
private void CrateProjectile(RangedAttackSO rangedAttackSO, float angle)
{
GameObject obj = GameManager.Instance.ObjectPool.SpawnFromPool(rangedAttackSO.bulletNameTag);
obj.transform.position = projectileSpawnPosition.position;
ProjectileController attackController = obj.GetComponent<ProjectileController>();
attackController.InitializeAttack(RoatateVector2(aimDirection,angle),rangedAttackSO);
}
실제로 SpawnFromPool을 하여 오브젝트를 활성화 시키고 해당 오브젝트의 위치를 지정하고 발사까지 하는 코드이다.
'Unity > Unity 학습정리' 카테고리의 다른 글
Unity - 슬라이더바로 사운드 조절하기 (1) | 2024.06.05 |
---|---|
Unity - Scriptable Object (0) | 2024.05.27 |
Unity - 싱글톤 패턴 (0) | 2024.05.21 |
Unity - Vector2.Dot으로 시야각 구하기 (0) | 2024.05.17 |
Unity - 각도 구하기 (0) | 2024.05.16 |