2025/11/12 수정
using UnityEngine;
/// <summary>
/// 제네릭 싱글톤 베이스 클래스
/// 모든 MonoBehaviour 기반 싱글톤이 상속받을 수 있는 기본 구현체
/// </summary>
/// <typeparam name="T">싱글톤으로 구현할 컴포넌트 타입</typeparam>
public abstract class Singleton<T> : MonoBehaviour where T : Component
{
// 싱글톤 인스턴스 저장 필드
private static T instance;
// 스레드 안전성을 위한 lock 객체
private static readonly object lockObject = new object();
// 어플리케이션 종료 상태 플래그 (종료 시 잘못된 접근 방지)
private static bool applicationIsQuitting = false;
/// <summary>
/// 싱글톤 인스턴스에 접근하기 위한 프로퍼티
/// 인스턴스가 없을 경우 자동으로 생성
/// </summary>
public static T Instance
{
get
{
// 어플리케이션이 종료 중인 경우 null 반환
if (applicationIsQuitting)
{
Debug.LogWarning($"[Singleton] Instance '{typeof(T)}' already destroyed. Returning null.");
return null;
}
// 스레드 안전성을 위해 lock 사용
lock (lockObject)
{
// 인스턴스가 없는 경우 새로 생성
if (instance == null)
{
// 씬에 이미 존재하는 인스턴스 검색
instance = FindAnyObjectByType<T>();
// 씬에 존재하지 않는 경우 새로 생성
if (instance == null)
{
// 새로운 게임오브젝트 생성
GameObject singletonObject = new GameObject();
singletonObject.name = $"{typeof(T).Name} (Singleton)";
// 컴포넌트 추가
instance = singletonObject.AddComponent<T>();
// 씬 전환시 파괴되지 않도록 설정
DontDestroyOnLoad(singletonObject);
Debug.Log($"[Singleton] Created new instance of {typeof(T).Name}");
}
}
return instance;
}
}
}
/// <summary>
/// 컴포넌트가 활성화될 때 호출됨
/// 싱글톤 초기화 수행
/// </summary>
protected virtual void Awake()
{
InitializeSingleton();
}
/// <summary>
/// 싱글톤 초기화 로직
/// 인스턴스 중복 생성 방지 및 설정 관리
/// </summary>
protected virtual void InitializeSingleton()
{
// 스레드 안전성을 위해 lock 사용
lock (lockObject)
{
// 인스턴스가 아직 설정되지 않은 경우
if (instance == null)
{
// 현재 인스턴스를 싱글톤으로 설정
instance = this as T;
// 씬 전환시 파괴되지 않도록 설정
DontDestroyOnLoad(gameObject);
}
// 이미 인스턴스가 존재하고 현재 인스턴스와 다른 경우 (중복 생성)
else if (instance != this)
{
Debug.LogWarning($"[Singleton] Multiple instances of {typeof(T).Name} found. Destroying duplicate.");
// 중복 인스턴스 제거
Destroy(gameObject);
}
}
}
/// <summary>
/// 어플리케이션이 종료될 때 호출됨
/// 인스턴스 접근 방지를 위해 플래그 설정
/// </summary>
protected virtual void OnApplicationQuit()
{
applicationIsQuitting = true;
}
/// <summary>
/// 컴포넌트가 파괴될 때 호출됨
/// 인스턴스 정리 수행
/// </summary>
protected virtual void OnDestroy()
{
// 현재 파괴되는 인스턴스가 싱글톤 인스턴스인 경우
if (instance == this)
{
// 어플리케이션 종료 플래그 설정
applicationIsQuitting = true;
}
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SingletonMonobehaviour<T> : MonoBehaviour where T : MonoBehaviour
{
static T _Instance = null;
public static T Instance
{
get
{
if (_Instance == null)
{
//_Instance가 Null일 경우 찾아본다.
_Instance = (T)FindObjectOfType(typeof(T));
if (_Instance == null)
{
var _NewGameObject = new GameObject(typeof(T).ToString());
_Instance = _NewGameObject.AddComponent<T>();
}
}
return _Instance;
}
}
protected virtual void Awake()
{
if (_Instance == null)
{
_Instance = this as T;
}
DontDestroyOnLoad(gameObject);
}
}
// Singleton 상속
public class TestApp : SingletonMonobehaviour<TestApp>
{
protected override void Awake()
{
base.Awake();
}
public void TestFunction()
{
}
}
public class TestSingleton : MonoBehaviour
{
private void Awake()
{
TestApp.Instance.TestFunction();
}
}
클래스의 인스턴스를 반환하는 공용 정적 속성
인스턴스가 null이면 장면에서 클래스의 기존 인스턴스를 검색
인스턴스를 찾을 수 없으면 새 인스턴스를 생성
if (_Instance == null)
{
//_Instance가 Null일 경우 찾아본다.
_Instance = (T)FindObjectOfType(typeof(T));
if (_Instance == null)
{
var _NewGameObject = new GameObject(typeof(T).ToString());
_Instance = _NewGameObject.AddComponent<T>();
}
}
return _Instance;
인스턴스가 장면에 하나만 존재하도록 하는 편리한 방법으로
게임 상태, 컨트롤러 또는 여러 인스턴스를 가져서는 안 되는 기타 구성 요소를 관리하는 데 유용



