Pv_log

Manage scene flow and data: Implement data persistence between scenes 본문

Unity Learn 번역/Pathway: Junior Programmer

Manage scene flow and data: Implement data persistence between scenes

Priv 2022. 1. 4. 23:55

출처


 

 

1. 서언

이제 앱에 몇 가지 버튼들을 설정해주어 사용자들이 다음과 같은 행동을 수행할 수 있도록 만들어주겠습니다:

● Menu 씬과 Main 씬 사이를 이동

● 애플리케이션 종료 (또는 에디터 상에서 Play 모드 종료)

다음으로, 사용자가 커스텀 색상 선택기 버튼을 클릭하여 색상을 선택하면, 씬(Scene)을 시작할 때 선택한 색상이 창고에 있는 지게차들 색상으로 적용되도록 애플리케이션을 구성해보겠습니다.

여러분의 프로젝트는 다음과 같이 동작해야 합니다:


(영상: 링크 참조)


영상과 같이 동작하도록 만들기 위해서는 먼저 데이터 지속성의 기초에 대한 이해가 필요합니다.

 


 

2. 데이터 지속성이란?

데이터 지속성이란, 데이터를 생성하는 데 사용되는 프로세스보다 데이터를 더 오래 지속시키는 것을 의미합니다. 데이터 지속성의 몇 가지 예로는 다음과 같습니다:

● 일회성 멀티플레이어 게임(예: 퀴즈 파티 게임)에서 선택한 특정 플레이어 아이콘

● 애플리케이션 시작 때 이름을 입력하고 이후 세션 동안 이름이 표시됨 (예: 풀링 도구)

● 오랫동안 플레이하는 게임들의 진행 상황 (예: 콘솔 RPG 게임)

● 워드 프로세싱 애플리케이션에서의 작업

씬(Scenes) 사이의 데이터 지속성

유니티 상에서 씬 내에서 생성된 데이터는 데이터를 생성한 해당 씬 내에서 쉽게 접근해 사용할 수 있습니다. 하지만 사용자가 다른 씬으로 넘어가게 되면 어떻게 될까요? 일반적으로, 해당 데이터는 손실됩니다. 씬 사이의 데이터 지속성은 사용자가 여러분의 애플리케이션을 사용하는 동안, 사용자에게 동일한 경험을 제공하도록 씬에서 씬으로 데이터를 전달하는 프로세스입니다. 위의 첫 2가지 예시는 씬 사이의 데이터 지속성의 예시입니다. - 일반적으로 씬 여러 개를 사용하는 단일 세션 경험입니다.

세션 사이의 데이터 지속성

다른 예시 2개(오랫동안 플레이하는 게임과 워드 프로세싱 애플리케이션)는 일반적으로 다중 세션 경험입니다. 사용자들은 한 세션을 진행하는 동안 진행사항을 저장하고, 중단한 지점부터 다시 복원하기를 원합니다. 다음은 세션 사이의 데이터 지속성에 대한 예시입니다.

여러분은 더 복잡한 애플리케이션에서 2가지 타입의 데이터 지속성을 자주 접하실 것입니다. - 사용자가 씬 사이를 이동할 때, 함께 따라가야 하며, 여러 세션에 걸쳐서 저장 및 복원될 수 있어야 하는 데이터입니다.

 


 

3. 할 일 검토

자원 관리 시뮬레이션 프로젝트에 대해 간단히 알아보자면, 초기 메뉴(Menu 씬)에서 색상을 선택할 수 있도록 만드는 것과 창고 내에 있는 지게차에 선택된 색상을 적용하는 것(Main 씬)을 포함합니다.

현재, 버튼들이 존재하는 이유는 저희가 버튼들을 위한 사용자 정의 스크립트를 미리 제공했기 때문입니다. - 여러분은 이전 튜토리얼에서 다른 버튼들을 설정하실 때 이 부분에 대해 살펴보셨습니다. 이제 Main 씬에서 색상 데이터를 선택할 수 있도록 만들어 씬 사이의 데이터 지속성을 구현해보겠습니다.

작업을 수행하기 위해 아래의 요소들을 사용할 것입니다:

● DontDestroyOnLoad: 새로운 씬을 로드/언로드 할 때 게임 오브젝트가 메모리 상에 저장되도록 표시해주는 유니티 메서드입니다.

Static 클래스 및 class 멤버: Static 멤버는 특정 객체를 참조하지 않아도 어디에서나 접근할 수 있습니다. 아마 Time.deltaTime 또는 Vector3.forward와 같은 일부 Static 멤버들을 이미 사용해보셨을 수도 있습니다. 이는 특정 Time 객체 또는 특정 vector3가 아닙니다. - static 클래스 멤버의 형식은 ClassName.memberName입니다.

이제 시작해봅시다!

 


 

4. 새로운 스크립트 생성하기

먼저, 여러분은 씬 간에 유지하고자 하는 데이터를 저장할 static 클래스가 될 새로운 스크립트를 작성하셔야 합니다.

