본문 바로가기
유니티/기초

유니티 씬(Scene)과 씬 전환 (Scene Transition)

by 노튜 2020. 11. 1.
728x90

1. 씬 (Scene)

 

경찰, 범죄 등과 관련된 영화나 드라마를 보게 되면, Crime Scene이라는 노란색 테이프로 현장을 막아놓은 장면들이 나온다. 범죄에 사용된 물건, 사물 등이 존재하는 사건 현장이 씬이다. 씬은 캐릭터, 장애물, 벽, 지면 등의 요소들을 포함한다.

 

게임 설계에 따라, 게임은 단일 씬으로 구성되거나, 여러 개의 씬으로 구성될 수 있다. 

각각의 Level을 하나의 Scene에서 구성할 수 있으며, 각각의 레벨에 대응하는 여러 개의 씬으로 구성할 수 있다.

또한, 씬은 씬을 하위 요소처럼 불러와 사용할 수 있다.  

2. 씬 전환 (Scene transition) 

 

유니티는 SceneManager 클래스를 사용해 씬 전환을 제어할 수 있다. 씬 전환을 제어하는 방식은 동기화 방식과 비동기화 방식으로 나눌 수 있다. 동기화 방식은 씬을 호출하는 행동 이외에, 다른 작업을 수행하지 않는다. 비동기화 방식은 씬을 호출하는 동시에 현재 진행 중인 작업을 계속 실행하고, 씬의 호출이 완료되면, 씬을 불러온다.   

씬을 Single과 Addictive 모드로 불러올 수 있다. LoadSceneMode.Single은 현재 씬을 종료하고, 새로운 씬을 로드하는 방법이다. LoadSceneMode.Addictive는 현재 씬 위에 추가적으로 새로운 씬을 불러온다.

2.1 SceneManagement

SceneManager 클래스를 사용하기 위해서는 SceneManagement namespace를 지정해야 한다. 

using UnityEngine.SceneManagement;

namespace는 클래스가 정의된 공간 또는 영역이다. 

클래스가 정의된 공간에 접근하기 위해 "using" 키워드를 사용한다.   

 

2.2 LoadScene

 

SceneManager 클래스의 LoadScene("SceneName")을 사용하여 씬을 불러온다.

씬은 Name(string) 또는 BuildIndex(integer) 값을 이용해 불러올 수 있다.  BuildIndex는 Build Settings의 Index 값이다. 

File  → Build Settings  Scenes in Build

 

 

using UnityEngine;
using UnityEngine.SceneManagement;

public class Example : MonoBehaviour
{
    void CallNextScene()
    {
        // Only specifying the sceneName or sceneBuildIndex will load the Scene with the Single mode
        SceneManager.LoadScene("SceneName");
        
        /*
        * LoadSceneMode.Single  : 모든 씬을 닫고, 새로운 씬을 불러온다. 
        *  
        * LoadSceneMode.Additive : 현재 씬에 추가적으로 씬을 불러온다.
        */
        SceneManager.LoadScene("SceneName", LoadSceneMode.Single); 
        SceneManager.LoadScene("SceneName", LoadSceneMode.Additive);
        
    }
}

 

2.3 LoadSceneAsync()

 

LoadSceneAsynce()는 비동기적으로 Scene을 호출한다.

 

유니티는 씬을 불러올 때, 동기적으로 호출하는 LoadScene() 대신, LoadSceneAsync()를 사용할 것을 권한다. 

LoadScene()은 중지 또는 약간의 지연 등이 발생할 수 있기 때문이다. 

LoadSceneAsync()은 AsyncOperation 클래스를 리턴 값으로 전달한다. AsyncOperation 프로퍼티로 현재 씬의 호출 상태를 알수 있다.

 

아래는 각 프로퍼티에 대한 설명이다.

  • allowSceneActivation : 씬을 활성화 시킨다. 
  • isDone : 씬의 호출이 완료 되었는지를 확인한다. 완료되면 isDone은 true 값을 가진다.
  • progress : 씬의 호출이 얼마나 이루어 졌는지 알려주는 값이다. 0~1.0사이의 값을 가진다. 1.0이 되면, isDone은 True로 값을 가진다.
  • priority : 멀티씬을 로드할 때 씬을 호출하는 순서를 나타낸다. 

