Google Play에서 다운로드 App Store에서 다운로드

Unity

유니티 고수만 아는 싱글턴 관리 비법: '이 코드' 한 줄로 하이어라키(Hierarchy) 깔끔하게 정리하기

정보처리마법사 2025. 8. 22. 09:12
반응형

유니티 고수만 아는 싱글턴 관리 비법: '이 코드' 한 줄로 하이어라키(Hierarchy) 깔끔하게 정리하기

 

 

안녕하세요, 유니티 개발자 여러분!

혹시 여러분의 유니티 프로젝트 하이어라키(Hierarchy) 창은 안녕하신가요? 프로젝트 규모가 조금만 커져도 GameManager, SoundManager, UIManager, DataManager 등... 온갖 매니저들이 최상단(루트)에 흩어져 지저분해 보이는 경험, 다들 한 번쯤은 있으실 겁니다.

"어쩔 수 없지. 싱글턴 매니저는 DontDestroyOnLoad를 써야 하고, 그건 루트 오브젝트에만 되니까..."

라고 생각하며 스스로를 위로하셨나요? 오늘, 그 고정관념을 깨뜨릴 아주 우아하고 참신한 방법을 소개해 드리고자 합니다. 단 한 줄의 코드로 지저분했던 하이어라키를 전문가처럼 정리하고, 동료에게 "오, 이거 어떻게 하셨어요?" 라는 질문을 받게 될 준비를 하세요!

 

우리가 겪는 딜레마: 왜 매니저들은 흩어져야만 했을까?

문제의 시작은 바로 DontDestroyOnLoad 입니다. 이 함수는 씬(Scene)이 전환될 때 게임 오브젝트가 파괴되지 않도록 보호해주는, 싱글턴 매니저에게는 필수적인 기능입니다. 하지만 Unity 엔진의 규칙상 이 기능은 부모가 없는 최상위, 즉 루트(Root) 게임 오브젝트에만 적용할 수 있다는 치명적인 제약이 있습니다.

결국 우리는 울며 겨자 먹기로 모든 전역 매니저들을 하이어라키 최상단에 꺼내놓을 수밖에 없었습니다. 이는 당장 기능 구현에는 문제가 없지만, 다음과 같은 문제점들을 야기합니다.

  • 가독성 저하: 중요한 오브젝트를 찾기 위해 계속 스크롤해야 합니다.
  • 관리의 어려움: 매니저가 10개, 20개로 늘어나면 어떤 것이 있는지 한눈에 파악하기 힘듭니다.
  • 협업의 비효율: 여러 사람이 작업할 때, 누가 어떤 매니저를 추가했는지 파악하기 어렵고 충돌의 원인이 되기도 합니다.

발상의 전환: 에디터에서만 부모를 갖게 하자!

여기서 우리는 생각을 조금 비틀어 볼 필요가 있습니다. "꼭 처음부터 루트 오브젝트일 필요가 있을까? 게임이 시작되는 그 순간에만 루트 오브젝트가 되면 되지 않을까?"

바로 이 아이디어가 모든 문제의 해결 열쇠입니다.

핵심 원리는 이렇습니다.

  1. 에디터에서는 깔끔한 정리를 위해 비어있는 게임 오브젝트(@[Managers])의 자식으로 모든 매니저를 넣어 둡니다.
  2. 게임이 실행되면(런타임), 각 매니저들이 Awake() 함수에서 스스로 부모-자식 관계를 끊고 루트 오브젝트로 독립하게 만듭니다.

결과적으로, 개발할 땐 깔끔한 상태를 유지하고, 게임이 실행될 땐 Unity의 규칙을 완벽하게 준수하게 되는 것입니다.

 

실전 적용 가이드 (코드 포함)

이제 마법을 부려볼 시간입니다. 단계별로 차근차근 따라 해 보세요.

1단계: 정리용 부모 오브젝트 생성

하이어라키 창에서 마우스 오른쪽 클릭 -> Create Empty를 선택해 빈 게임 오브젝트를 만듭니다. 그리고 이름을 @[Managers] 또는 --- Singleton Managers --- 처럼 눈에 잘 띄게 지어주세요. (@나 -를 앞에 붙이면 하이어라키 상단에 정렬되어 편리합니다.)

2단계: 매니저들을 자식으로 이동

기존에 루트에 흩어져 있던 GameManager, SoundManager 등의 모든 싱글턴 매니저들을 방금 만든 @[Managers] 오브젝트 안으로 드래그해서 넣어주세요.

(이미지 Alt 정보: Unity-Singleton-Hierarchy)

3단계: 매니저 스크립트에 코드 한 줄 추가

이제 가장 중요한 단계입니다. 모든 싱글턴 매니저 스크립트의 Awake() 함수로 이동하여 DontDestroyOnLoad 호출 바로 아래에 다음 코드를 단 한 줄 추가합니다.

C#
 
// 대부분의 싱글턴 매니저가 사용하는 일반적인 Awake() 함수 예시입니다.
// 여러분의 코드에 맞게 적용하세요.

private static GameManager _instance;
public static GameManager Instance
{
    get 
    {
        if (_instance == null)
            Debug.LogError("GameManager is NULL");
        return _instance;
    }
}

void Awake()
{
    if (_instance != null)
    {
        Destroy(gameObject);
        return;
    }
    
    _instance = this;
    
    // 이 두 줄이 핵심입니다!
    DontDestroyOnLoad(gameObject);
    transform.SetParent(null); // <<-- 바로 이 코드 한 줄을 추가하세요!
}

transform.SetParent(null); 이 코드는 "나의 부모를 null(없음)으로 설정하겠다" 라는 의미입니다. 즉, 게임이 시작될 때 스스로 @[Managers] 와의 부모-자식 관계를 끊고 당당하게 루트 오브젝트로 독립하는 것입니다.

 

이 방법이 가져다주는 엄청난 이점

  • 압도적인 가독성: 하이어라키가 놀랍도록 깔끔해져 원하는 오브젝트를 바로 찾을 수 있습니다.
  • 향상된 프로젝트 구조: 누가 봐도 매니저들이 어디에 모여 있는지 명확하게 알 수 있습니다.
  • 협업 효율 극대화: 팀원 모두가 동일한 규칙으로 매니저를 관리하므로 충돌과 혼란이 줄어듭니다.
  • 실수 방지: 새로운 매니저를 만들 때 자연스럽게 @[Managers] 폴더에 넣게 되어 실수를 예방합니다.

마치며

개발은 단순히 기능을 구현하는 것에서 끝나지 않습니다. 내가 만든 코드를 동료가, 그리고 미래의 내가 얼마나 쉽게 이해하고 유지보수할 수 있는지가 진정한 실력의 척도가 되기도 합니다.

오늘 소개해 드린 transform.SetParent(null); 트릭은 단순한 코드 한 줄을 넘어, 여러분의 프로젝트를 한 단계 더 성숙시키는 현명한 습관이 될 것입니다. 지금 바로 여러분의 프로젝트에 적용해보고 전문가 수준으로 관리되는 하이어라키의 쾌적함을 느껴보시길 바랍니다.

 

반응형
Google Play에서 다운로드 App Store에서 다운로드