1. Project 창에서 Assets > Scripts로 가주세요.

2. Menu 씬에서 새로운 스크립트를 생성하시고, 이름을 MainManager로 설정해주세요.

3. Hierarchy 창에서 새로운 공백 게임 오브젝트를 생성하시고, 이름을 MainManager로 설정해주세요. 방금 만드신 MainManager 스크립트를 할당하시고, IDE에서 스크립트를 열어주세요.

4. 기본 제공되는 Start() 메서드와 Update() 메서드를 삭제하신 뒤, MainManager 클래스에 static 멤버를 생성하기 위한 아래 코드를 추가해주세요:

public class MainManager : MonoBehaviour
{
    // Start() and Update() methods deleted - we don't need them right now

    public static MainManager Instance;

    private void Awake()
    {
        Instance = this;
        DontDestroyOnLoad(gameObject);
    }
}

이 코드는 여러분이 다른 아무 스크립트에서 MainManager 오브젝트에 접근할 수 있도록 만들어줍니다.

 


 

5. 코드 리뷰

이제 코드를 한 줄씩 살펴보겠습니다:

클래스(class) 멤버 선언

public static MainManager Instance;

이 코드는 static 클래스 멤버를 선언하는 코드입니다. static 키워드가 public 키워드 뒤에 온다는 것을 기억해두세요. 이 키워드의 의미는 클래스 멤버 안에 저장된 값들이 클래스의 모든 인스턴스와 공유된다는 것을 의미합니다.

예를 들어, 만약 MainManager의 인스턴스 10개가 씬 안에 있다면, 이는 모두 Instance에 저장된 동일한 값을 공유합니다. 만약 MainManager 10개 중 어떤 1개의 값이 바뀌었다면, 다른 9개의 값도 다 함께 바뀝니다.

Awake메서드 코드

다음으로, 여러분은 오브젝트가 생성되자마자 호출되는 Awake 메서드에 다음과 같은 코드를 추가하셨습니다:

Instance = this;
DontDestroyOnLoad(gameObject);

코드 첫 번째 줄은 클래스 멤버 Instance에 "this"를 저장합니다. - 여기서 this란, MainManager의 현재 인스턴스를 의미합니다. 이제 여러분은 MainManager.Instance를 아무 스크립트에서 호출할 수 있습니다. (예를 들어, Unit 스크립트 상에서) 또한 해당 특정 인스턴스에 대한 링크를 가져올 수 있습니다. Inspector 창에서 스크립트 속성에 게임 오브젝트를 할당했을 때처럼 참조하실 필요가 없습니다.

코드 두 번째 줄은 해당 스크립트에 연결된 MainManager 게임 오브젝트가 씬이 변경될 때 파괴되지 않도록 표시해주는 코드입니다.

 


 

6. 유니티 에디터(Unity Editor) 상에서 테스트하기

이제 변경 사항들을 에디터 상에서 테스트해봅시다:

1. Unity 에디터로 돌아오셔서, Menu 씬을 여시고 Play 모드에 진입해주세요.

2. Hierarchy 창의 게임 오브젝트들을 확인해주세요. MainManager가 여러분의 일반 씬(Menu 씬)에서 DontDestroyOnLoad라는 특별한 씬으로 이동했습니다.

중요: 이 DontDestroyOnLoad라는 씬은 [DebugUpdater]라는 이름의 새로운 게임 오브젝트도 가지고 있습니다. 이 오브젝트는 Unity가 사용하는 디버그 게임 오브젝트이므로, 무시하셔도 됩니다.

3. Start 버튼을 눌러서 Main 씬을 시작하세요. MainManager 게임 오브젝트가 여전히 제자리에 있다면 성공입니다!

4. Back to menu 버튼을 클릭해서 이전 씬으로 돌아오신 뒤, Hierarchy 창을 살펴보세요.

이런, 이제 MainManager 게임 오브젝트가 2개가 되어버렸네요! 이는 MainManager가 우리와 함께 Main 씬에서 본래의 MainManager 인스턴스가 위치해 있던 Menu 씬으로 넘어왔기 때문입니다. 이는 추후에 문제를 일으킬 수도 있습니다. - 다음 파트에서 고쳐보도록 하죠.

 


 

7. Awake 메서드 수정하기

MainManager 게임 오브젝트는 항상 1개만 있어야 하므로, Awake 메서드를 수정해 문제를 해결해보겠습니다:

1. 여러분의 IDE에서 MainManager.cs로 돌아가 주세요.

2. Awake 메서드를 아래 코드와 같이 수정해주세요:

private void Awake()
{
    // start of new code
    if (Instance != null)
    {
        Destroy(gameObject);
        return;
    }
    // end of new code

    Instance = this;
    DontDestroyOnLoad(gameObject);
}

3. 변경 사항을 저장해주세요.

4. 유니티 에디터로 돌아와 아까와 동일한 테스트를 거쳐 어떤 일이 벌어지는지 확인해주세요.

