using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MultipleObjectPooling : MonoBehaviour
{
public GameObject[] poolPrefabs;
public int poolingCount;
private Dictionary<object, List<GameObject>> pooledObjects = new Dictionary<object, List<GameObject>>();
public void CreateMultiplePoolObjects()
{
for (int i = 0; i < poolPrefabs.Length; i++)
{
for (int j = 0; j < poolingCount; j++)
{
if (!pooledObjects.ContainsKey(poolPrefabs[i].name))
{
List<GameObject> newList = new List<GameObject>();
pooledObjects.Add(poolPrefabs[i].name, newList);
}
GameObject newDoll = Instantiate(poolPrefabs[i], transform);
newDoll.SetActive(false);
pooledObjects[poolPrefabs[i].name].Add(newDoll);
}
}
}
public GameObject GetPooledObject(string _name)
{
if (pooledObjects.ContainsKey(_name))
{
for (int i = 0; i < pooledObjects[_name].Count; i++)
{
if (!pooledObjects[_name][i].activeSelf)
{
return pooledObjects[_name][i];
}
}
int beforeCreateCount = pooledObjects[_name].Count;
CreateMultiplePoolObjects();
return pooledObjects[_name][beforeCreateCount];
}
else
{
return null;
}
}
}
단 싱글톤을 적용할 스크립트는 씬 내에서 하나밖에 존재하지 않다는 가정하에 사용해야 합니다.
예로 게임 내에서 돈을 관리하는 스크립트는 MoneyManager 스크립트 하나 뿐일 것이므로
MoneyManager에 싱글톤 디자인 패턴을 사용하여 스크립트에 접근하기 쉽고 간편하게 하는 것 입니다.
빠르게 코드 먼저 훑고 가겠습니다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SingleTon<T> : MonoBehaviour
{
private static T _instance;
public static T instance
{
get
{
return _instance;
}
}
protected virtual void Awake()
{
_instance = this.GetComponent<T>();
}
}
싱글톤 스크립트는 이렇게 짭니다.
T.instance 로 접근하게 됩니다.
에제 보겠습니다
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CometManager : SingleTon<CometManager>
{
public Transform waypoint;
[HideInInspector] public Transform[] waypoints;
public ObjectPooling comets;
private void Start()
{
waypoints = waypoint.GetComponentsInChildren<Transform>();
comets = GetComponent<ObjectPooling>();
}
private void Update()
{
if (Input.GetKeyDown(KeyCode.W))
{
StartCoroutine(SpawnComet(10, 10));
}
}
public IEnumerator SpawnComet(int cometCount, float _maxHealth)
{
yield return null;
for (int i = 0; i < cometCount; i++)
{
Comet newComet = comets.Pooling().transform.GetComponent<Comet>();
newComet.maxHealth = _maxHealth;
newComet.gameObject.SetActive(true);
yield return new WaitForSeconds(1);
}
}
}
오브젝트 풀링은 게임 오브젝트를 생성하고 삭제하는 스크립트 상에서 GC(Garbage Collector)를 생성하지 않기 위해
오브젝트 풀링 디자인 패턴을 주로 사용하게 됩니다.
우선 오브젝트 풀링을 검색하고 사용하려는 사람들은 프로그래밍 언어에 대한 기본적인 지식이 있다고 생각하여
작동 원리만 간단히 설명하겠습니다.
유니티 상에서의 오브젝트 풀링의 기본적인 작동원리는 게임 오브젝트를 생성할 때 GC(Garbage Colletor)를 생성하지 않기
위해 Destroy를 최소한으로 사용하여 오브젝트를 생성 및 파괴를 하는 원리입니다.
Instantiate와 Destroy 대신 gameObject.SetActive(boolean)를 사용하게 되는데 생성할 때는
gameObject.SetActive(true)를, 파괴할 때는 gameObject.SetActive(false)를 사용하게 된다.
애니팡과 같은 퍼즐게임을 예로 들었을 때
만일 파란색 박스 안의 박스들을 파괴하게 되면 핑크색 박스 안의 박스들이 아래로 내려오게 되는데
이때 파괴한 파란색 박스안의 박스들을 gameObject.SetActive(false)로 파괴를 대신하여
재사용 가능한 상태로 만들어주어 GC(Garbage Collector)를 생성하지 않게 합니다.
또한 핑크색 박스안의 박스들은 gameObject.SetActive(true)를 사용하여 Instantiate를 사용하지 않아
GC(Garbage Collector)가 생성되지 않습니다.
이런 식으로 계속해서 반복하여 GC(Garbage Collector)를 생성하지 않게 합니다.
유니티 상에서 사용 가능한 ObjectPooling 예제를 아래에 남겨놓겠습니다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ObjectPooling : MonoBehaviour
{
public List<GameObject> pooledObjects = new List<GameObject>();
public GameObject poolPrefabs;
public int poolingCount;
private void Awake()
{
CreatePoolObjects();
}
public void CreatePoolObjects()
{
for (int i = 0; i < poolingCount; i++)
{
GameObject newPoolingObject = Instantiate(poolPrefabs, transform.position, transform.rotation, transform);
newPoolingObject.SetActive(false);
pooledObjects.Add(newPoolingObject);
}
}
public GameObject GetPooledObject()
{
for (int i = 0; i < pooledObjects.Count; i++)
{
if (!pooledObjects[i].activeSelf)
{
return pooledObjects[i];
}
}
int beforeCreateCount = pooledObjects.Count;
CreatePoolObjects();
return pooledObjects[beforeCreateCount];
}
public List<GameObject> GetAllDeactivePooledObjects()
{
List<GameObject> deactivePooledObjects = new List<GameObject>();
for (int i = 0; i < pooledObjects.Count; i++)
{
if (!pooledObjects[i].activeSelf)
{
deactivePooledObjects.Add(pooledObjects[i]);
}
}
return deactivePooledObjects;
}
public List<GameObject> GetAllActivePooledObjects()
{
List<GameObject> activePooledObjects = new List<GameObject>();
for (int i = 0; i < pooledObjects.Count; i++)
{
if (pooledObjects[i].activeSelf)
{
activePooledObjects.Add(pooledObjects[i]);
}
}
return activePooledObjects;
}
}
게임이 처음 시작한 후 설정해놓은 poolingCount만큼 poolPrefabs를 Instantiate로 먼저 생성해주고
이후 GetPooledObject를 통해 현재 gameObject.activeSelf가 false인 GameObject를 반환해주는 함수를 통해