2026-05-06 15:07:56 +02:00

200 lines
6.4 KiB
C#

using System.Collections;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
using DuloGames.UI.Tweens;
namespace DuloGames.UI
{
/// <summary>
/// Loading Overlay
/// This script requires to be attached to a canvas.
/// The canvas must have the highest sorting order.
/// The canvas must have a GraphicRaycaster.
/// The visibility of the overlay is controlled by a CanvasGroup alpha.
/// </summary>
[RequireComponent(typeof(Canvas)), RequireComponent(typeof(GraphicRaycaster)), AddComponentMenu("UI/Loading Overlay", 58)]
public class UILoadingOverlay : MonoBehaviour
{
[SerializeField] private UIProgressBar m_ProgressBar;
[SerializeField] private CanvasGroup m_CanvasGroup;
[Header("Transition")]
[SerializeField] private TweenEasing m_TransitionEasing = TweenEasing.InOutQuint;
[SerializeField] private float m_TransitionDuration = 0.4f;
private bool m_Showing = false;
private int m_LoadSceneId = 0;
// Tween controls
[System.NonSerialized] private readonly TweenRunner<FloatTween> m_FloatTweenRunner;
// Called by Unity prior to deserialization,
// should not be called by users
protected UILoadingOverlay()
{
if (this.m_FloatTweenRunner == null)
this.m_FloatTweenRunner = new TweenRunner<FloatTween>();
this.m_FloatTweenRunner.Init(this);
}
protected void Awake()
{
DontDestroyOnLoad(this.gameObject);
// Make sure it's top most ordering number
Canvas[] canvases = FindObjectsOfType<Canvas>();
Canvas currentCanvas = this.gameObject.GetComponent<Canvas>();
foreach (Canvas canvas in canvases)
{
// Make sure it's not our canvas1
if (!canvas.Equals(currentCanvas))
{
if (canvas.sortingOrder > currentCanvas.sortingOrder)
currentCanvas.sortingOrder = canvas.sortingOrder + 1;
}
}
// Update the progress bar
if (this.m_ProgressBar != null)
this.m_ProgressBar.fillAmount = 0f;
// Update the canvas group
if (this.m_CanvasGroup != null)
this.m_CanvasGroup.alpha = 0f;
}
protected void OnEnable()
{
SceneManager.sceneLoaded += OnSceneFinishedLoading;
}
protected void OnDisable()
{
SceneManager.sceneLoaded -= OnSceneFinishedLoading;
}
/// <summary>
/// Shows the loading overlay and loads the scene.
/// </summary>
/// <param name="sceneName">The scene name.</param>
public void LoadScene(string sceneName)
{
Scene scene = SceneManager.GetSceneByName(sceneName);
if (scene.IsValid())
this.LoadScene(scene.buildIndex);
}
/// <summary>
/// Shows the loading overlay and loads the scene.
/// </summary>
/// <param name="sceneIndex">The scene build index.</param>
public void LoadScene(int sceneIndex)
{
this.m_Showing = true;
this.m_LoadSceneId = sceneIndex;
// Update the progress bar
if (this.m_ProgressBar != null)
this.m_ProgressBar.fillAmount = 0f;
// Update the canvas group
if (this.m_CanvasGroup != null)
this.m_CanvasGroup.alpha = 0f;
// Start the tween
this.StartAlphaTween(1f, this.m_TransitionDuration, true);
}
/// <summary>
/// Starts alpha tween.
/// </summary>
/// <param name="targetAlpha">Target alpha.</param>
/// <param name="duration">Duration.</param>
/// <param name="ignoreTimeScale">If set to <c>true</c> ignore time scale.</param>
public void StartAlphaTween(float targetAlpha, float duration, bool ignoreTimeScale)
{
if (this.m_CanvasGroup == null)
return;
var floatTween = new FloatTween { duration = duration, startFloat = this.m_CanvasGroup.alpha, targetFloat = targetAlpha };
floatTween.AddOnChangedCallback(SetCanvasAlpha);
floatTween.AddOnFinishCallback(OnTweenFinished);
floatTween.ignoreTimeScale = ignoreTimeScale;
floatTween.easing = this.m_TransitionEasing;
this.m_FloatTweenRunner.StartTween(floatTween);
}
/// <summary>
/// Sets the canvas alpha.
/// </summary>
/// <param name="alpha">Alpha.</param>
protected void SetCanvasAlpha(float alpha)
{
if (this.m_CanvasGroup == null)
return;
// Set the alpha
this.m_CanvasGroup.alpha = alpha;
}
/// <summary>
/// Raises the list tween finished event.
/// </summary>
protected void OnTweenFinished()
{
// When the loading overlay is shown
if (this.m_Showing)
{
this.m_Showing = false;
StartCoroutine(AsynchronousLoad());
}
else
{
// Destroy the loading overlay
Destroy(this.gameObject);
}
}
IEnumerator AsynchronousLoad()
{
yield return null;
AsyncOperation ao = SceneManager.LoadSceneAsync(this.m_LoadSceneId);
ao.allowSceneActivation = false;
while (!ao.isDone)
{
// [0, 0.9] > [0, 1]
float progress = Mathf.Clamp01(ao.progress / 0.9f);
// Update the progress bar
if (this.m_ProgressBar != null)
{
this.m_ProgressBar.fillAmount = progress;
}
// Loading completed
if (ao.progress == 0.9f)
{
ao.allowSceneActivation = true;
}
yield return null;
}
}
private void OnSceneFinishedLoading(Scene scene, LoadSceneMode mode)
{
if (scene.buildIndex != this.m_LoadSceneId)
return;
// Hide the loading overlay
this.StartAlphaTween(0f, this.m_TransitionDuration, true);
}
}
}