싱글톤(Singleton)은 게임 개발에서 자주 쓰이는 디자인 패턴 중 하나로
객체를 여러 개 인스턴스화시키지 않고 하나만 만들어서 그 객체에 접근하는 디자인 패턴입니다.
Singleton 쓰는 이유
- 객체를 여러 개 만드는 것보다 하나만 만드는 것이 메모리에 할당되는 데이터양이 더 적습니다.
- 게임 내내 접근해야 할 전역 변수, 함수가 필요할 때 사용합니다.
보통 게임에서 싱글톤은 Manager 스크립트에서 자주 쓰입니다.
Game Manager, Input Manager, Enemy Manager, Sound Manager 등등
슈퍼마리오 같은 스테이지 게임을 예시로 들면
Game Manager에서 ChangeStage, GameOver 같은 함수들이 있다고 치겠습니다.
그러면 마리오가 Lives를 다 소비하면 GameOver가 되니까
언제든지, 어떤 스테이지던지 GameOver가 될 수 있습니다.
마찬가지로 마리오가 스테이지를 클리어 하면 ChangeStage가 발동됩니다.
예시가 좀 이상할수도 있는데 아무튼 이렇게 게임에서 언제든지 사용할 거 같은 함수나 변수를 사용할 때 필요합니다.
구현
Singleton
public class GameManager : MonoBehaviour
{
public static GameManager Instance { get; private set; }
private void Awake()
{
if (Instance == null)
{
Instance = this;
DontDestroyOnLoad(this);
}
else
{
Destroy(gameObject);
}
}
public void ChangeStage(string stage)
{
}
public void GameOver()
{
}
}
일반적으로 유니티에서 싱글톤은 위 스크립트처럼 만듭니다.
GameManager 오브젝트를 만들어서 싱글톤으로 작성된 스크립트를 넣습니다.
static으로 자기 자신을 Instance에 넣어줬으므로 고정적으로 메모리 static 영역에 할당됩니다.
또한, 프로그램이 시작하고 끝날 때까지 GameManager는 계속 살아있어서
해당 클래스 내 함수나 변수에 접근할 수 있습니다.
private GameManager gameManager;
private void Awake()
{
gameManager = GameManager.Instance;
gameManager.GameOver();
}
private void Awake()
{
GameManager.Instance.GameOver();
}
사용 방법은 위 두 가지 방법 중 하나를 사용하면 되는데
위 방법은 클래스에서 GameManager를 여러 번 사용할 거 같다 싶으면 참조에 저장시켜서 함수를 실행시키고
아래 방법은 적게 사용할꺼 같다 하면 간단하게 사용할 수 있는 방법입니다.
상황에 따라 다른 방법을 사용하면 될 거 같습니다.
Generic Singleton
위 방법은 매번 싱글톤을 만들 때마다 Instance를 만들고 this로 넣어놓고 하는 작업을 반복해야 합니다.
굳이 저렇게 안하고 상속으로 싱글톤을 만드는 방법이 있는데
따로 MonoBehaivour를 상속한 Singleton 클래스를 만들어주면 됩니다.
public class MonoSingleton<T> : MonoBehaviour where T : MonoBehaviour
{
private static readonly object lockObject = new object();
private static T instance;
public static T Instance
{
get
{
lock (lockObject)
{
if (instance == null)
{
instance = FindFirstObjectByType(typeof(T)) as T;
DontDestroyOnLoad(instance);
}
}
return instance;
}
}
private void OnDestroy()
{
instance = null;
}
}
이 클래스를 만든 후
public class GameManager : MonoSingleton<GameManager>
{
public void ChangeStage(string stage)
{
}
public void GameOver()
{
}
}
이렇게 MonoSingleton을 상속받으면 간단하게 싱글톤을 사용할 수 있습니다.
MonoSingleton도 MonoBehaviour를 상속하므로 반드시 GameObject를 만들어서
그 안에 GameManager를 넣어줘야 합니다.
MonoSingleton에서 lock을 거는 이유는
여러 thread가 Instance에 접근하는 과정에서 경쟁 상태에 돌입해 오류가 날 수 있으므로
한 thread만 접근하도록 lock을 거는겁니다.
'유니티 > Tutorial' 카테고리의 다른 글
Unity Compute Shader 01 (0) | 2025.03.22 |
---|---|
Unity New Input System (0) | 2025.02.19 |
Unity FSM 유한 상태 머신 (0) | 2025.01.13 |
UniTask란? (0) | 2025.01.09 |