비동기적으로 Scene 전환하기

Tom·2024년 9월 8일
0
post-custom-banner

유니티 프로젝트에서 씬은 필요한 모든 게임 오브젝트들을 담고 있는 컨테이너다. 게임에 필요한 플레이어, 적, 레벨등 외적인 게임 오브젝트 뿐 아니라 UI, 사운드, 물리 등 여러 게임 시스템 또한 씬 단위로 분할해서 관리된다. 새로운 씬을 만드는건 새 프로젝트를 시작하는 기분이다.
그래서 현재 화면에 보이는 씬에서 새로운 씬으로 넘어가는건 많은 연산을 필요로 한다. 배치되어 있는 오브젝트들을 메모리에 올리는 작업이 필요하기 때문이다.
프로젝트의 규모가 크지 않다면 간단히 페이드 아웃 - 페이드 인 되는 효과로도 처리 할 수 있겠지만, 그것보다 긴 시간을 확보해야 한다면 그동안 사람들에게 보여줘야 할 화면이 필요하다. 가만히 멈춰있는 프로그램을 보고 싶어하는 사람은 없으니까.
그래서 보통 게임에선 Scene의 전환이 필요할 때 로드하는 작업은 비동기를 통해 프로그램 뒷편 저 넘어에서 진행하고, 화면엔 로딩창이라는걸 띄워준다.

유니티엔 이런 비동기 작업을 도와주는 AsyncOperation이라는 클래스가 있다. 씬뿐만 아니라 리소스, 에셋 불러오기등 비동기 작업이 필요한 경우에 사용할 수 있다. 사용법도 굉장히 간단함.

using UnityEngine;
using UnityEngine.SceneManagement;

class AsyncTest : MonoBehaviour 
{
    public void LoadSceneSync()
    {
        SceneManager.LoadScene("NextScene");
    }

    public void LoadSceneAsync()
    {
        SceneManager.LoadSceneAsync("NextScene");
    }
}

요 두개의 메서드는 같은 동작을 한다. 이름이 NextScene인 씬을 찾아 그 씬으로 넘어가주는 것. 근데 위에껀 비동기적으로 작업하고 아래껀 동기적으로 작업한다는 차이가 있다.
LoadSceneAsync는 현재 진행중인 작업을 AsyncOperation에 담아 반환한다. AsyncOperation에 내장된 기능과 코루틴을 통해 간단하게 씬을 로드하는 동안 작업 진행 상황을 보여주는 로딩바를 만들 수 있음.

using UnityEngine;
using UnityEngine.SceneManagement;

public class AsyncTest : MonoBehaviour 
{
    AsyncOperation asyncOperation;

    public void LoadSceneAsync()
    {
        asyncOperation = SceneManager.LoadSceneAsync("NextScene");

        asyncOperation.allowSceneActivation = true; // 작업이 왼료되고 씬을 전환할 것인지
        bool isDone = asyncOperation.isDone; // 작업이 끝났나요?
        asyncOperation.priority = 0; // 작업 우선순위도 설정할 수 있다.
        float progress = asyncOperation.progress; // 작업이 얼마나 진행되었나용?
    }
}

요것들과 유니티 UI의 슬라이더를 활용해 비동기적으로 작동하고 전환 진행상황을 알려주는 로딩 화면을 만들 수 있다!

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

public class SceneLoad : MonoBehaviour 
{
    private AsyncOperation asyncOperation;
    private Slider loadingBar;

    public void LoadScene(string sceneName) // 가고싶은 씬 이름을 말하세요 
    {
        StartCoroutine(LoadSceneAsync(sceneName));
    }

    private IEnumerator LoadSceneAsync(string SceneName)
    {
        // ~~ 대충 로딩 화면 켜주는 코드 ~~
        
        asyncOperation = SceneManager.LoadSceneAsync(SceneName); // 비동기로 씬 로딩을 시작한다
        asyncOperation.allowSceneActivation = false; // 다 되도 전환하지 말아주십쇼

        while (!asyncOperation.isDone)
        {
            // progress는 0.0 ~ 0.9 사이의 값을 반환한다 (마지막 0.1은 전환될 때 처리한다고 함)
            if (asyncOperation.progress < 0.9f)
            {
                loadingBar.value = asyncOperation.progress;
            }
            else 
            {
                loadingBar.value = 1; // 0.9가 넘으면 그냥 1로 바꿔버리고 씬을 로드한다
                asyncOperation.allowSceneActivation = true; // 이제 씬을 켜셔도 됩니다
            }

            yield return null;
        }
    }
}

씬의 규모가 작은 경우에는 로딩 화면이 슉슉 있는지도 모르게 지나가는 일이 생길 수도 있다. 그래서 유저의 경험 개선을 위해 일부러 슬라이더를 늦게 채운다거나, progress와 상관없이 일부러 일정한 시간을 지연시키는 등의 방법으로 자연스러운 로딩 화면을 만드는 경우가 많다고 한다.
로딩이 끝나면 바로바로 전환 시켜줄 것이지.

profile
여기 글은 보통 틀린 경우가 많음
post-custom-banner

0개의 댓글