본문 바로가기
스파르타 내배캠

스파르타 내배캠 Unity 3기 38일차

by LemongO 2024. 2. 18.

35시간 무수면의 최후

 

 

다신 밤샘 작업은 하지 말아야지...

 

 


SceneManagerEx

 

동적 생성을 하기위해 꼭 필요한 것이 하나 있다면

그건바로 씬을 이동할 때 해당 씬 초기에 필요한 것 들을 불러주는 오브젝트 라고 할 수 있다.

 

A 씬에서 필요한 것들이 B 씬에선 필요가 없을 수도 있고 전혀 다른 오브젝트들을 소환할 수 있다.

 

이를 위해서 

 

씬을 관리할 SceneManagerEx와 해당씬에 대한 정보를 가진 BaseScene 클래스가 필요하다.

 

어차피 유니티에서 자체적으로 SceneManager를 지원하고 씬을 전환할 수 있는데 왜 굳이 씬 매니저를 만드는가 싶지만

그 부분을 지금부터 알아보자.

 

 

 

먼저 앞서 말했듯 필요한 다른 것들을 불러주기위한 선발대 오브젝트가 필요하다.

그 역할을 @Scene 오브젝튿가 담당한다

 

해당 오브젝트는 BaseScene을 상속받은 각각의 자신의 씬 클래스를 가지고 있는데 현재 씬이 Title 이니 

TitleScene 컴포넌트를 가지고있다.

 

그럼 이제 SceneManagerEx 를 보도록 하자.

 

public class SceneManagerEx
{
    public BaseScene CurrentScene => UnityEngine.Object.FindObjectOfType<BaseScene>();    

    public void LoadScene(Define.Scenes scene)
    {
        Managers.Clear();

        SceneManager.LoadScene(GetSceneName(scene));
    }

    private string GetSceneName(Define.Scenes scene)
    {
        string sceneName = System.Enum.GetName(typeof(Define.Scenes), scene);
        return sceneName;
    }    

    public void Clear()
    {
        CurrentScene.Clear();        
    }
}

 

씬 매니저의 전체 코드이다. 

 

코드 내용을 살펴 보면 먼저 현재 씬이 어떤 씬인지 알 수 있는 CurrentScene get 프로퍼티가 있다.

현재 씬에 있는 BaseScene 을 찾아 현재 씬이 무엇인지 확인하는 구조이다.

 

그리고 실제 씬을 로드하는 Define.Scenes enum을 매개변수로 받는 LoadScene 함수가 있다.

public enum Scenes
{
    None,
    Title,
    Main,
    Dungeon,
    Ending,
}

 

enum Scenes 에는 실제 사용될 씬이 들어있다.

예전 UI 자동화 때 썻던 방식과 비슷하게 실제 씬과 같은 이름이어야한다.

 

 

그 이유는 LoadScene을 하는 로직을 보면

유니티가 지원하는 SceneManager.LoadScene 에 씬 이름(string) 을 넘겨주는 부분에 Enum.GetName을 이용하기 때문.

이렇게 하면 하드코딩을 하지 않고 enum 값만 넘겨주면 된다.

 

그리고 Clear 함수를 이용하여 실제 현재 씬이 넘어갈 때 호출할 것 들을 적어주면 되는데

이번 프로젝트에선 Managers에 다른 모든 Manager들의 Clear를 넣어주고

씬이 넘어가는 LoadScene에서 호출하는 것으로 만들었다.

Managers.Clear();

 

LoadScene을 할 때 Managers.Clear 를 호출하는데 이 때 SceneManager의 Clear도 같이 호출이 된다.

 

 

그럼이제 Base 씬을 살펴 보도록 하자.

 

public class BaseScene : MonoBehaviour
{
    public Define.Scenes SceneType { get; protected set; }

    private void Awake()
    {
        Init();
    }

    protected virtual void Init()
    {
        EventSystem eventSys = FindObjectOfType<EventSystem>();
        if (eventSys == null)
            Managers.RM.Instantiate("UI/@EventSystem");
    }

    public virtual void Clear() { }
}

 

자신의 씬을 나타내는 SceneType 프로퍼티와

 

씬이 시작될 때 실행되는 Init 함수가 있다.

Init 에선 현재 씬에 EventSystem이 있는지 확인하여 없으면 미리 프리팹화 시켜둔 EventSystem을 생성한다.

 

또한 Init은 virtual 로 만들어 BaseScene을 상속받는 Scene들이 자신의 씬이 무엇인지 프로퍼티 set을 하고,

씬에서 필요한 것들을 호출하는 형태로 작성이 가능하다.

 

public class TitleScene : BaseScene
{
    protected override void Init()
    {
        base.Init();

        SceneType = Define.Scenes.Title;

        Managers.Player.Init();
        Managers.Attack.Init();
        Managers.Pool.Init();

        Managers.UI.ShowSceneUI<UI_Title>();
    }
}

 

이런식으로 말이다.