제네릭 활용
스탠다드반 강의를 도강하면서 유용한 정보들을 쏙쏙 뽑아왔다. (대충 꺼억콩)
제네릭 싱글톤
다양한 Manager 클래스를 만들 때 싱글톤으로 만드는 코드가 반복되는데, 제네릭을 사용해서 싱글톤 객체를 효율적으로 만들 수 있다.
- public class Singleton<T> : MonoBehaviour where T : MonoBehaviour
- Singleton : MonoBehaviour Singleton 클래스가 MonoBehaviour를 상속받는다. (그래야 FindObjectOfType 가능)
- where T : MonoBehaviour T에 들어올 클래스가 MonoBehaviour를 상속받고 있어야 한다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 제네릭 싱글톤
/// </summary>
/// <typeparam name="T">싱글톤 인스턴스로 만들 클래스 타입</typeparam>
public class Singleton<T> : MonoBehaviour where T : MonoBehaviour
{
private static T _instance;
public static T Instance
{
get
{
if (_instance == null)
{
_instance = FindObjectOfType<T>();
// 찾은 후에도 없으면 생성
if (_instance == null)
{
GameObject singletonObj = new GameObject(typeof(T).Name);
_instance = singletonObj.AddComponent<T>();
DontDestroyOnLoad(singletonObj);
}
}
return _instance;
}
}
protected virtual void Awake()
{
if (_instance == null)
{
_instance = this as T;
DontDestroyOnLoad(gameObject);
}
else
{
Destroy(gameObject);
}
}
}
제네릭 싱글톤을 사용하는 예제
위의 Singleton<T> 클래스를 상속받으면 바로 싱글톤 기능을 사용할 수 있다.
using UnityEngine;
public class GameManager : Singleton<GameManager>
{
public int playerScore = 0;
public void AddScore(int amount)
{
playerScore += amount;
Debug.Log("현재 점수: " + playerScore);
}
}
제네릭 오브젝트 풀
오브젝트 풀링에 제네릭을 사용하면 어떤 타입의 오브젝트든 재사용할 수 있는 오브젝트 풀을 만들 수 있다.
제네릭 오브젝트 풀 클래스
public class ObjectPool<T> where T : MonoBehaviour
{
private Queue<T> pool = new Queue<T>();
private T prefab;
private Transform parent;
// 생성자에서 initialSize만큼 만들어서 pool에 넣어놓기
public ObjectPool(T prefab, int initialSize, Transform parent = null)
{
this.prefab = prefab;
this.parent = parent;
for (int i = 0; i < initialSize; i++)
{
T obj = Object.Instantiate(prefab, parent);
obj.gameObject.SetActive(false);
pool.Enqueue(obj);
}
}
// pool에 남아있다면 빼서 주고, 없다면 새로 만들어서 줌
public T Get()
{
if (pool.Count > 0)
{
T obj = pool.Dequeue();
obj.gameObject.SetActive(true);
return obj;
}
else
{
T newObj = Object.Instantiate(prefab, parent);
return newObj;
}
}
// 리턴된 오브젝트는 비활성화 시킨 뒤 pool에 넣어놓는다.
public void Return(T obj)
{
obj.gameObject.SetActive(false);
pool.Enqueue(obj);
}
}
이 제네릭 오브젝트 풀을 이용해서 Bullet pool을 만든다고 치면 아래와 같은 코드가 되겠다.
public class BulletPool : MonoBehaviour
{
public static BulletPool Instance;
private ObjectPool<Bullet> pool; // 제네릭 오브젝트 풀 사용
public Bullet bulletPrefab;
public int poolSize = 10;
private void Awake()
{
Instance = this;
pool = new ObjectPool<Bullet>(bulletPrefab, poolSize, transform);
}
public Bullet Get()
{
return pool.Get();
}
public void Return(Bullet bullet)
{
pool.Return(bullet);
}
}
그리고 이 BulletPool에서 나온 Bullet은 충돌 시 싱글톤으로 만들어진 BulletPool에 리턴하면 되겠다.
public class Bullet : MonoBehaviour
{
public float speed = 10f;
void Update()
{
transform.Translate(Vector3.forward * speed * Time.deltaTime);
}
void OnTriggerEnter(Collider other)
{
// 충돌 시 Bullet Pool에 반환
BulletPool.Instance.Return(this);
}
}
지난 '레전드 닌자' 프로젝트에서 원거리 몬스터의 Projectile을 구현할 때 오브젝트 풀링을 사용해보고 싶어서 잠시 공부했었는데, 이해하는 데에 시간이 걸려서 적용하지 못했다. 아쉬움이 남았었는데 제네릭을 활용하면서 제대로 배우게 된 것 같아서 아주 만족스럽다. 이번 개인 프로젝트에서라도 꼭 적용해보고 싶다.
'공부 기록 > 유니티 Unity' 카테고리의 다른 글
[Unity/TIL] 시네머신 활용 정리 (추적, 전환, 흔들림) (0) | 2025.03.20 |
---|---|
[Unity] 코루틴 활용 기록 (0) | 2025.03.12 |
[Unity/TIL] AI Navigation 사용해서 NPC 구현 (0) | 2025.03.06 |
[Unity/TIL] 유니티 숙련 과정에서 알게 된 것들 (0) | 2025.03.05 |
[Unity/TIL] 3D 환경 조성하기 (스카이박스 & 낮과 밤 구현하기) (0) | 2025.03.04 |