Quick Reference
DontDestroyOnLoad는 scene load 때 파괴하지 않을 object를 지정합니다. GameObject 또는 Component를 넘기면 root GameObject와 그 Transform children이 보존됩니다. root가 아닌 child에 호출해도 전역 service로 승격하는 용도로 쓰지 않습니다.
| 확인할 점 | 동작 | 설계 선택 |
|---|---|---|
| 대상 위치 | root GameObject 또는 root의 Component여야 함 | bootstrap scene의 root service로 생성 |
| 보존 범위 | root와 모든 child Transform hierarchy | UI, AudioSource처럼 함께 살아야 할 child만 둠 |
| duplicate | 새 scene에서 같은 prefab이 또 생성될 수 있음 | 한 곳에서만 생성하거나 Awake guard |
| scene object reference | 이전 scene의 object는 파괴됨 | scene load 후 다시 resolve·clear |
| play mode static | domain reload 설정에 따라 static이 남을 수 있음 | static reset policy와 test cleanup |
private void Awake()
{
DontDestroyOnLoad(gameObject); // root GameObject에서 호출
}생성 위치와 duplicate 방지
가장 단순한 구조는 bootstrap scene이나 runtime bootstrap code가 service를 한 번만 만드는 것입니다. 모든 gameplay scene에 같은 manager prefab을 넣고 Awake에서 중복을 파괴하는 방식은 빠르게 시작할 수 있지만, scene 순서·additive load·test setup에 따라 duplicate 생성 경쟁을 계속 관리해야 합니다.
public sealed class AudioService : MonoBehaviour
{
public static AudioService Instance { get; private set; }
private void Awake()
{
if (Instance != null && Instance != this)
{
Destroy(gameObject);
return;
}
Instance = this;
DontDestroyOnLoad(gameObject);
}
private void OnDestroy()
{
if (Instance == this)
{
Instance = null;
}
}
}Instance guard는 object가 하나만 남도록 할 뿐, duplicate prefab을 매 scene에서 생성했다가 Destroy하는 비용·설계 혼란까지 없애지는 않습니다. service source를 하나로 고정할 수 있으면 그 편이 좋습니다.
scene reference와 lifecycle
보존된 service가 [SerializeField]로 이전 scene의 Player, Camera, UI를 들고 있으면 scene 전환 뒤 reference는 destroyed Unity object를 가리킬 수 있습니다. global service에는 scene-local reference를 오래 cache하지 않거나, SceneManager.sceneLoaded에서 현재 scene의 대상만 다시 연결하고 unload 때 해제합니다.
using UnityEngine.SceneManagement;
private void OnEnable()
{
SceneManager.sceneLoaded += OnSceneLoaded;
}
private void OnDisable()
{
SceneManager.sceneLoaded -= OnSceneLoaded;
}
private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
{
activeCamera = Camera.main;
}Additive scene에서는 어떤 scene이 active인지, service가 어느 scene의 target를 소유하는지 더 명확히 정합니다. DontDestroyOnLoad를 scene loading ownership의 대체로 쓰지 않습니다.
static과 Enter Play Mode
Editor에서 Domain Reload를 끈 설정은 빠른 Play Mode 진입을 주지만 static field가 이전 run에서 남을 수 있습니다. singleton Instance가 destroyed object를 보거나 test 사이에 event listener가 남는 문제는 build보다는 Editor에서 먼저 나타날 수 있습니다. RuntimeInitializeOnLoadMethod 같은 명시적 reset과 test teardown 중 어느 정책을 쓰는지 팀에서 통일합니다.
DontDestroyOnLoad object도 앱 종료, test cleanup, title scene으로 완전히 돌아갈 때는 소유자가 Destroy할 수 있어야 합니다. 전역 object라는 이유로 끝없이 남겨 두지 않습니다.
자주 틀리는 부분
| 증상 | 원인 | 수정 |
|---|---|---|
| scene마다 BGM이 겹침 | 각 scene prefab이 service를 새로 생성 | bootstrap 하나로 생성하거나 duplicate guard와 source 정책 적용 |
| child object만 남을 것으로 기대 | root 대상 호출은 children도 함께 보존 | persistent hierarchy를 최소화하고 parent를 분리 |
| 다음 scene에서 Player reference가 Missing | service가 이전 scene object를 cache | sceneLoaded/unload에 재연결·clear 정책 추가 |
| Editor에서만 singleton이 두 개처럼 보임 | Domain Reload disabled인데 static reset 없음 | Enter Play Mode 설정과 static reset을 같이 점검 |
| child에 호출했는데 유지되지 않음 | DontDestroyOnLoad의 root object 제약 | root service에서 호출하고 hierarchy 구조 수정 |
참고 링크
3 sources