이해를 돕기위해, Unity documents의 일부분을 발췌하였다. 

"In most cases, to avoid pauses or performance hiccups while loading, you should use the asynchronous version of this command which is: LoadSceneAsync."

 

using System.Collections;
using UnityEngine;
using UnityEngine.SceneManagement;

public class Example : MonoBehaviour
{
	public string nextSceneName = "NextScene";

    void Update()
    {
        // Space 키 입력
        if (Input.GetKeyDown(KeyCode.Space))
        {
			LoadNextScene();
        }
    }
    
    public void LoadNextScene(){
      // 비동기적으로 Scene을 불러오기 위해 Coroutine을 사용한다.
      StartCoroutine(LoadMyAsyncScene());
    }

    IEnumerator LoadMyAsyncScene()
    {    
    // AsyncOperation을 통해 Scene Load 정도를 알 수 있다.
        AsyncOperation asyncLoad = SceneManager.LoadSceneAsync(nextSceneName);

        // Scene을 불러오는 것이 완료되면, AsyncOperation은 isDone 상태가 된다.
        while (!asyncLoad.isDone)
        {
            yield return null;
        }
    }
}

 

3. 데이터 공유

 

여러 개의 Scene으로 구성된 게임은 Scene들 간의 이동 시 데이터 공유 등이 요구된다. 가령 캐릭터가 A 씬에서 B씬으로 이동할 때, 캐릭터의 HP, MP 등의 데이터를 넘겨주어야 한다. 

 

실제 게임 오브젝트를 넘기는 것이 아닌 데이터를 파일로 저장하고, 새로운 씬이 호출되면, 저장된 값을 불러와 사용하도록 설정한다. 아래의 예제 코드는 PlayerPrefs 컴포넌트를 사용하였다. PlayerPrefs는 각 세션간에 데이터를 저장하고, 접근하도록 구현한 유니티 컴포넌트이다. 

float, int, string 타입을 지원한다.  

using UnityEngine;
using System.Collections;
using UnityEngine.SceneManagement;

public class NextSceneClass : MonoBehaviour
{
    float healthValue;
    int levelValue;
    
    void Start()
    { 
	 LoadData();	      
    }
    
   void LoadData()
    {
      // 불러오기
      healthValue = PlayerPrefs.GetFloat("Health");
      levelValue = PlayerPrefs.GetInt("Level");
    }
}

public class Example : MonoBehaviour
{
	public string nextSceneName = "NextScene";

    float healthValue;
    int levelValue;
    
    void Update()
    {
        // Space 키 입력
        if (Input.GetKeyDown(KeyCode.Space))
        {
			LoadNextScene();
        }
    }
    
    public void LoadNextScene(){    
    // 데이터를 저장
      SaveData();
     
      // 비동기적으로 Scene을 불러오기 위해 Coroutine을 사용한다.
      StartCoroutine(LoadMyAsyncScene());
    }

    IEnumerator LoadMyAsyncScene()
    {    
    // AsyncOperation을 통해 Scene Load 정도를 알 수 있다.
        AsyncOperation asyncLoad = SceneManager.LoadSceneAsync(nextSceneName);

        // Scene을 불러오는 것이 완료되면, AsyncOperation은 isDone 상태가 된다.
        while (!asyncLoad.isDone)
        {
            yield return null;
        }
    }
    
    void SaveData()
    {
      // 저장 
      PlayerPrefs.SetFloat("Health", healthValue);
      PlayerPrefs.SetInt("Level", levelValue);
    }
}

 

 

 

참고자료

 

docs.unity3d.com/ScriptReference/SceneManagement.SceneManager.LoadScene.html

 

Unity - Scripting API: SceneManagement.SceneManager.LoadScene

Note: In most cases, to avoid pauses or performance hiccups while loading, you should use the asynchronous version of this command which is: LoadSceneAsync. When using SceneManager.LoadScene, the scene loads in the next frame, that is it does not load imme

docs.unity3d.com

 

728x90