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
}
사용중인 싱글톤
더보기
using UnityEngine;
namespace Mentum
{
/// <summary>
/// SceneBoundSingleton : 씬에 한정된 싱글톤 객체로, 씬 전환 시 삭제됨.
/// PersistentSingleton : 씬 전환 후에도 유지되는 영구적인 싱글톤.
/// AutoSceneSingleton : 씬 한정 싱글톤으로, 존재하지 않을 경우 자동으로 생성됨.
/// AutoPersistentSingleton : 씬 전환 후에도 유지되는 싱글톤으로, 없으면 자동 생성됨.
/// </summary>
public abstract class Singleton<T> : MonoBehaviour where T : Component
{
protected static T _instance;
public static T Instance
{
get
{
if (_isOnQuit) return null;
if (_instance == null)
{
_instance = FindAnyObjectByType(typeof(T)) as T;
if (_instance == null)
Debug.LogError($"싱글턴 {typeof(T)}이 씬에 존재하지않음.");
}
return _instance;
}
}
public static bool IsExist => !_isOnQuit && _instance != null;
protected static bool _isOnQuit = false;
protected abstract bool IsDonDestroyOnLoad { get; }
protected void Awake()
{
if (_instance != null && _instance != this)
DestroyImmediate(gameObject);
else
{
_instance = this as T;
if (IsDonDestroyOnLoad)
DontDestroyOnLoad(gameObject);
InitOnAwake();
}
}
protected virtual void InitOnAwake()
{
}
protected virtual void OnApplicationQuit()
{
_isOnQuit = true;
}
protected virtual void OnDestroy()
{
if (_instance == this)
_instance = null;
}
//Domain Reload를 언체크한 상황에서도 동작하는 초기화 애트리뷰트
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
protected static void ReloadDomain()
{
_instance = null;
_isOnQuit = false;
}
}
public class SceneBoundSingleton<T> : Singleton<T> where T : Component
{
protected sealed override bool IsDonDestroyOnLoad => false;
}
public class PersistentSingleton<T> : Singleton<T> where T : Component
{
protected sealed override bool IsDonDestroyOnLoad => true;
}
public class AutoSceneSingleton<T> : Singleton<T> where T : Component
{
protected sealed override bool IsDonDestroyOnLoad => false;
public new static T Instance
{
get
{
if (_isOnQuit) return null;
if (_instance == null)
{
_instance = FindAnyObjectByType(typeof(T)) as T;
if (_instance == null)
_instance = new GameObject($"{typeof(T).Name}").AddComponent<T>(); // 새로 생성함
}
return _instance;
}
}
}
public class AutoPersistentSingleton<T> : Singleton<T> where T : Component
{
protected sealed override bool IsDonDestroyOnLoad => true;
public new static T Instance
{
get
{
if (_isOnQuit) return null;
if (_instance == null)
{
_instance = FindAnyObjectByType(typeof(T)) as T;
if (_instance == null)
_instance = new GameObject($"{typeof(T).Name}").AddComponent<T>(); // 새로 생성함
}
return _instance;
}
}
}
}
'🌍 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 |