새로운 코드 살펴보기

조건문 하나를 새로 추가하여 Instance가 null인지 아닌지를 검사하도록 만들었습니다. 여러분이 Menu 씬을 최초로 로드하셨을 때는 MainManager가 Instance 변수에 할당되어 있지 않을 것입니다. 이는 즉, Instance가 null임을 의미하므로, 조건문의 검사 결과가 거짓(false)이 되어 이전에 작성하신 코드가 이어서 실행될 것입니다.

그러나, 만약 여러분이 Menu 씬을 다시 로드하게 되면,  이미 1개의 MainManager가 존재할 것이므로, Instance는 null이 아니게 됩니다. 이 경우에는 조건문의 검사 결과가 참(true)이 되어 여분의 MainManager는 삭제되고(destroyed) 스크립트는 거기서 바로 끝나게 됩니다.

이러한 패턴을 싱글톤(Singleton) 패턴이라고 부릅니다. 여러분은 이를 사용해 오직 1개의 MainManager 인스턴스만 존재할 수 있도록 하였으므로, 이는 중앙 액세스 지점 역할을 수행합니다.

 


 

8. 선택된 색상 적재 및 전달

이제 여러분의 애플리케이션에 씬 사이에 데이터를 전달하는 시스템을 구축하였습니다. 이제 새로운 public 멤버를 MainManager에 추가하여 사용자가 선택한 색상을 전달해줄 수 있도록 만들어봅시다:

1. 여러분의 IDE에서 MainManager.cs로 돌아가주세요.

 

2.Awake 메서드 위에 TeamColor라는 이름의 새로운 public 클래스 멤버를 추가해주세요.

public class MainManager : MonoBehaviour
{
    public static MainManager Instance; 

    public Color TeamColor; // new variable declared
    
    private void Awake()
    {
        if (Instance != null)
        {
            Destroy(gameObject);
            return;
        }

        Instance = this;
        DontDestroyOnLoad(gameObject);
    }
}

3. 변경 사항을 저장하시고, 유니티 에디터로 돌아오세요. 여러분의 IDE에서 MenuUIHandler.cs 스크립트를 열어주세요.

이 스크립트에는 NewColorSelected라는 이름의 메서드가 존재하며, 사용자가 새로운 색상을 선택했을 때 호출됩니다. 이제 해당 색상을 검색해서 MainManager에 저장해보겠습니다.

4. NewColorSelected 메서드에 아래 코드를 추가해주세요.

public void NewColorSelected(Color color)
{
    // add code here to handle when a color is selected
    MainManager.Instance.TeamColor = color;
}

끝났습니다. 이제 사용자가 선택한 색상이 MainManager에 저장될 것이므로, Main 씬으로부터 TeamColor 변수에 접근하여 색상 값을 불러올 수 있습니다! 이제 창고에 있는 지게차에 불러온 색상을 적용해주기만 하면 됩니다.

5. 변경 사항을 저장하고, 유니티 에디터로 돌아오세요. Unit.cs 스크립트 파일을 여러분의 IDE에서 열어주세요.

6. 새로운 Start 메서드를 추가하시고, 아래 코드를 작성해주세요.

private void Start()
{
    if (MainManager.Instance != null)
    {
        SetColor(MainManager.Instance.TeamColor);
    }
}

7. 변경 사항을 저장하세요.

새로 추가한 코드를 살펴봅시다.

SetColor는 유닛(지게차)의 색상을 설정해주기 위해 저희가 미리 작성해둔 메서드입니다.

색상을 설정하기 전에, MainManager.Instance가 null인지를 검사합니다. MainManager는 초기 menu 씬에서 생성될 터인데, 왜 검사해야 하는 걸까요?

글쎄요, 만약 여러분이 테스트를 좀 더 빨리 하고 싶으시다면, Menu 씬을 거치지 않고 에디터 상에서 바로 Main 씬부터 시작하시고 싶으실 겁니다. 이 경우, MainManager는 생성되지 않으며, MainManager.Instance는 null이 될 것입니다. 이 코드는 프로그래머가 메인 메뉴를 건너뛰고 자체적으로 Main 씬을 실행했을 경우에 발생하는 에러를 방지해줌으로써, 테스트를 보다 쉽고 빠르게 진행할 수 있도록 만들어주는 코드입니다.

결과 테스트

유니티 에디터 상에서 테스트를 다시 진행해보세요: 메뉴에서 색상을 선택하기 전에, Main 씬을 시작하고 어떤 일이 일어나는지 확인해보세요!

 


 

9. 다음 단계

이렇게 애플리케이션에서 데이터 지속성을 구현하는 첫 번째 파트인 씬 사이의 데이터 지속성 구현을 완료하였습니다.

다음 튜토리얼에서는 애플리케이션 세션 간의 데이터 지속성을 구현하여 이를 더 확장해보겠습니다.

 


 


수고하셨습니다!


0 Comments