1. 개요
게임에서 적이나 총알 오브젝트를 관리를 한다고 할 때, 적군에게는 잡병1,2,3... 중간 클래스1,2,3... 등등.. 총알에는 라이플탄, 스나이퍼탄, 샷건탄 등등.. 한 가지 종류가 아닌 경우가 많습니다. 이것들을 위해 각각의 풀링매니저를 생성하기에는 비효율적이니, 열거형인 Enum을 통해 타입을 구분하고 이 타입을 통해 다중 오브젝트 풀링을 구현하겠습니다.
2. 스크립트 구현
3가지 종류가 있는 Enemy를 풀링으로 구현해보는 것이 목표입니다.
※ EnemyType을 열거형으로 선언.
public enum EnemyType
{
Square,
Sphere,
Capsule,
}
※ 풀링할 Enemy의 오브젝트의 정보
[System.Serializable]
public class EnemyPoolingInfo
{
public EnemyType type; // 적 타입
public GameObject prefab; // 생성할 적 프리팹
public Transform container; // 부모로 설정할 Transform
public int createCount; // 생성 개수
// 관리를 위한 queue
public Queue<GameObject> queue = new Queue<GameObject>();
}
아래의 EnemyManager에서 이 EnemyPoolingInfo를 List로 가지고 있기 때문에, 컴포넌트로 붙이게 되면 Inspector 창에서 이런 형식을 가지게 됩니다.

※ Enemy의 풀링을 담당하는 매니저
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyManager : MonoBehaviour
{
// 다중 오브젝트 풀링을 위한 List
public List<EnemyPoolingInfo> poolList = new List<EnemyPoolingInfo>();
// 초기 생성
private void Start()
{
for (int i = 0; i < poolList.Count; i++)
{
FillStack(poolList[i]);
}
}
// 저장소에 지정한 프리팹으로 채워넣는다.
public void FillStack(EnemyPoolingInfo info)
{
for (int i = 0; i < info.createCount; i++)
{
GameObject pulledObject = Instantiate(info.prefab, info.container);
pulledObject.SetActive(false);
info.queue.Enqueue(pulledObject);
}
}
// 타입을 받아와 Peek()과 Dequeue로 빼준다.
public GameObject Pop(EnemyType type)
{
for (int i = 0; i < poolList.Count; i++)
{
if (type.Equals(poolList[i].type))
{
// 개수가 0 이하면 다시 채워준다.
if (poolList[i].queue.Count <= 0)
{
FillStack(poolList[i]);
}
// 오브젝트를 켜주고 넘겨준다.
poolList[i].queue.Peek().SetActive(true);
return poolList[i].queue.Dequeue();
}
}
return null;
}
// 반환 받는 함수.
public void ReturnToStack(EnemyType type, GameObject enemy)
{
// 리스트를 검색하여
for (int i = 0; i < poolList.Count; i++)
{
// 넘어온 오브젝트의 타입과 같으면
if (type.Equals(poolList[i].type))
{
// 그 타입을 관리하는 queue에 추가하고, 오브젝트를 꺼준다.
poolList[i].queue.Enqueue(enemy);
enemy.SetActive(false);
}
}
}
}
※ Enemy
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Enemy : MonoBehaviour
{
//Scene에서 설정할 타입.
[SerializeField] EnemyType enemyType;
// 켜질 때(Pop()) 부터 반환 코루틴 시작.
private void OnEnable()
{
StartCoroutine(ReturnToStack());
}
// 2초 후 반환
IEnumerator ReturnToStack()
{
var returnTime = new WaitForSeconds(2.0f);
yield return returnTime;
EnemyManager.Instance.ReturnToStack(enemyType, gameObject);
}
}
3. Scene 적용
※ Enemy
ㆍ생성해둔 프리팹에 Enemy 스크립트를 컴포넌트로 추가하여 Type들을 설정.



※ EnemyManager

4. 플레이 확인
1을 누르면 정육면체, 2를 누르면 구, 3을 누르면 캡슐 Enemy 생성
private void Update()
{
if(Input.GetKeyDown(KeyCode.Alpha1))
{
Pop(EnemyType.Square);
}
else if(Input.GetKeyDown(KeyCode.Alpha2))
{
Pop(EnemyType.Sphere);
}
else if (Input.GetKeyDown(KeyCode.Alpha3))
{
Pop(EnemyType.Capsule);
}
}

Pop()으로 꺼내오는 것, 2초 후 저장소로 ReturnToStack()이 작동되는 것, Pop()해줄 오브젝트가 없다면 다시 채워주는 것, 모두 작동이 잘 되는 것을 확인할 수 있으니 마무리 하겠습니다.
'Design Pattern > 유니티에 적용해보기' 카테고리의 다른 글
| C#(Unity) - 오브젝트 풀링 라이브러리 (0) | 2022.08.23 |
|---|---|
| C#(Unity) - 오브젝트 풀링(Object Pool) (0) | 2022.08.23 |
| C#(Unity) - 싱글톤 (0) | 2022.08.22 |