Unity Scene

선비Sunbei·2023년 1월 23일
0

Unity

목록 보기
12/18
post-thumbnail
post-custom-banner

Scene은 게임의 오브젝트가 포함되어있다. 각 씬에는 환경과 장애물, 장식을 배치하고 게임을 세세하게 디잔인하고자 한다.

우리는 이러한 씬을 코드를 통해서 옮겨다닐라고 한다.

Scene을 변경하는 것은 이미 Unity에서 모두 구현되어있다.
SceneManager (UnityEngine.SceneManagement)을 이용하면 된다.

MethodDescription
GetActiveScene현재 활성화된 씬을 리턴한다.
GetSceneByName이름으로 BuildSettings 창에 표시되는 씬을 찾는다. 이때 .unity 확장자는 없어야 한다.
LoadScene씬을 로드한다. 이때 Build Settings에서 index나 name으로 찾는다.
LoadSceneAsync백그라운드에서 비동기적으로 씬을 로드한다.
MergeScenessource Scene에서 Dest Scene으로 합친다.
MoveGameObjectToScene게임오브젝트를 현재 씬에서 새로운 씬으로 이동시킨다.
SetActiveScene활성화시킬 씬을 선택한다.
UnloadSceneAsync씬에 관련된 모든 게임 오브젝트를 비동기적으로 삭제한다.

위의 메소드는 static 메서드로 일반적으로 호출할 수 있다.

EventsDescription
activeSceneChangedactive scene이 변경될 때 발생하는 이벤트이다.
sceneLoaded로드가 완료됐을 때 호출되는 이벤트이다.
sceneUnloaded언로드가 완료됐을 때 호출되는 이벤트이다.

해당 이벤트 사용법은 delegate로, SceneManager.sceneLoaded += 함수, 와 같이 사용하면 된다.

예로 Scene 1, 2를 만들어보겠다.
각 Scene에 스크립트를 만들겠다.

// Scene1Script
using UnityEngine;
using UnityEngine.SceneManagement;

public class Scene1Script : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        Debug.Log("Load Scene1");
        SceneManager.LoadScene("Scene2");
    }
}
// Scene2Script
using UnityEngine;

public class Scene2Script : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        Debug.Log("Load Scene2");
    }
}

실행시켜보면 에러가 뜰 것이다. 이는 BuildSetting에서 Scene 목록을 선택안해줬기때문이다.

다음과 같이 Scene을 끌어당겨 추가 후 빌드해주면 된다.

그리고 Scene1으로 실행시켜보면 Scene2로 바로 넘어가진다.

이처럼 LoadScene은 바로 로드시켜준다.
하지만 LoadSceneAsync를 응용하면 게임 시작할 때 미리 게임 오브젝트들을 조금씩 갖고오고 원할 때 넘어갈 수 있다.

// Scene1Script.cs
using UnityEngine;
using UnityEngine.SceneManagement;

public class Scene1Script : MonoBehaviour
{
    AsyncOperation asyncOperation;

    // Start is called before the first frame update
    void Start()
    {
        Debug.Log("Load Scene1");
        asyncOperation = SceneManager.LoadSceneAsync("Scene2");
        asyncOperation.allowSceneActivation = false;
        // 장면이 준비된 즉시 장면이 활성화 여부이다.
        SceneManager.sceneLoaded += (Scene scene, LoadSceneMode mode) =>
        {
            Debug.Log($"Finish Loading {scene.name}");
        };
    }

    private void OnDisable()
    {
        asyncOperation.allowSceneActivation = true;
    }
}

실행 시 다음과 같이 되어있다.
이제 스크립트르 갖고있는 오브젝트를 Disable로 만들어보자.

참고로 AsyncOperation.isDone()을 통해서 Load가 완료됐는지 확인할 수 있다.

그렇다면 Scene Manager가 이미 구현되어있는데 왜 만드느냐?
그것은 Scene의 초기세팅과 관련된 부분을 Scene의 스크립트 및 Scene GameObject를 만들어서 코드로 관리하기 위해서이며, Scene Manager로 Load 시에 String으로 넘기는 것에 실수를 방지하기 위해서 enum으로 관리하기 위해서이다.

public class Define 
{
    public enum Scene
    {
        Unknown,
        Scene1,
        Scene2
    }
}

먼저 다음과 같이 Scene과 이름이 똑같은 Enum을 만든다.
그리고 Scene에 관련된 스크립트를 작성하겠다.

// BaseScene.cs
using UnityEngine;

public abstract class BaseScene : MonoBehaviour
{
    public Define.Scene SceneType { get; protected set; } = Define.Scene.Unknown;
    void Awake()
    {
        Init();
    }

    protected virtual void Init()
    {
        // 모든 씬에서 공통적으로 처리해야 하는 것들 코드
        // 예를 들어 UI의 EventSystem같은 것을 씬에 없으면 추가.
    }
    public abstract void Clear();
}
// Scene1.cs
public class Scene1 : BaseScene
{
    protected override void Init()
    {
        base.Init();

        SceneType = Define.Scene.Scene1;

        // Scene1에서 처리할 내용.
    }

    public override void Clear()
    {
        // Scene 종료 시 처리할 내용.
    }
}
// Scene2.cs
public class Scene2 : BaseScene
{
    protected override void Init()
    {
        base.Init();

        SceneType = Define.Scene.Scene2;

        // Scene2에서 처리할 내용.
    }
    public override void Clear()
    {
        // Scene 종료 시 처리할 내용.
    }
}

해당 스크립트는 꼭 Scene에 추가되어있어야 한다.

using UnityEngine;
using UnityEngine.SceneManagement;

public class SceneManagerEX : MonoBehaviour
{
    public BaseScene CurrentScene { get { return GameObject.FindObjectOfType<BaseScene>(); } }
    public void LoadScene(Define.Scene type)
    {
        Clear();
        SceneManager.LoadScene(getSceneName(type));
    }

    public string getSceneName(Define.Scene type)
    {
        return System.Enum.GetName(typeof(Define.Scene), type);
    }

    public void Clear()
    {
        CurrentScene.Clear();
    }
}
post-custom-banner

0개의 댓글