public class Singleton<T> : MonoBehaviour
{
private T _instance;
public static T instance
{
get
{
if (_instance == null)
{
_instance = FindObjectOfType<T>();
if (_instance != null)
{
_instance = new GameObject(typeof(T).Name).AddComponent<T>();
}
}
return _instance;
}
set
{
_instance = value;
}
}
protected virtual void Awake()
{
if (_instance != null)
Destroy(gameObject);
else
DontDestroyOnLoad(this);
}
}
제네릭 싱글톤
위 싱글톤 클래스를 상속하게 되면 코드 중복없이 싱글톤 클래스를 작성할수 있다
이때 T의 제한자는 where Monobehaviour로 제한해주어 이를 상속받는 클래스로 제한한다.
싱글톤에선 본인 클래스의 변수타입으로 선언해준뒤 이를통해 싱글톤으로 만들기 때문에 코드를 따로 제작해 주어야하지만 제네릭을 통하여 간단히 싱글톤을 만들수있게된다.
public class GameManager : Singleton<GameManager>
{
public int score = 0;
}
위와같이 제네릭 T를 GameManager로 치환하여 사용하면된다.
유니티에서 최적화를 위해 최대한 사용을 줄이면 좋은것들
1. Instantiate, Destroy
오브젝트 풀을 활용하여 setActive 사용
2. GameObject.Find/ FindObjectOfType
start에서 캐싱
3.GetComponent
start에서 캐싱
4. Instantiate 후 즉시 GetComponent 호출
프리팹에서 미리 컴포넌트를 할당한다.
5. 문자열(string) 관련 연산
stringbuilder 활용
6. LINQ (Where, Select 등)
for 문 사용
7. Coroutines (코루틴)
IEnumerator 코루틴은 내부적으로 메모리 할당을 발생시킴.
yield return new WaitForSeconds 반복 사용시 성능저하 발생
미리 캐싱하여 사용
여기서 getcomponent의 예시를 보자면
void Update()
{
GetComponent<Rigidbody>().velocity = Vector3.forward * 5f;
}
업데이트에서 getcomponent를 사용하면 사망한다. 대신
using UnityEngine;
public class CachedComponent<T> : MonoBehaviour where T : Component
{
private T _component;
public T Cached
{
get
{
if (_component == null) // 처음 한 번만 `GetComponent<T>()` 실행
_component = GetComponent<T>();
return _component;
}
}
}
를 상속해 준다면
public class Player : CachedComponent<Rigidbody>
{
void Update()
{
Cached.velocity = Vector3.forward * 5f; // `GetComponent<T>()` 호출이 1번만 발생!
}
}
최적화 할수도 있다.
기본적으로 이미 활용하던 Start에서 getcomponent를 활용해도되지만 만약 여러 컴포넌트를 캐싱해줘야한다면
using System.Collections.Generic;
using UnityEngine;
public class ComponentCache : MonoBehaviour
{
private Dictionary<System.Type, Component> _componentCache = new Dictionary<System.Type, Component>();
public T GetCachedComponent<T>() where T : Component
{
if (!_componentCache.ContainsKey(typeof(T)))
{
_componentCache[typeof(T)] = GetComponent<T>(); // 처음 한 번만 `GetComponent<T>()` 호출
}
return _componentCache[typeof(T)] as T;
}
}
메서드에 제네릭을 활용하여 컴포넌츠를 사용할때 처음 한번만 캐싱하며 코드의 유지 확장성을 좋게 할 수 있다.