본문 바로가기
Unity

유니티에서 Scene 전환에도 안전한 GameManager class 만들기 (singleton)

by Oz Driver 2025. 3. 30.

GameManger 같은 전역 클래스가 필요할 경우, 흔히 singleton 패턴을 사용합니다. 그런데 하나의 scene 이 아니라 2개 이상의 scene 에서 GameManager 를 사용하려면, 각 scene 마다 GameManager GameObject 를 hierarchy 창에 생성해야 하는 문제에 부딪히게 됩니다. 이 문제를 깔끔하게 해결하려면 싱글톤 구조를 약간 확장해줄 필요가 있습니다.

 

 

Scene 전환이 있을 경우에도 안전한 singleton 패턴

public class GameManager : MonoBehaviour
{
    public static GameManager Instance { get; private set; }

    void Awake()
    {
        if (Instance != null && Instance != this)
        {
            Destroy(gameObject); // 중복 인스턴스 제거
            return;
        }

        Instance = this;
        DontDestroyOnLoad(gameObject); // 씬 전환 시에도 유지
    }
}

 

이 구조는 다음과 같은 상황에서 안정적으로 작동합니다:

 

* GameManager 가 첫 번째 scene 에서 한 번만 생성됩니다.

* DontDestroyOnLoad 로 인해 이후 scene 에서도 유지됩니다.

* 두 번째 scene 부터는 중복 생성 시 바로 파괴됩니다.

 

하지만 문제는 GameManager 가 없는 특정 scene 만 단독으로 실행(Play) 할 경우입니다.

이때는 GameManager 가 존재하지 않기 때문에 NullReferenceException이 발생할 수 있습니다.

 

 

Resources 폴더를 통한 GameManager 자동 생성

이 문제를 해결하려면 GameManager 를 사전에 Resources 폴더에 prefab 으로 저장해두고, 코드에서 자동으로 로딩되도록 구성하면 됩니다.

GameManager 프리팹 생성 및 저장

1) Hierarchy에서 GameManager 오브젝트를 생성합니다.

2) Project 창의 Assets/Resources 폴더로 드래그하여 프리팹으로 저장합니다.

3) Hierarchy에 있는 GameManager 오브젝트는 삭제합니다.

 

GameManager.cs 에 자동 로딩 코드 추가

[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
static void AutoCreateSingleton()
{
    if (Instance == null)
    {
        GameObject prefab = Resources.Load<GameObject>("GameManager");
        if (prefab != null)
        {
            _ = Instantiate(prefab);
        }
        else
        {
            Debug.LogError("GameManager 프리팹을 Resources 폴더에서 찾을 수 없습니다.");
        }
    }
}

 

이제 어느 씬에서든 GameManager가 존재하지 않으면 자동으로 생성되어 null 참조 문제 없이 안전하게 작동하게 됩니다.

 

 

마무리

Scene 이 하나일 때는 단순한 singleton 구조로도 충분하지만, 여러 scene 을 오가는 게임에서는 조금 더 견고한 구조가 필요합니다. Resources 폴더를 활용한 자동 생성 방식은 이러한 문제를 깔끔하게 해결해줄 수 있으며, 프로젝트가 커질수록 유용해집니다.

 

 

추가로 ...

만약 GameManager 와 같은 싱글톤 클래스가 scene 마다 초기화해야 할 데이터를 가지고 있다면, Awake() 나 Start() 함수에 의존해서는 안 됩니다. 왜냐하면 씬이 다시 로드되어도 이 함수들은 이미 호출되었기 때문에 다시는 호출되지 않습니다.

이런 경우에는 반드시 SceneManager.sceneLoaded 이벤트를 활용해, 씬이 바뀔 때마다 필요한 데이터를 초기화해주는 구조로 만들어야 합니다. SceneManager.sceneLoaded 에 대해서는 이후에 자세히 다뤄보겠습니다.