DontDestroyOnLoad 

파괴하지 않을 게임 오브젝트 만들기

 

작성 기준 버전 :: 2019.1.4f1

 

[이 포스트의 내용을 유튜브 영상으로도 시청하실 수 있습니다]

 

유니티에서는 씬(Scene, 장면) 단위로 게임이 플레이될 공간이나 장소 등을 구현하며, 한 씬에서 다른 씬으로 넘어갈 때는, 기존 씬이 언로드되면서 기존 씬에 있던 게임 오브젝트(Game Object)는 모두 파괴된다. 아래의 예시를 보자.

 

 

위 이미지는 Destroy Object라는 이름의 게임 오브젝트 다섯 개를 배치한 Test Scene의 캡처 화면이다. 플레이가 시작되면 아무것도 없는 Other Scene으로 넘어가게 설계되어 있다.

 

 

설계대로 플레이 버튼을 누르면 Test Scene에서 Other Scene으로 이동하며 씬에 배치되어 있는 다섯 개의 Destroy Object가 사라지는 것을 볼 수 있다.

 

 

 

DontDestoryOnLoad 사용법

 

위의 예시에서 볼 수 있듯이 유니티에서는 새로운 씬을 불러오면 이전 씬에 남아있던 게임 오브젝트들은 모두 사라진다. 하지만 개발자의 의도나 설계에 따라서 몇몇 게임 오브젝트들은 다른 씬으로 넘어갈 때 파괴되지 않도록 할 필요성이 생길 수도 있다.

 

public class DontDestoryObject : MonoBehaviour
{
    private void Awake()
    {
        DontDestroyOnLoad(gameObject);
    }
}

 

씬 로드시 파괴하지 않을 오브젝트로 만들려면 바로 위의 코드처럼 DontDestroyOnLoad()함수를 호출해서 매개변수로 자신의 게임 오브젝트를 전달하면 된다.

 

   

이렇게 파괴하지 않을 오브젝트로 만들어진 게임 오브젝트는 게임 플레이가 시작되고 함수가 호출되면 위의 이미지처럼 Test Scene에서 DontDestroyOnLoad 영역으로 옮겨진다.

 

 

만들어진 스크립트를 Dont Destroy Game Object라는 이름의 구체 게임 오브젝트에 붙인 다음 플레이 버튼을 눌러보면 Test Scene에서 Other Scene으로 넘어가면서 Destroy Object는 전부 사라지지만 Dont Destory Game Object는 남아있는 것을 확인할 수 있다.

 

 

Don't Destroy On Load 게임 오브젝트 파괴하기

 

Don't Destory On Load로 설정된 게임 오브젝트는 그럼 파괴할 수 없는 것인가? 라고 생각할 수도 있다. 하지만 제일 앞의 단어가 Can't가 아니라 Don't 임을 명심하자. 파괴할 수 없는 것이 아니라 파괴하지 않는 것이다.

 

Destroy(gameObject);

 

Don't Destory On Load로 설정된 게임 오브젝트는 Destroy() 함수를 이용하면 손쉽게 다시 파괴할 수 있다.

 

 

설계시 주의 사항

 

Don't Destory On Load 게임 오브젝트를 사용한 설계를 할 때는 주의할 점이 있다.

 

 

위의 이미지와 같이 Don't Destory On Load가 적용된 게임 오브젝트가 들어있는 씬과 다른 씬을 여러 번 왔다 갔다 하는 방식의 구조를 생각해보자. 

 

Test Scene에 진입하면 파괴하지 않는 게임 오브젝트가 Don't Destroy On Load 영역으로 이동되면서 씬을 이동해도 파괴되지 않게 될 것이다. 그 다음 Other Scene으로 이동했다가 다시 Test Scene으로 돌아오면 어떻게 될까? 파괴하지 않는 게임 오브젝트는 Don't Destroy On Load 영역으로 이동했으니 더 이상 Test Scene에 남아있지 않을까?

 

아니다. 씬을 새로 불러올 때는 해당 씬의 초기 상태로 불러오기 때문에 파괴하지 않는 게임 오브젝트는 새 것이 생성되어 있으며 이것은 그대로 다시 Don't Destroy On Load 영역으로 옮겨진다. 즉, 똑같은 파괴하지 않는 게임 오브젝트가 2개가 되어버리는 것이다.

 

 

그대로 두 씬을 왕복하면 같은 게임 오브젝트가 계속해서 누적되는 문제가 발생한다. 이 문제는 그대로 불필요한 메모리 사용을 증가시킬 것이고, 뿐만 아니라 예측할 수 없는 작동 문제 역시 일으킬 수 있다. 

 

 

해결 방법 1 : 중복 검사 후 파괴하기

 

public class DontDestoryObject : MonoBehaviour
{
    private void Awake()
    {
        var obj = FindObjectsOfType<DontDestoryObject>();
        if (obj.Length == 1)
        {
            DontDestroyOnLoad(gameObject);
        }
        else
        {
            Destroy(gameObject);
        }
    }
}

 

해당 게임 오브젝트를 파괴하지 않는 게임 오브젝트로 설정하는 이유가 게임 내에서 단 하나만 존재하는 오브젝트를 만들고자 하는 경우라면 가장 간단하고 손쉬운 해결 방법으로는 게임 오브젝트가 생성된 직후에 실행되는 Awake() 함수에서 현재 씬에 있는 같은 오브젝트가 몇 개인지 검사를 한 뒤 2개 이상이라면 생성된 오브젝트를 파괴하는 방법이다.

 

 

해결 방법 2 : 초기화 씬 구현하기

 

 

두 번째 방법으로는 파괴하지 않는 게임 오브젝트를 생성하는 전용 씬을 만들고 그 씬에서 파괴하지 않는 게임 오브젝트를 생성한 뒤 다른 씬만 오가는 방식이다. 이 방법 게임 내에서 단 하나만 존재하는 오브젝트를 만들고자 하는 경우에 유용한 방법이다.

 

 

해결 방법 3 : 라이프 사이클 관리하기

 

파괴하지 않는 게임 오브젝트는 위의 예시에서 볼 수 있듯이 씬을 이동한다고 해서 파괴되지 않는다. 그렇기 때문에 제대로 관리하지 않는다면 생성되는 족족 Don't Destroy On Load 영역에 게임 오브젝트가 쌓일 것이다. 

 

위의 두 가지 방법은 게임 내에서 해당 오브젝트를 단 하나만 만들고자 하는 경우에 유용한 방법이다. 만약 해당 오브젝트가 파괴되지 않아야 하지만 여러 개의 오브젝트를 만드는 것을 허용하는 구조라면 위의 방법들은 적절하지 않다.

 

또한 앞선 예시들은 모두 파괴하지 않을 게임 오브젝트를 정적으로 씬에 배치를 해서 씬이 불러와질 때마다 생성되게 만드는 구조를 채용했다. 하지만 이와 반대로 같은 종류의 파괴되지 않을 게임 오브젝트를 여러 개 생성하는 것을 허용하려고 한다면 정적인 씬 배치 방식보다는 프리팹으로 관리하며 원하는 시점에 생성하는 것이 좋다.

 

 

이러한 경우에 더욱 주의해야할 점은 파괴하지 않는 게임 오브젝트들이 동적으로 여러 개 생성되어 작동하고 있으며, 이후에도 계속해서 생성된다는 점이다. 때문에 파괴하지 않은 게임 오브젝트들에 대해서 제대로 추적/관리해야 하며 해당 오브젝트의 사용이 끝나면 파괴하는 식으로 라이프 사이클(Life Cycle) 관리가 필요하다.

반응형

+ Recent posts