유니티 LoadScene vs LoadSceneAsync

유니티에는 씬을 불러오는 두 가지 방법이 있습니다. 

 

동기 방식 - LoadScene 

LoadScene (동기 방식): LoadScene은 동기 방식으로, 씬을 불러오는 동안 다른 작업을 수행하지 못합니다. 즉, 씬의 모든 데이터를 메모리로 가져오기 전까지 다른 작업이 중지됩니다. 불러오려는 씬의 규모가 크다면, 게임이 멈춰있는 상황이 더 지속될 수 있습니다.

 

씬의 크기가 작은 경우 LoadScene  방식을 사용하면 됩니다.

 

using UnityEngine;
using UnityEngine.SceneManagement;

public class Example : MonoBehaviour
{
    public void LoadSceneExample()
    {
        SceneManager.LoadScene("SceneName");
    }
}

비동기 방식 - LoadSceneAsync 

LoadSceneAsync (비동기 방식): LoadSceneAsync는 비동기 방식으로, 씬을 불러오는 동안 다른 작업을 계속 수행할 수 있습니다.LoadSceneAsync 방식은 주로 코루틴을 사용하여 씬을 비동기적으로 불러옵니다.

 

LoadSceneAsync 방식에는 AsyncOperation 객체가 존재하여 비동기 작업의 상태를 추적할 수 있습니다.

프로퍼티 설명
allowSceneActivation 이 프로퍼티는 씬이 준비되는 즉시 활성화될 것인지를 제어합니다. 기본값은 true이며, 이 경우 씬이 준비되는 즉시 활성화됩니다. false로 설정하면, 씬이 준비되더라도 활성화되지 않습니다. 
isDone 이 프로퍼티는 비동기 작업이 완료되었는지를 나타냅니다. true이면 작업이 완료되었음을 의미하며, false이면 작업이 아직 완료되지 않았음을 의미합니다.
progress 이 프로퍼티는 비동기 작업의 진행 상황을 나타냅니다. 0.0에서 1.0 사이의 값을 가지며, 1.0은 작업이 완료되었음을 의미합니다. 이 값을 사용하여 로딩 바를 구현할 수 있습니다.
 
씬의 크기가 큰 경우 LoadSceneAsync  방식을 사용하면 됩니다.
using UnityEngine.SceneManagement;

IEnumerator LoadSceneAsync(string sceneName)
{
    AsyncOperation asyncOper = SceneManager.LoadSceneAsync(sceneName);
    while (!asyncOper.isDone)
    {
        yield return null;
    }
}
 

예시 코드 - 세팅

LoadSceneAsync방식을 이용한 코드를 만들어보았습니다.

Canvas

세팅은 위 사진 처럼 해주시면 됩니다.

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

public enum SceneName
{
    MainMenu = 0,
    MainGame,
}

public class SceneController : MonoBehaviour
{
    public static SceneController Instance;

    [SerializeField] private GameObject sceneLoadingPanel;
    [SerializeField] private Image progressImage;
    [SerializeField] private TextMeshProUGUI progressText;
    [SerializeField] private float delay = 0.5f;

    [SerializeField] private SceneName currentScene;
    [SerializeField] private SceneName nextScene;
    
    private void Awake()
    {
        Instance = this;
        DontDestroyOnLoad(gameObject);
    }

    [ContextMenu("Test")]
    public void Test()
    {
        LoadScene(nextScene);
    }
    
    private void OnGUI()
    {
        if (GUI.Button(new Rect(50, 10, 150, 50), "LoadScene"))
        {
            LoadScene(nextScene);
        }
    }

    public void ReloadScene()
    {
        sceneLoadingPanel.SetActive(true);
        StartCoroutine(LoadSceneAsync(currentScene));
    }
    
    public void LoadScene()
    {
        sceneLoadingPanel.SetActive(true);
        StartCoroutine(LoadSceneAsync(nextScene));
    }
    
    public void LoadScene(SceneName sceneName)
    {
        sceneLoadingPanel.SetActive(true);
        StartCoroutine(LoadSceneAsync(sceneName));
    }
    
    private IEnumerator LoadSceneAsync(SceneName sceneName)
    {
        currentScene = sceneName;
        AsyncOperation asyncOper = SceneManager.LoadSceneAsync((int)sceneName);
        asyncOper.allowSceneActivation = false;

        float progress = 0f;
    
        while (!asyncOper.isDone)
        {
            progress = Mathf.Lerp(progress, asyncOper.progress, 0.95f);
            progressImage.fillAmount = progress;
            progressText.text = Mathf.RoundToInt(progress * 100) + "%";

            if (asyncOper.progress >= 0.9f)
            {
                yield return new WaitForSeconds(delay);
                sceneLoadingPanel.SetActive(false);
                asyncOper.allowSceneActivation = true;
            }
            yield return null;
        }
    }
}

 

using UnityEngine;

public class NextSceneTest : MonoBehaviour
{
    public void Test()
    {
        SceneController.Instance.LoadScene(SceneName.MainGame);
    }
}