본문 바로가기
Unity/Advanced

유니티 프로젝트 씬 구성 (Project structure with Scenes)

by 노튜 2025. 2. 27.
728x90
반응형

 

1. 단일 씬과 다수 씬 (Single Scene and Multiple Scenes)

씬(Scene)은 유니티 프로젝트를 구성하는 기본적인 단위이다. 씬은 다양한 오브젝트 및 컴포넌트들을 구성하며, 씬과 씬의 이동을 통해 게임이나 앱은 실행된다. 게임이나 앱은 단일 씬이나 여러 씬들로 구성될 수 있다. 단일 씬은 게임이나 앱의 규모가 커질수록 메모리 사용량이 증가하여, 성능이 하락하게 된다. 또한, 단일 씬은 관리해야 하는 오브젝트들이 증가하게 되어 씬이 복잡해질 우려가 있다.

그래서 일반적으로 여러 씬으로 나누어 프로젝트를 설계한다. 여러 개의 씬으로 구성되면 불편하게 느껴질 수 있다. 씬과 씬 간의 데이터를 공유하기 위한 방법들을 추가적으로 구현해야 하며, 오브젝트들의 배치가 여러 씬에 분산되기 때문에 어떤 오브젝트들이 배치되어 있는지 확인하기 어려울 수 있다. 하지만 유니티는 여러 씬을 한 번에 올려 씬을 수정할 수 있는 방법을 제공하고 있으며, 데이터를 공유하기 위한 다양한 방법들 역시 존재한다.

다수 씬을 사용한 설계는 각각의 씬에 필요한 오브젝트와 컴포넌트들만 배치되기 때문에 메모리 사용량 감소, 연산 시간이 감소하게 된다. 이는 곧 자원의 사용량이 줄어들어 성능이 향상되게 된다. 

 

2 다수 씬 구성

다수 씬으로 구성하기 위해서는 설계 단계에서 각각의 씬의 역할에 대하여 정의할 필요가 있다. 서버 연결, 데이터의 로드등의 기능적 측면과 레벨, 마을, 던전 및 필드와 같은 물리적 측면으로 나누어 씬을 구성한다. 씬을 역할 별로 구분하면 시작, 전환, 대기실, 레벨로 구분할 수 있다.    

 

※ 본 글에서는 오브젝트 배치, 몬스터 소환 기능과 같은 씬을 어떻게 구성하는지에 대해서는 언급하지 않는다. 겜이나 앱의 개발 방향, 개발자의 역량, 레벨 디자인 등에 따라 달라질 수 있기 때문이다.  

 

반응형

2.1. 시작 씬(Entry Scene)

시작 씬은 처음 호출되는 씬으로 데이터의 다운로드, 서버 접속 등과 같은 기능을 담당한다. 사용자에게는 시작 메뉴, 로그인 기능 등을 제공한다. 시작 씬은 씬과 씬 간에 데이터를 공유하기 위해 필요한 요소들을 미리 로드하여, 파괴되지 않도록 한다. 

 

Entry Scene and DontDestroyOnLoad

 

 

2.2. 전환 씬(Transition Scene)

전환 씬은 씬과 씬 사이에 호출되는 씬으로 다음 씬이 로딩되는 상태를 보여준다. 씬의 전환은 씬과 씬이 동시에 존재한다는 의미이다. A 씬은 여전히 메모리 상에 존재하며, B 씬은 불러오는 중이므로 메모리에 로드되고 있는 상태이다. 데이터를 불러오고 데이터를 삭제하는 중이기 때문에 많은 자원을 소모하게 된다. 이때 가벼운 중간 씬을 두어서 한 번에 많은 자원을 소모하지 않도록 하여 성능을 향상시킬 수 있다. 전환 씬은 다음 씬이 무겁다면 불러오는데 시간이 걸리기 때문에, 이미지 등을 표시하여 사용자에게 간단한 정보를 제공하여 지루하지 않도록 하는 기능을 구현한다.   

 

Transition Scene

 

2.3. 대기실 씬 (Lobby Scene)

대기실은 플레이어의 상태 정보 제공 및 상태 변경, 레벨 정보 또는 진입 기능 제공 등의 역할을 한다. 예를 들어 인벤토리 시스템, 레벨 선택 시스템, 캐릭터 선택 시스템 등이 있다. 마을, 집 등으로 디자인하는 경우도 있으며, 게임 설계에 따라 구현하지 않는 경우도 있다.

Lobby Scene

 

