안녕하세요.
유니티 싱글톤에 대해서 모르시는 분은 없을거라고 생각합니다.
다만 매번 클래스에서 싱글톤을 구현하실 때 코드가 많이 더러워지는데요.
이런분들을 위해 싱글톤을 구현한 클래스를 상속하면 바로 쓸 수 있게 템플릿을 준비했습니다.
아래 템플릿 코드를 그냥 복사 붙여넣기하시거나 파일 다운하시면 됩니다.
바로 코드를 봅시다.
MMSingleton.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// Singleton pattern.
/// </summary>
public class MMSingleton<T> : MonoBehaviour where T : Component
{
protected static T _instance;
public static bool HasInstance => _instance != null;
public static T TryGetInstance() => HasInstance ? _instance : null;
public static T Current => _instance;
/// <summary>
/// Singleton design pattern
/// </summary>
/// <value>The instance.</value>
public static T Instance
{
get
{
if (_instance == null)
{
_instance = FindObjectOfType<T>();
Create(true);
}
return _instance;
}
}
public static void Create()
{
if (_instance == null)
{
GameObject obj = new GameObject(typeof(T).Name);
obj.name = typeof(T).Name + "_AutoCreated";
_instance = obj.AddComponent<T>();
}
}
public static void Create(bool dontDestroy)
{
if (_instance == null)
{
GameObject obj = new GameObject(typeof(T).Name);
obj.name = typeof(T).Name + "_AutoCreated";
_instance = obj.AddComponent<T>();
if(dontDestroy) DontDestroyOnLoad(obj);
}
}
/// <summary>
/// On awake, we initialize our instance. Make sure to call base.Awake() in override if you need awake.
/// </summary>
protected virtual void Awake()
{
InitializeSingleton();
}
/// <summary>
/// Initializes the singleton.
/// </summary>
protected virtual void InitializeSingleton()
{
if (!Application.isPlaying)
{
return;
}
_instance = this as T;
}
}
코드를 간단히 보자면 Instance를 호출했을 때 없다면 새로 생성하고 씬 전환시 Don't Destroy하도록 되어있습니다.
그리고 Awake() 함수에서 초기화가 되는걸 볼 수 있습니다.
사용법
사용하실 땐 싱글톤으로 만들 클래스에서 MMSingleton<클래스이름> 이런식으로 상속하면됩니다.
public class Global : MMSingleton<Global>
{
}
네 이게 답니다.
상속에 대해서 잘 모르겠다면 아래글을 참고하시기바랍니다.
장점 ①
외부 클래스에서 Global.cs 싱글톤으로 접근한다면 어떻게 해야할까요?
평소 여러분이 생각한대로면 Global.instance.메서드() 이런식으로 instance 키워드 붙여야해서 복잡했을겁니다.
그런데 MMSingleton에선 그냥 Global.메서드() 이렇게 호출해도 됩니다.
Global의 인스턴스가 생성안됐다면 호출한 순간에 생성되니 문제 없습니다.
예시코드)
using System.Numerics;
public class CashManager
{
public BigInteger Cash;
public void AddCash(BigInteger amt)
{
Cash += amt;
Global.UserDataManager.SetCashData(Cash);
}
}
장점 ②
그리고 싱글톤으로 선언된 Global.cs의 내부에 그냥 다른 싱글톤으로 만들 클래스들을 몰아넣어서 굳이 개별적으로 싱글톤을 작성할 필요가 없습니다. 그냥 하나의 싱글톤으로 선언된 클래스에 모아놔도 다 접근이 되는겁니다.
예를 들어 Global.클래스이름.메서드() 이런식으로 접근이 가능합니다.
예시코드)
public class Global : MMSingleton<Global>
{
public static SceneBase CurrentScene { get; set; }
public static UIManager UIManager { get; private set; }
public static UserDataManager UserDataManager { get; set; }
}
주의점
사실 하나의 싱글톤 Global.cs에 다 몰아 넣는 이유는 순서 보장하는 이유가 가장큽니다.
만일 서로 다른 싱글톤 인스턴스를 호출했을 때 뒤늦게 인스턴스 생성하게 되면 Null 에러가 자주 뜹니다.
그렇기에 하나에 몰아넣어서 Global.cs는 게임 시작시 바로 호출되게 하는 방식으로 관리하면 좋습니다.
씬에서 생성해야하는 인스턴스는 따로 또 씬에 싱글톤 객체를 미리 만들어두면 됩니다.
또한 인스턴스 생성시 MMSingleton.cs를 보시면 알겠지만 유니티의 Awake() 함수를 사용합니다.
때문에 상속한 뒤 Awake()에서 처리하실게 있다면 override 키워드로 하위 클래스에서 Awake를 오버라이드해주시면 됩니다.
그리고 오버라이드된 Awake() 내부는 base.Awake();로 싱글톤 처리를 먼저해주셔야합니다.
여하튼 이렇게 오늘 한번 상속으로 사용하는 싱글톤 템플릿을 소개해드려봤습니다.
클래스:MMSingleton<클래스> 이것만 익숙해지면 굉장히 편한 것 같습니다.
즐거운 개발되시길 바랍니다.
'유니티 > 유니티 관련 지식' 카테고리의 다른 글
[2] OpenUPM으로 UnityWeldKR 세팅 (1) | 2024.11.09 |
---|---|
[1] MVVM 데이터 바인딩이란? (0) | 2024.11.07 |
유니티 멀티플레이의 기반인 Netcode For GameObjects 튜토리얼 (9) | 2024.10.18 |
유니티 넷코드 성능 비교 보고서 (0) | 2024.10.18 |