Unity/Tips

Unity Scene 전환 간단히

최애뎡 2022. 7. 31. 16:21
728x90
반응형

https://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

씬 전환을 위해 사용하는 LoadScene의 내용

* 알아둬야 할 내용은

요 두 부분 정도 언데 Async를 사용해야 하는지랑 이건 몰랐던 것인데 Resources.UnloadUnusedAssets();가 자동 호출이 되는 것... 헐....(*이지만 사실 그리 중요한 건 아니구..)

Resources.UnloadUnusedAssets();의 내용은 

https://docs.unity3d.com/ScriptReference/Resources.UnloadUnusedAssets.html

 

Unity - Scripting API: Resources.UnloadUnusedAssets

An asset is deemed to be unused if it isn't reached after walking the whole game object hierarchy, including script components. Static variables are also examined. The script execution stack, however, is not examined so an asset referenced only from within

docs.unity3d.com

를 참고하면 됨 (* Resources.UnloadUnusedAssets()의 경우는 꼭 씬 전환시에만 사용할 게 아니라 간혹 메모리를 정리해야 할 상황이 올 수 있는데 이때도 사용한다.)

 

어쨌든 여기서 씬 전환이 Unity에서 내부적으로 어떻게 돌아가는지를 꼭 알아야 한다.

예로 a, b씬이 있다 가정할 때 a씬에서 b씬으로 전환할 때 Unity에서 메모리 처리 과정은

이미 a씬에 대한 메모리가 올라가 있을 것이고 b씬이 로드되게 되는데 이때 a씬의 메모리를 내리고 b씬이 로드되면서 메모리가 올라오는 것이 아니라 a씬의 메모리가 올라와 있는 상태에서 b씬의 메모리가 같이 올라오고 그 뒤에 b씬의 로드가 끝나면 a씬을 제거하면서 a씬이 할당하고 있던 메모리가 내려가게 된다.

그렇기에 각 씬이 차지하는 메모리가 많을 경우 혹은 동시에 씬이 올라왔을 때 순간 메모리가 많아지는 경우를 대비하여 씬 전환 시 빈 씬이나 혹은 로드 씬을 사용하는 것이다.

즉, 빈 씬인 n이 있고 a씬에서 b씬으로 로드한다 가정하면

a(now) -> n(load) -> a(remove) -> b(load) -> n(remove)의 느낌으로 가는 게 메모리 측면에서 과부하를 대비할 수 있다.

 

본인의 경우

요런 식으로 중간에 거쳐가는 씬을 하나 두고 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

using TMPro;

public class NextScene : MonoBehaviour
{
    [SerializeField] TMP_Text _TMP_progress = null;

    private void Start()
    {
        AD.Managers.SceneM.GoScene();
    }

    private void Update()
    {
        this._TMP_progress.text = $"{AD.Managers.SceneM.Progress * 100}%";
    }
}

이렇게 NextScene의 로드가 끝난 뒤에 SceneM의 GoScene메서드를 통해 씬 전환을 하는데 SceneM의 경우

using System.Collections;

using UnityEngine;

namespace AD
{
    public class SceneManager : MonoBehaviour
    {
        AD.Define.Scenes _scene;
        Coroutine _co_GoScene = null;

        float progress = 0f;
        public float Progress { get { return progress; } } 

        public void NextScene(AD.Define.Scenes scene)
        {
            this._scene = scene;
            UnityEngine.SceneManagement.SceneManager.LoadScene(AD.Define.Scenes.NextScene.ToString());
        }

        public void GoScene()
        {
            _co_GoScene = StartCoroutine(Co_GoScene());
        }

        IEnumerator Co_GoScene()
        {
            AsyncOperation ao = UnityEngine.SceneManagement.SceneManager.LoadSceneAsync(this._scene.ToString());

            while (!ao.isDone)
            {
                AD.Debug.Log("SceneManager", $"{ao.progress} - progress");
                this.progress = ao.progress;
                yield return null;
            }

            if (_co_GoScene != null)
            {
                StopCoroutine(_co_GoScene);
                _co_GoScene = null;

                Resources.UnloadUnusedAssets();
            }
        }
    }
}

이런 식으로 가고 싶은 씬을 받아둔 뒤 NextScene에서 GoScene()을 호출하여 전환하는 식으로 진행한다.

Load가 얼마나 됐는지를 확인하기 위해 코드를 이렇게 하고 있긴 한데 이러면 Async의 의미가 없는 것 같기에... 음 지금 보니 개선이 필요.. 하다....

반응형