1) 기본형 싱글톤
- DonDestroyOnLoad 를 삭제하면 해당 씬에서만 쓰이는 싱글톤으로 사용.
public class SingletonExample : MonoBehaviour
{
#region 싱글톤
private static SingletonExample _instance = null;
public static SingletonExample Instance
{
get
{
if (_instance == null)
{
_instance = (SingletonExample)FindObjectOfType(typeof(SingletonExample));
if (_instance == null)
{
Debug.Log("There's no active ManagerClass object");
}
}
return _instance;
}
}
void Awake()
{
if (_instance != null && _instance != this)
{
DestroyImmediate(gameObject);
}
else
{
_instance = this;
DontDestroyOnLoad(this.gameObject);
AwakeAfter();
}
}
#endregion
void AwakeAfter()
{
}
}
2) 다른 씬으로 전환할 때 마다 특정 함수 호출하는 싱글톤
- 문제점 : DonDestroyOnLoad상태의 오브젝트는 Awake랑 Start가 최초 씬에서만 호출된다. 하지만 씬이 전환될 때마다 처리를 해주어야 하는 경우가 있다.
- 해결 : DonDestroyOnLoad + 다른 씬으로 갈때 OnLevelLoaded 델리게이트를 체인 시켜준다.
- 주의할 점은 함수의 호출 순서가 Awake -> OnEnable -> OnLevelLoaded -> Start 순이라서 Awake가 아니라 Start에서 호출할 경우 첫 번째 씬에서는 체인 메소드가 실행되지 않는다.
- https://docs.unity3d.com/kr/530/Manual/ExecutionOrder.html 함수 호출 순서 참고.
public class LevelLoadedSingleton : MonoBehaviour
{
#region 싱글톤
private static LevelLoadedSingleton _instance = null;
public static LevelLoadedSingleton Instance
{
get
{
if (_instance == null)
{
_instance = (LevelLoadedSingleton)FindObjectOfType(typeof(LevelLoadedSingleton));
if (_instance == null)
{
Debug.Log("There's no active ManagerClass object");
}
}
return _instance;
}
}
void Awake()
{
if (_instance != null && _instance != this)
{
DestroyImmediate(gameObject);
}
else
{
_instance = this;
DontDestroyOnLoad(gameObject);
// 델리게이트 체인을 걸어준다. Awake -> OnEnable -> OnLevelLoaded -> Start 순이라서 첫 씬도
SceneManager.sceneLoaded += OnLevelLoaded;
}
}
private void OnLevelLoaded(Scene scene, LoadSceneMode mode)
{
// 레벨 변경시에 호출됨.
}
#endregion
}
3) 심화. 제네릭 싱글톤
- 1)의 싱글톤 패턴은 새 클래스를 만들 때 마다 클래스 이름을 5번이나 써줘야 한다는 문제점이 있다.
- 때문에 제네릭 <T> 로 상속하여 간단하게 만들어 볼 수 있다.
Base가 되는 Singleton.cs 는 아래와 같이 만들어두고,
public class Singleton<T> : MonoBehaviour where T : MonoBehaviour
{
protected static T _instance = null;
public static T Instance
{
get
{
if (_instance == null)
{
_instance = FindObjectOfType(typeof(T)) as T;
if (_instance == null)
{
Debug.Log("싱글턴 " + typeof(T) + "이 씬에 존재하지않음");
}
}
return _instance;
}
set => _instance = value;
}
}
상속시킬 스크립트에서는 : Singleton<해당클래스명> 으로 상속시켜주면 된다.
public class SingletonChildExample : Singleton<SingletonChildExample>
{
#region 싱글톤
void Awake()
{
if (Instance != null && Instance != this)
{
DestroyImmediate(gameObject);
}
else
{
Instance = this;
DontDestroyOnLoad(gameObject);
AwakeAfter();
}
}
#endregion
}
즉 구조가
Singleton<T> ---상속--> PlayerDataManager 이렇게 되는데,
상속을 받지않았던 싱글톤들은 쉽게 적용이 가능하지만
아래와 같이 상속을 먼저 받은 후 개별적으로 싱글톤을 적용했던 스크립트들은 적용하기 힘들다.
FlowManager ---상속---> MainFlowManager / BattleFlowManager
Singleton<T>를 상속받는 순간 <T>의 자료형이 해당 스크립트(아래에서는 FlowManager)가 돼버린다.
Singleton<T> ---상속--> FlowManager ---상속---> MainFlowManager
이 경우 FlowManager 를 interface로 바꾸고,
MainFlowManager는 Singleton<T>를 상속받으면서 Interface IFlow 를 상속받으면 된다.
인터페이스는 변수를 상수 밖에 못 가지니 공통 변수가 필요한 거라면, 그냥 싱글톤을 개별적으로 선언할 것.
'🌍 Unity > 유니티 프로그래밍' 카테고리의 다른 글
CSV 파일 쓰기 (0) | 2019.11.19 |
---|---|
유니티 csv 파일 읽기 ( Unity csv file read ) 수정 19.11.15 (2) | 2019.11.15 |
유니티 안드로이드 스크린샷 / 스크린캡쳐 (Unity Android screenCapture) (1) | 2019.11.14 |
유니티 앱 설정 열기 (Unity open App setting) (0) | 2019.11.14 |
사운드/오디오 매니저 Unity Sound Manager (0) | 2019.07.29 |