2.4. 레벨 씬 (Level Scene)

레벨 씬은 하나만 구성할 수도 있으며, 여러 개로 구성할 수도 있다. 예를 들어 레벨은 스테이지일 경우이다. 동일한 기능을 사용한다면, 여러 개를 만들 필요가 없으므로 레벨의 환경만 변경을 하거나 캐릭터의 소환 장소만 변경해 줄 수 있다. 레벨은 던전, 사냥터, 스테이지등으로 표현되며, 레벨 디자인은 환경, 장애물, 난이도 등을 포함하는 포괄적인 의미로 사용된다.  

Level Scene

 

728x90

 

3. 씬의 전환 과정

씬의 전환은 전환 씬을 거쳐서 이루어진다.

 

시작 씬 → 전환 씬 → 대기실 씬 ↔ 전환 씬 ↔ 레벨 씬 A

                                   대기실 씬 ↔ 전환 씬 ↔ 레벨 씬 B

                                   대기실 씬 ↔ 전환 씬 ↔ 레벨 씬 C    

                                                        ...

 

Build Settings Scenes

3.1  전환 씬 - TransitionManager

씬과 씬 간의 호출이 발생하면 호출된다. 호출 대상이 되는 씬을 호출하는 역할을 한다. PlayerPrefs 클래스를 사용하여 호출해야하는 대상의 씬 이름을 받아온다. 이미지 컴포넌트를 통해 현재 진행중인 상태를 보여준다.

 

Image filled

 

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

public class TransitionSceneManager : MonoBehaviour
{
   const string nextSceneNameKey = "NextKey";
   public Image progressImage;
   
   // Start is called the first frame update
   void Start()
   {
      LoadNextScene();
   }
   
   void LoadNextScene()
   {
      StartCoroutine(LoadScene());      
   }
   
   IEnumerator LoadScene()
   {
      yield return new WaitForSeconds(1.0f);
      
      if(PlayerPrefs.HasKey(nextSceneNameKey) == false)
      {
         Debug.LogError("NextSceneNameKey does not exist.");
      }
      
      string nextSceneName = PlayerPrefs.GetString(nextSceneNameKey);
      AsyncOperation asyncOperation = SceneManager.LoadSceneAsync(nextSceneName);
      
      while (!asyncOperation.isDone)
      {
         progressImage.fillAmount = asyncOperation.progress / 0.9f;
         yield return null;
      }   
   }  
}

 

Transition ScenManager

 

3.2. 시작(Entry Scene), 대기실 (Lobby Scene), 레벨 (Level Scene)

3.2.1 MySceneManager 

각 씬들에 배치되어, 다음 호출 대상이 되는 씬의 이름을 PlayerPrefs 클래스를 사용해 저장하고, 전환 씬(Transition Scene)을 호출하는 역할을 한다.

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

public class MySceneManager : MonoBehaviour
{
   const string nextSceneName = "NextKey";
   const string transitionSceneName = "Scene Transition";
  
   public void LoadNextScene(string _nextSceneName)
   {
      PlayerPrefs.SetString(nextSceneNameKey, _nextSceneName);
      StartCoroutine(LoadScene());
   }
  
   IEnumerator LoadScene()
   {
      AsyncOperation asyncOperation = SceneManager.LoadSceneAsync(transitionScenName);
    
      while (!asyncOperation.isDone)
      {
         yield return null;
      }
   }
}

 

MySceneManager

                 

3.2.2  BaseSceneManager

전환 씬을 제외한 씬들의 매니저의 기본 클래스이다. 씬의 이름을 사용하여, 다음 호출이 되는 씬의 이름을 변수로 가지고 있다. 씬의 전환이 이루어지기 전에 FadeOut 애니메이션을 진행하여 화면에 더 이상 이벤트가 발생하지 않도록 하며, MySceneManager에 씬의 전환을 요청한다. 

 

using System.Collections;
using UnityEngine;
using UnityEngine.UI;

public class BaseSceneManager : MonoBehaviour
{
   public string[] NextSceneName;
   public MySceneManager mySceneManager;
   public GraphicRaycaster graphicRaycaster;
   public Image image;
   Color baseColor;
   WaitForEndOfFrame waitForEndOfFrame = new WaitForEndOfFrame();
   // Awake is called
   void Awake()
   {
      baseColor = image.color;
      image.enabled = false;
      graphicRaycaster.enabled = false;
   }
   
