유니티의 로딩 화면을 제작 중에 로딩 진행률을 나타내는 코드를 구현해봤다. 유니티 UI - Slider를 이용하여 현재 로딩 진행률을 시각적으로 표현하려고 했다.
구현하고자 했던 목표는 다음과 같다.
using System.Collections;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
public class NextSceneManager : MonoBehaviour
{
[SerializeField]
private GameObject pannelLoading; // 로딩 화면 대신 패널을 이용했다
[SerializeField]
private Slider sliderProgress; // 로딩 상태를 나타낼 슬라이더
[SerializeField]
private float loadingDelayTime; // 다음 씬 전환까지 지연을 위한 시간
private float currentTick;
private float moveTick;
private void Start()
{
currentTick = 0f;
moveTick = 0.0003f;
}
public void StartLoadingCoroutine(string sceneName)
{
// 코루틴을 호출한다
StartCoroutine(LoadingProgress(sceneName));
}
// 로딩 작업 완료 후 다음 씬으로 이동하는 코루틴
public IEnumerator LoadingProgress(string sceneName)
{
// 비동기 로드 시작
AsyncOperation op = SceneManager.LoadSceneAsync(sceneName);
// 해당 작업 중 다른 씬으로 바로 전환되지 않도록 한다
op.allowSceneActivation = false;
// 1번 구간에서의 증가량을 구한다 : Start()에 위치하는 게 더 적절하지만 가독성을 위해....
float toLoadingTime = (Time.deltaTime / loadingDelayTime);
// 로딩 진행률 업데이트
while (!op.isDone)
{
// 슬라이더의 70% 까지는 toLoadingTime을 이용하여 업데이트
if (sliderProgress.value < 0.7)
{
currentTick += toLoadingTime;
sliderProgress.value = currentTick;
}
// 슬라이더의 70% 도달했는데, 실제 진행률이 70% 이상일 때 슬라이더 최대 0.03씩 이동
// 실제 진행률이 70% 미만이라면, 70%에서 대기하게 된다
else if (op.progress > sliderProgress.value)
{
sliderProgress.value = Mathf.MoveTowards(sliderProgress.value, op.progress, moveTick);
}
// 비동기 로딩 작업이 완료된 경우
// op.progress는 ture가 되기 전까지 0.9가 최댓값이다.
else if (op.progress >= 0.9f)
{
// 0.9에서 바로 1.0으로 이동하는 걸 막기 위해 moveTick을 더해 자연스럽게 증가한다.
while (sliderProgress.value < 0.99f) sliderProgress.value += moveTick;
op.allowSceneActivation = true;
}
yield return null;
}
}
}
AsyncOperation.allowSceneActivation
속성을 false
로 설정하면, progress
는 0.0에서 0.9까지 진행된다. 씬 로딩이 완료되었더라도, allowSceneActivation
이 false
일 때는 씬을 활성화하지 않기 때문에 progress
는 0.9에서 멈춘다. 이 때, 최댓값이 0.9이기 때문에 작업의 완료 조건 설정 시 1.0으로 생각해선 안 된다.
또, 슬라이더의 증가율을 부드럽게 하겠다고 이 코드에서 MoveTowards()
대신 Lerp()
함수를 사용해선 안 된다. Lerp()
는 절대 목표치에 도달하지 않고 무한히 가까워지지만, MoveTowards()
는 반드시 목표치에 도달하기 때문에 이 메소드를 사용했다.