2026-04-16 로딩화면
This commit is contained in:
8
Assets/02_Scripts/Core.meta
Normal file
8
Assets/02_Scripts/Core.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 733e83836bb077c49bc004782151d904
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
43
Assets/02_Scripts/Core/Util.cs
Normal file
43
Assets/02_Scripts/Core/Util.cs
Normal file
@@ -0,0 +1,43 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using UnityEngine;
|
||||
|
||||
public static class Util
|
||||
{
|
||||
/// 특정 시간(초) 후에 액션을 실행
|
||||
public static async Awaitable RunDelayed(float delay, Action action, CancellationToken token = default)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 유니티 전용 비동기 대기
|
||||
await Awaitable.WaitForSecondsAsync(delay, token);
|
||||
|
||||
// 함수 실행
|
||||
action?.Invoke();
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
// 취소되었을 때의 처리 (필요 시)
|
||||
}
|
||||
}
|
||||
|
||||
/// 다음 프레임에 액션을 실행
|
||||
public static async Awaitable RunNextFrame(Action action, CancellationToken token = default)
|
||||
{
|
||||
try
|
||||
{
|
||||
await Awaitable.EndOfFrameAsync(token);
|
||||
action?.Invoke();
|
||||
}
|
||||
catch (OperationCanceledException) { }
|
||||
}
|
||||
|
||||
public static float NormalizeAngle(float angle)
|
||||
{
|
||||
while (angle > 180)
|
||||
angle -= 360;
|
||||
while (angle < -180)
|
||||
angle += 360;
|
||||
return angle;
|
||||
}
|
||||
}
|
||||
2
Assets/02_Scripts/Core/Util.cs.meta
Normal file
2
Assets/02_Scripts/Core/Util.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ecdc55c0184e3fc44a49245b82ac1449
|
||||
18
Assets/02_Scripts/GlobalObject.cs
Normal file
18
Assets/02_Scripts/GlobalObject.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using UnityEngine;
|
||||
|
||||
public class GlobalObject : MonoBehaviour
|
||||
{
|
||||
private static GlobalObject _instance;
|
||||
void Awake()
|
||||
{
|
||||
if (_instance == null)
|
||||
{
|
||||
_instance = this;
|
||||
DontDestroyOnLoad(gameObject);
|
||||
}
|
||||
else
|
||||
{
|
||||
Destroy(gameObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
2
Assets/02_Scripts/GlobalObject.cs.meta
Normal file
2
Assets/02_Scripts/GlobalObject.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5730f2ce7e804634783f0d9808222a34
|
||||
8
Assets/02_Scripts/Managers.meta
Normal file
8
Assets/02_Scripts/Managers.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cf9904a0c2c0c1c4997d3a0256aa87c2
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
22
Assets/02_Scripts/Managers/GameManager.cs
Normal file
22
Assets/02_Scripts/Managers/GameManager.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEngine.InputSystem;
|
||||
using UnityEngine.SceneManagement;
|
||||
using UnityEngine.UI;
|
||||
|
||||
public class GameManager : MonoBehaviour
|
||||
{
|
||||
public static GameManager Instance;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (Instance == null)
|
||||
{
|
||||
Instance = this; //만들어진 자신을 인스턴스로 설정
|
||||
}
|
||||
else
|
||||
{
|
||||
Destroy(gameObject); //이미 인스턴스가 있으면 자신을 파괴
|
||||
}
|
||||
}
|
||||
}
|
||||
2
Assets/02_Scripts/Managers/GameManager.cs.meta
Normal file
2
Assets/02_Scripts/Managers/GameManager.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dd21571511bbe3444871551dcd8fc777
|
||||
146
Assets/02_Scripts/Managers/SceneLoadManager.cs
Normal file
146
Assets/02_Scripts/Managers/SceneLoadManager.cs
Normal file
@@ -0,0 +1,146 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
|
||||
public class SceneLoadManager : MonoBehaviour
|
||||
{
|
||||
public static SceneLoadManager Instance;
|
||||
|
||||
[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 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(alphaTime > 0f)
|
||||
{
|
||||
await FadeLoadingCanvas(!isActive,alphaTime);
|
||||
}
|
||||
|
||||
_loadingScreen.gameObject.SetActive(isActive);
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
await SetSceneLoadingActive(true,2f);
|
||||
|
||||
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,2f);
|
||||
//-------------------------------------------------------------------------------
|
||||
|
||||
Debug.Log("씬 전환됨");
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
Debug.Log("씬 전환 작업이 취소됨");
|
||||
}
|
||||
}
|
||||
}
|
||||
2
Assets/02_Scripts/Managers/SceneLoadManager.cs.meta
Normal file
2
Assets/02_Scripts/Managers/SceneLoadManager.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1bb2fdf9537239e4f968be4954a998d7
|
||||
16
Assets/02_Scripts/UI/LoadingScreen.cs
Normal file
16
Assets/02_Scripts/UI/LoadingScreen.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
public class LoadingScreen : MonoBehaviour
|
||||
{
|
||||
public Image LoadingImage;
|
||||
public Image BackgroundImage;
|
||||
public TextMeshProUGUI LoadingTextMeshProUGUI;
|
||||
public CanvasGroup LoadingScreenCanvasGroup;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
LoadingScreenCanvasGroup = GetComponent<CanvasGroup>();
|
||||
}
|
||||
}
|
||||
2
Assets/02_Scripts/UI/LoadingScreen.cs.meta
Normal file
2
Assets/02_Scripts/UI/LoadingScreen.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8cfa3149f37cd3844882b0f2135cf423
|
||||
Reference in New Issue
Block a user