   protected void LoadScene(int _sceneIndex)
   {
      StartCoroutine(WaitTimes(_sceneIndex));
   }
   
   IEnumerator WaitTimes(int _sceneIndex)
   {
      yield return FadeOutAnimation();
      yield return new WaitForSeconeds(1.0f);
      mySceneManager.LoadNextScene(nextSceneName[_sceneIndex]);
   }
   
   IEnumerator FadeOutAnimation()
   {
      graphicRaycaster.enabled = true;
      float alphaValue = 0.0f;
      image.color = new Color(baseColor.r, baseColor.g, baseColor.b, alphaValue);
      image.enabled = true;
      
      while (1.0f > alphaValue)
      {
        yield return waitForEndOfFrame;
        value += Time.deltaTime;
        image.color = new Color(baseColor.r, baseColor.g, baseColor.b, alphaValue);
      }
      yield return new WaitForSecondsReatime(0.5f);
      graphicRaycaster.enabled = false;
   }
}

 

Canvas를 생성하고 SortOrder를 다른 Canvas보다 높게 설정한다. 예를 들어 Canvas Main의 Sort Order의 값이 0이라면, Canvas의 Sort Order의 값을 1로 설정한다. 

Canvas FadeOut

 

Canvas FadeOut Image

 

3.2.3 EntrySceneManager

EntryScenManager는 BaseSceneManager를 상속받아 구현된다. 플레이어가 버튼을 클릭하면 Lobby Scene을 호출하도록 한다.

 

public class EntrySceneManager : BaseSceneManager
{
  public void OnButtonClicked()
  {
     LoadScene(0);
  }
}

 

EntrySceneManager

 

Canvas Button OnClick

 

GameManager 

GameManager는 EntryScene이 실행되면 함께 실행된다. GameManager는 데이터를 불러오고 저장한다. 모든 씬에서 데이터를 공유하도록 DontDestoryOnLoad를 사용해 파괴되지 않도록 하고, 정적 변수를 생성하여 접근할 수 있도록 한다.

using UnityEngine;

public class GameManager : MonoBehaviour
{
   public static GameManager Instance;
   SaveLoadSystem saveLoadSystem;
   
   // Awake is called
   void Awake()
   {
      if(Instance != null)
      {
         return;
      }
      Instance = this;
      DontDestroyOnLoad(this);
      
      LoadData();
   }
   
   void LoadData()
   {
      saveLoadSystem = new SaveLoadSystem();
      saveLoadSystem.Load();     
   }
   
   public SaveLoadSystem GetSaveLoadSystem()
   {
      return saveLoadSystem;
   }
   
   void OnApplicationPause(bool pauseStatus)
   {
      if(pauseStatus)
      {
         saveLoadSystem.Save();
      }
   }
   
   void OnApplicationQuit()
   {
#if UNITY_EDITOR
       saveLoadSystem.Save();
#endif
   }
}

// Save and Load data

public class SaveLoadSystem
{
   /*
    * Date
    */
    
   public void Load()
   {

   }
   
   public void Save()
   {
      
   }
}

 

Entry Scene GameManager

 

 

3.2.4 LobbySceneManager

LobbyScenManager는 BaseSceneManager를 상속받아 구현된다

public class LobbySceneManage : BaseSceneManager
{
   public void LoadLevel()
   {
      LoadScene(0);
   }
}

 

LobbySceneManager

 

3.2.5 LevelSceneManager

LevelSceneManager는 BaseSceneManager를 상속받아 구현된다. EndLevel 함수가 호출되어 Lobby Scene을 호출하도록 한다.

public class LevelSceneManager : BaseSceneManager
{
   public void EndLevel()
   {
      LoadScene(0);
   }
}

 

Level SceneManager

 

4 데이터의 공유 

씬과 씬은 공간이 다르다. 그래서 일반적으로 씬과 씬은 데이터를 공유하지 않는다. 그러나 데이터를 공유하는 방법은 있다. DontDestoryOnLoad를 사용하여 오브젝트를 파괴하지 않고, 유지시켜 다른 씬에서 접속이 가능하게 하거나, 데이터를 파일로 저장하여 데이터를 다른 씬에서 로드하여 사용하는 방법 등을 들 수 있다.

 

이와 관련된 기능은 본인이 작성한 아래의 글에서 다룬다. 

Unity Basic  - 유니티 DontDestoryOnLoad,  PlayerPrefs

Unity Advanced - Json 파일 저장 및 불러오기

 

 

728x90
반응형