[Skill] 로딩 화면 구현하기 (UI 방식)



전에 썼던 글과는 다르게 이번에는 로딩 화면을 구현하는데 UI를 써보도록하고 싱글톤 패턴까지 적용해보겠다.

image

우선 canvas 오브젝트를 만들고 LoadingUI로 이름을 바꾼 뒤 Canvas Group 컴포넌트를 추가하자.

Canvas Group 컴포넌트에 프로퍼티 중 Alpha는 LoadingUI의 하위 오브젝트의 알파값까지 영향을 준다.

그리고 로딩바 이미지와, 로딩바 프레임 이미지를 만들어주고 아래의 스크립트를 작성하자.

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

public class LoadingSceneController : MonoBehaviour
{
    //기존 씬을 UI로 가리고 다음 씬을 불러오는 역할
    //싱글톤패턴으로 구현하여 하나뿐인 로딩 UI를 어디서든지 호출할 수 있게 만듬
    private static LoadingSceneController instance;
    public static LoadingSceneController Instance
    {
        get
        {
            if (instance == null)
            {
                var obj=FindObjectOfType<LoadingSceneController>();
                if(obj != null)
                {
                    instance = obj;
                }
                else
                {
                    //새로운 인스턴스를 만들 때 미리 만들어둔 배경UI이나 로딩바의 셋팅이 있어야하므로
                    //리소스폴더에 있는 UI들을 인스턴화 한다.
                    instance = Create();
                }
            }
            return instance;
        }
    }
    private static LoadingSceneController Create()
    {
        //Resources폴더에서 LoadingSceneController타입의 LoadingUI를 불러옴
        return Instantiate(Resources.Load<LoadingSceneController>("LoadingUI"));
    }

    private void Awake()
    {
        if(instance != this)
        {
            Destroy(gameObject);
            return;
        }
        DontDestroyOnLoad(gameObject);
    }

    [SerializeField]
    private CanvasGroup CanvasGroup; //로딩 UI에서 사용됨

    [SerializeField]
    private Image progressBar;

    private string loadSceneName;

    public void LoadScene(string sceneName)
    {
        //비활성화 되어있던 LoadingSceneController오브젝트를 활성화 시키고
        //씬을 로딩하는 과정 처리
        gameObject.SetActive(true);

        //씬의 로딩이 끝나는 시점을 알려줌( SceneManager.sceneLoaded)
        SceneManager.sceneLoaded += OnSceneLoaded;
        loadSceneName = sceneName;
        StartCoroutine(LoadSceneProcess()); //씬을 로딩하는 과정을 처리함
    }

    private IEnumerator LoadSceneProcess()
    {
        progressBar.fillAmount = 0;
        //yield return 뒤에 StartCoroutine이 있으면 StartCoroutine으로 호출한 코루틴이 종료될 때 까지 멈춤
        yield return StartCoroutine(Fade(true));//FadeIn으로 자연스러움 연출

        //FadeIn이 끝나면 비동기로 씬을 불러오기 시작
        AsyncOperation op = SceneManager.LoadSceneAsync(loadSceneName);
        op.allowSceneActivation = false;//씬의 로딩이 끝나도 자동으로 넘어가지 않음

        float timer = 0f;
        while (!op.isDone)
        {
            yield return null;
            if (op.progress < 0.9f)
            {
                progressBar.fillAmount=op.progress;
            }
            else
            {
                timer += Time.unscaledDeltaTime;
                progressBar.fillAmount = Mathf.Lerp(0.9f,1.0f,timer);
                if (progressBar.fillAmount >= 1.0f)
                {
                    op.allowSceneActivation = true;
                    yield break;
                }
            }
        }
    }

    private void OnSceneLoaded(Scene arg0, LoadSceneMode arg1)
    {
        //매개변수 Scene을 통해 어떤 씬이 로딩 되었는지 알 수 있음
        //씬의 로딩이 끝나면 유니티 엔진이  SceneManager.sceneLoaded에 등록해둔
        //OnSceneLoaded를 자동으로 호출해서 씬로딩이 끝난 시점을 우리에게 알려준다.
        if (arg0.name == loadSceneName)
        {
            //불러오고자 하는 씬이 모두 불려와 진 것
            StartCoroutine(Fade(false));
            SceneManager.sceneLoaded -= OnSceneLoaded;
        }
    }

    private IEnumerator Fade(bool isFadeIn)
    {
        float timer = 0f;
        while (timer <= 1f)
        {
            yield return null;
            timer += Time.unscaledDeltaTime*3f;
            CanvasGroup.alpha = isFadeIn ? Mathf.Lerp(0f, 1f, timer) : Mathf.Lerp(1f, 0f, timer);
        }
        if (!isFadeIn)
        {
            gameObject.SetActive(false);
        }
    }
}

코드가 상당히 길다. 하지만 이해하기 어려운 부분은 그다지 없다. 설명 또한 코드에 바로 적어두었다.

그나마 바로 해석하기 어려운 것은 SceneManager.sceneLoaded += OnSceneLoaded; 이 부분이다. 처음 봤을 때 저게 뭐지 했다가 이벤트라는걸 알고 c#에 이벤트 체인이 떠올랐다. 그리고 마지막으로 유니티에서는 Resoueces폴더를 만들면 런타임중에 Resources폴더안에 있는 에셋을 불러올 수 있게 만들어 놨다.

예시로는 Resources.Load<LoadingSceneController(“LoadingUI”)이 있다.

직역하면 리소스폴더에서 불러와라 LoadingSceneController타입의 LoadingUI를 이런식으로 해석이 가능하다.




© 2022. by KSC

Powered by sora