Files
Shopping_UnityVR/Assets/02_Scripts/Managers/SceneLoadManager.cs

163 lines
5.2 KiB
C#

using System;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.SceneManagement;
public class SceneLoadManager : MonoBehaviour
{
public static SceneLoadManager Instance;
[SerializeField] private GameObject _loadingRoot;
[SerializeField] private Camera _loadingCam;
[SerializeField] private Transform _loadingCamTargetTransform;
[SerializeField] private LoadingScreen _loadingScreen;
private void Awake()
{
if (Instance == null)
{
Instance = this; //만들어진 자신을 인스턴스로 설정
}
else
{
Destroy(gameObject); //이미 인스턴스가 있으면 자신을 파괴
}
_loadingScreen = _loadingCam.GetComponentInChildren<LoadingScreen>();
}
private void Start()
{
SceneManager.sceneLoaded += OnSceneLoaded;
}
private void Update()
{
if(_loadingCamTargetTransform != null)
{
_loadingCam.transform.position = _loadingCamTargetTransform.position;
_loadingCam.transform.rotation = _loadingCamTargetTransform.rotation;
}
}
private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
{
// 씬이 로드될 때마다
}
public async Awaitable FadeLoadingCanvas(bool isOut,float fadeTime)
{
float startAlpha = isOut ? 1f : 0f;
float endAlpha = isOut ? 0f : 1f;
float timer = 0;
_loadingScreen.LoadingScreenCanvasGroup.alpha = startAlpha;
while(timer < fadeTime)
{
timer += Time.deltaTime;
_loadingScreen.LoadingScreenCanvasGroup.alpha = Mathf.Lerp(startAlpha, endAlpha, timer / fadeTime);
await Awaitable.NextFrameAsync(this.destroyCancellationToken);
}
_loadingScreen.LoadingScreenCanvasGroup.alpha = endAlpha;
}
public async Task SetSceneLoadingActive(bool isActive,float alphaTime)
{
if (isActive)
_loadingRoot.SetActive(true);
if (alphaTime > 0f)
{
await FadeLoadingCanvas(!isActive,alphaTime);
}
if (!isActive)
_loadingRoot.SetActive(false);
}
public void SetSceneLoadingActive(bool isActive)
{
_ = SetSceneLoadingActive(isActive, 0f);
}
public void SetSceneLoadingProgressValue(float value)
{
_loadingScreen.LoadingImage.fillAmount = value;
_loadingScreen.LoadingTextMeshProUGUI.text = $"{(value * 100):F0}% 로딩 중...";
}
public void SetSceneLoadingProgressValue(float value,string loadingText)
{
_loadingScreen.LoadingImage.fillAmount = value;
_loadingScreen.LoadingTextMeshProUGUI.text = loadingText;
}
public void RequestSceneChange(string sceneName)
{
_ = SceneChange(sceneName);
}
private async Awaitable SceneChange(string sceneName)
{
try
{
SetSceneLoadingProgressValue(0f);
await SetSceneLoadingActive(true,1f);
AsyncOperation op = SceneManager.LoadSceneAsync(sceneName);
//자동 전환을 하고 싶지 않을 경우 해당값을 false로 두었다가 true로 바꾸면 그 때 전환됨
op.allowSceneActivation = false;
//화면에 보여줄 로딩 수치
float displayProgress = 0f;
//op.progress 0.9가 데이터 로딩이 끝난 기준 allowSceneActivation이 트루면 바로 다음으로 넘어가면서 op.isDone이 true가 된다.
while (op.progress < 0.9f)
{
//실제 로딩 수치
float realProgress = Mathf.Clamp01(op.progress / 0.9f);
//보여줄 값을 실제값을 향해 부드럽게 이동
displayProgress = Mathf.MoveTowards(displayProgress, realProgress, Time.deltaTime * 0.5f);
// UI에 적용
SetSceneLoadingProgressValue(displayProgress);
await Awaitable.NextFrameAsync(this.destroyCancellationToken); //자기자신이 파괴될때 토큰에 취소요청을 보냄
}
SetSceneLoadingProgressValue(1);
// 잠시 대기했다가 전환
await Awaitable.WaitForSecondsAsync(1.0f, this.destroyCancellationToken);
//로딩 끝
op.allowSceneActivation = true;
// 씬 활성화가 완전히 끝날 때까지 대기
// allowSceneActivation가 true가 되고 완전히 전환되기까지는 몇프레임 걸림. op.isDone 은 이 과정이 끝난 뒤에 true가 됨.
while(!op.isDone)
{
await Awaitable.NextFrameAsync(this.destroyCancellationToken);
}
//VR용 로직
//트래킹이 중단되면 안되기 때문에 카메라를 유지해야 한다
_loadingCamTargetTransform = Camera.main.transform; // 새로운 씬의 메인카메라를 따라가게끔 설정
await SetSceneLoadingActive(false,1f);
//-------------------------------------------------------------------------------
Debug.Log("씬 전환됨");
}
catch (OperationCanceledException)
{
Debug.Log("씬 전환 작업이 취소됨");
}
}
}