포스트

[Unity] 의존성 초기화 순서 문제

[Unity] 의존성 초기화 순서 문제

Unity에서 의존성 초기화 순서 문제

게임 개발 중 여러 컴포넌트 간에 초기화 순서가 중요할 경우, 단순히 Start()에 초기화를 맡기면 불안정한 실행 순서로 인해 예기치 않은 버그가 발생할 수 있습니다.

이 문서는 초기화 순서 문제를 해결하는 실전 전략과 예제를 정리한 자료입니다.


1. 문제 개요

Unity는 Start() 메서드의 호출 순서를 보장하지 않기 때문에 다음과 같은 상황에서 문제가 발생할 수 있습니다:

  • A는 B를 참조하여 Start()에서 초기화
  • B도 Start()에서 내부 상태를 설정
  • Unity가 A → B 순으로 Start()를 호출하면 A는 초기화되지 않은 B를 참조하게 됨

2. 해결 전략

전략설명
Init() 메서드 분리수동으로 초기화 순서를 지정
Script Execution Order 설정Unity 설정으로 호출 순서 고정
Awake()와 Start() 분리Awake는 Start보다 먼저 호출됨
중앙 관리자 패턴초기화 순서를 직접 통제
ScriptableObject 활용미리 정의된 정적 데이터 사용

3. 가장 안전한 방식: Init() 함수 분리

예제

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public class B : MonoBehaviour
{
    public string config;

    public void Init()
    {
        config = "B 초기화 완료";
        Debug.Log("B 초기화됨");
    }
}

public class A : MonoBehaviour
{
    public B b;

    public void Init()
    {
        Debug.Log("A: B의 설정 = " + b.config);
    }
}

public class InitController : MonoBehaviour
{
    public A a;
    public B b;

    void Start()
    {
        b.Init();   // B 먼저 초기화
        a.Init();   // 이후 A에서 B를 안전하게 참조
    }
}
  • 명시적 순서로 초기화되므로 안정적
  • 게임 시작 시점이나 로딩 후 자동 수행 가능

4. 보조 방법: Script Execution Order

설정 위치

  • Edit > Project Settings > Script Execution Order

사용법

  • B 스크립트를 A보다 위에 배치 → B의 Awake() / Start()가 먼저 실행됨

주의: 코드 외부 설정이므로 의존 관계를 파악하기 어려움


5. Awake() vs Start() 분리 활용

메서드호출 시점용도
Awake()오브젝트 활성화 시 즉시 호출자체 초기화, 외부 의존성 없음
Start()프레임 시작 직전에 호출Unity 오브젝트 참조 필요 시 사용

예시

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class B : MonoBehaviour
{
    public string config;

    void Awake()
    {
        config = "B에서 설정됨";
    }
}

public class A : MonoBehaviour
{
    public B b;

    void Start()
    {
        Debug.Log("B의 config: " + b.config);
    }
}

6. 중앙 관리자로 통제하는 방식

구조

1
2
3
4
5
6
7
8
9
10
11
public class GameInitializer : MonoBehaviour
{
    public PlayerManager playerManager;
    public EnemyManager enemyManager;

    void Start()
    {
        playerManager.Init();
        enemyManager.Init();
    }
}
  • 각 모듈의 Init()을 순서대로 호출해 초기화
  • 대규모 프로젝트에서 유용

7. ScriptableObject로 의존성 분리

  • ScriptableObject는 런타임 이전에 데이터를 정의할 수 있음
  • 데이터를 미리 세팅해두고 참조만 하도록 하면 초기화 타이밍 문제 회피 가능

8. 요약

해결 방법장점사용 추천 상황
Init() 메서드명시적, 안전함대부분의 상황
Script Execution Order간편함소규모 테스트용
Awake/Start 분리간단한 순서 제어내부 전용 초기화
중앙 초기화전체 흐름 통제 가능대규모 초기화
ScriptableObject런타임 이전 정의정적 데이터 참조

초기화 순서를 명시적으로 제어하는 것이 버그를 예방하는 가장 좋은 방법입니다.

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.