Add a loading screen between scenes
This commit is contained in:
@@ -1,255 +1,299 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using UI;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
|
||||
/// <summary>
|
||||
/// Singleton service for loading and unloading Unity scenes asynchronously, with events for progress and completion.
|
||||
/// </summary>
|
||||
public class SceneManagerService : MonoBehaviour
|
||||
namespace Core
|
||||
{
|
||||
private static SceneManagerService _instance;
|
||||
private static bool _isQuitting = false;
|
||||
/// <summary>
|
||||
/// Singleton instance of the SceneManagerService.
|
||||
/// Singleton service for loading and unloading Unity scenes asynchronously, with events for progress and completion.
|
||||
/// </summary>
|
||||
public static SceneManagerService Instance
|
||||
public class SceneManagerService : MonoBehaviour
|
||||
{
|
||||
get
|
||||
[SerializeField] private LoadingScreenController loadingScreen;
|
||||
|
||||
private static SceneManagerService _instance;
|
||||
private static bool _isQuitting = false;
|
||||
/// <summary>
|
||||
/// Singleton instance of the SceneManagerService.
|
||||
/// </summary>
|
||||
public static SceneManagerService Instance
|
||||
{
|
||||
if (_instance == null && Application.isPlaying && !_isQuitting)
|
||||
get
|
||||
{
|
||||
_instance = FindAnyObjectByType<SceneManagerService>();
|
||||
if (_instance == null)
|
||||
if (_instance == null && Application.isPlaying && !_isQuitting)
|
||||
{
|
||||
var go = new GameObject("SceneManagerService");
|
||||
_instance = go.AddComponent<SceneManagerService>();
|
||||
// DontDestroyOnLoad(go);
|
||||
_instance = FindAnyObjectByType<SceneManagerService>();
|
||||
if (_instance == null)
|
||||
{
|
||||
var go = new GameObject("SceneManagerService");
|
||||
_instance = go.AddComponent<SceneManagerService>();
|
||||
// DontDestroyOnLoad(go);
|
||||
}
|
||||
}
|
||||
return _instance;
|
||||
}
|
||||
}
|
||||
|
||||
// Events for scene lifecycle
|
||||
public event Action<string> SceneLoadStarted;
|
||||
public event Action<string, float> SceneLoadProgress;
|
||||
public event Action<string> SceneLoadCompleted;
|
||||
public event Action<string> SceneUnloadStarted;
|
||||
public event Action<string, float> SceneUnloadProgress;
|
||||
public event Action<string> SceneUnloadCompleted;
|
||||
|
||||
private readonly Dictionary<string, AsyncOperation> _activeLoads = new();
|
||||
private readonly Dictionary<string, AsyncOperation> _activeUnloads = new();
|
||||
private const string BootstrapSceneName = "BootstrapScene";
|
||||
|
||||
void Awake()
|
||||
{
|
||||
_instance = this;
|
||||
// DontDestroyOnLoad(gameObject);
|
||||
#if UNITY_EDITOR
|
||||
// In Editor, set CurrentGameplayScene to the currently open scene at play start
|
||||
if (Application.isPlaying)
|
||||
{
|
||||
var activeScene = SceneManager.GetActiveScene();
|
||||
if (activeScene.IsValid())
|
||||
{
|
||||
CurrentGameplayScene = activeScene.name;
|
||||
}
|
||||
}
|
||||
return _instance;
|
||||
}
|
||||
}
|
||||
|
||||
// Events for scene lifecycle
|
||||
public event Action<string> SceneLoadStarted;
|
||||
public event Action<string, float> SceneLoadProgress;
|
||||
public event Action<string> SceneLoadCompleted;
|
||||
public event Action<string> SceneUnloadStarted;
|
||||
public event Action<string, float> SceneUnloadProgress;
|
||||
public event Action<string> SceneUnloadCompleted;
|
||||
|
||||
private readonly Dictionary<string, AsyncOperation> _activeLoads = new();
|
||||
private readonly Dictionary<string, AsyncOperation> _activeUnloads = new();
|
||||
private const string BootstrapSceneName = "BootstrapScene";
|
||||
|
||||
void Awake()
|
||||
{
|
||||
_instance = this;
|
||||
// DontDestroyOnLoad(gameObject);
|
||||
#if UNITY_EDITOR
|
||||
// In Editor, set CurrentGameplayScene to the currently open scene at play start
|
||||
if (Application.isPlaying)
|
||||
{
|
||||
var activeScene = SceneManager.GetActiveScene();
|
||||
if (activeScene.IsValid())
|
||||
{
|
||||
CurrentGameplayScene = activeScene.name;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
// Ensure BootstrapScene is loaded at startup
|
||||
var bootstrap = SceneManager.GetSceneByName(BootstrapSceneName);
|
||||
if (!bootstrap.isLoaded)
|
||||
{
|
||||
SceneManager.LoadScene(BootstrapSceneName, LoadSceneMode.Additive);
|
||||
}
|
||||
}
|
||||
|
||||
void OnApplicationQuit()
|
||||
{
|
||||
_isQuitting = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Load a single scene asynchronously (additive).
|
||||
/// </summary>
|
||||
/// <param name="sceneName">Name of the scene to load.</param>
|
||||
/// <param name="progress">Optional progress reporter.</param>
|
||||
public async Task LoadSceneAsync(string sceneName, IProgress<float> progress = null)
|
||||
{
|
||||
SceneLoadStarted?.Invoke(sceneName);
|
||||
var op = SceneManager.LoadSceneAsync(sceneName, LoadSceneMode.Additive);
|
||||
_activeLoads[sceneName] = op;
|
||||
while (!op.isDone)
|
||||
{
|
||||
progress?.Report(op.progress);
|
||||
SceneLoadProgress?.Invoke(sceneName, op.progress);
|
||||
await Task.Yield();
|
||||
}
|
||||
_activeLoads.Remove(sceneName);
|
||||
SceneLoadCompleted?.Invoke(sceneName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unload a single scene asynchronously.
|
||||
/// </summary>
|
||||
/// <param name="sceneName">Name of the scene to unload.</param>
|
||||
/// <param name="progress">Optional progress reporter.</param>
|
||||
public async Task UnloadSceneAsync(string sceneName, IProgress<float> progress = null)
|
||||
{
|
||||
var scene = SceneManager.GetSceneByName(sceneName);
|
||||
if (!scene.isLoaded)
|
||||
{
|
||||
Debug.LogWarning($"SceneManagerService: Attempted to unload scene '{sceneName}', but it is not loaded.");
|
||||
return;
|
||||
}
|
||||
SceneUnloadStarted?.Invoke(sceneName);
|
||||
var op = SceneManager.UnloadSceneAsync(sceneName);
|
||||
_activeUnloads[sceneName] = op;
|
||||
while (!op.isDone)
|
||||
{
|
||||
progress?.Report(op.progress);
|
||||
SceneUnloadProgress?.Invoke(sceneName, op.progress);
|
||||
await Task.Yield();
|
||||
}
|
||||
_activeUnloads.Remove(sceneName);
|
||||
SceneUnloadCompleted?.Invoke(sceneName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Load multiple scenes asynchronously.
|
||||
/// </summary>
|
||||
/// <param name="sceneNames">Enumerable of scene names to load.</param>
|
||||
/// <param name="progress">Optional progress reporter.</param>
|
||||
public async Task LoadScenesAsync(IEnumerable<string> sceneNames, IProgress<float> progress = null)
|
||||
{
|
||||
int total = 0;
|
||||
int done = 0;
|
||||
var ops = new List<AsyncOperation>();
|
||||
foreach (var name in sceneNames)
|
||||
{
|
||||
total++;
|
||||
var op = SceneManager.LoadSceneAsync(name, LoadSceneMode.Additive);
|
||||
_activeLoads[name] = op;
|
||||
ops.Add(op);
|
||||
SceneLoadStarted?.Invoke(name);
|
||||
}
|
||||
while (done < total)
|
||||
{
|
||||
done = 0;
|
||||
float aggregate = 0f;
|
||||
foreach (var op in ops)
|
||||
// Set up loading screen event handlers
|
||||
SetupLoadingScreenEvents();
|
||||
|
||||
// Ensure BootstrapScene is loaded at startup
|
||||
var bootstrap = SceneManager.GetSceneByName(BootstrapSceneName);
|
||||
if (!bootstrap.isLoaded)
|
||||
{
|
||||
if (op.isDone) done++;
|
||||
aggregate += op.progress;
|
||||
SceneManager.LoadScene(BootstrapSceneName, LoadSceneMode.Additive);
|
||||
}
|
||||
float avgProgress = aggregate / total;
|
||||
progress?.Report(avgProgress);
|
||||
// Optionally, could invoke SceneLoadProgress for each scene
|
||||
await Task.Yield();
|
||||
}
|
||||
foreach (var name in sceneNames)
|
||||
|
||||
private void SetupLoadingScreenEvents()
|
||||
{
|
||||
_activeLoads.Remove(name);
|
||||
SceneLoadCompleted?.Invoke(name);
|
||||
if (loadingScreen == null) return;
|
||||
|
||||
SceneLoadStarted += _ => loadingScreen.ShowLoadingScreen();
|
||||
SceneLoadCompleted += _ => loadingScreen.HideLoadingScreen();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unload multiple scenes asynchronously.
|
||||
/// </summary>
|
||||
/// <param name="sceneNames">Enumerable of scene names to unload.</param>
|
||||
/// <param name="progress">Optional progress reporter.</param>
|
||||
public async Task UnloadScenesAsync(IEnumerable<string> sceneNames, IProgress<float> progress = null)
|
||||
{
|
||||
int total = 0;
|
||||
int done = 0;
|
||||
var ops = new List<AsyncOperation>();
|
||||
foreach (var name in sceneNames)
|
||||
void OnApplicationQuit()
|
||||
{
|
||||
total++;
|
||||
var op = SceneManager.UnloadSceneAsync(name);
|
||||
_activeUnloads[name] = op;
|
||||
ops.Add(op);
|
||||
SceneUnloadStarted?.Invoke(name);
|
||||
_isQuitting = true;
|
||||
}
|
||||
while (done < total)
|
||||
|
||||
/// <summary>
|
||||
/// Load a single scene asynchronously (additive).
|
||||
/// </summary>
|
||||
/// <param name="sceneName">Name of the scene to load.</param>
|
||||
/// <param name="progress">Optional progress reporter.</param>
|
||||
public async Task LoadSceneAsync(string sceneName, IProgress<float> progress = null)
|
||||
{
|
||||
done = 0;
|
||||
float aggregate = 0f;
|
||||
foreach (var op in ops)
|
||||
SceneLoadStarted?.Invoke(sceneName);
|
||||
var op = SceneManager.LoadSceneAsync(sceneName, LoadSceneMode.Additive);
|
||||
_activeLoads[sceneName] = op;
|
||||
while (!op.isDone)
|
||||
{
|
||||
aggregate += op.progress;
|
||||
if (op.isDone) done++;
|
||||
progress?.Report(op.progress);
|
||||
SceneLoadProgress?.Invoke(sceneName, op.progress);
|
||||
await Task.Yield();
|
||||
}
|
||||
float avg = aggregate / total;
|
||||
progress?.Report(avg);
|
||||
_activeLoads.Remove(sceneName);
|
||||
SceneLoadCompleted?.Invoke(sceneName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unload a single scene asynchronously.
|
||||
/// </summary>
|
||||
/// <param name="sceneName">Name of the scene to unload.</param>
|
||||
/// <param name="progress">Optional progress reporter.</param>
|
||||
public async Task UnloadSceneAsync(string sceneName, IProgress<float> progress = null)
|
||||
{
|
||||
var scene = SceneManager.GetSceneByName(sceneName);
|
||||
if (!scene.isLoaded)
|
||||
{
|
||||
Debug.LogWarning($"SceneManagerService: Attempted to unload scene '{sceneName}', but it is not loaded.");
|
||||
return;
|
||||
}
|
||||
SceneUnloadStarted?.Invoke(sceneName);
|
||||
var op = SceneManager.UnloadSceneAsync(sceneName);
|
||||
_activeUnloads[sceneName] = op;
|
||||
while (!op.isDone)
|
||||
{
|
||||
progress?.Report(op.progress);
|
||||
SceneUnloadProgress?.Invoke(sceneName, op.progress);
|
||||
await Task.Yield();
|
||||
}
|
||||
_activeUnloads.Remove(sceneName);
|
||||
SceneUnloadCompleted?.Invoke(sceneName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Load multiple scenes asynchronously.
|
||||
/// </summary>
|
||||
/// <param name="sceneNames">Enumerable of scene names to load.</param>
|
||||
/// <param name="progress">Optional progress reporter.</param>
|
||||
public async Task LoadScenesAsync(IEnumerable<string> sceneNames, IProgress<float> progress = null)
|
||||
{
|
||||
// Show loading screen at the start of multiple scene loading
|
||||
if (loadingScreen != null)
|
||||
{
|
||||
loadingScreen.ShowLoadingScreen();
|
||||
}
|
||||
|
||||
int total = 0;
|
||||
int done = 0;
|
||||
var ops = new List<AsyncOperation>();
|
||||
foreach (var name in sceneNames)
|
||||
SceneUnloadProgress?.Invoke(name, avg);
|
||||
await Task.Yield();
|
||||
}
|
||||
foreach (var name in sceneNames)
|
||||
{
|
||||
_activeUnloads.Remove(name);
|
||||
SceneUnloadCompleted?.Invoke(name);
|
||||
}
|
||||
}
|
||||
|
||||
// Optionally: expose current progress for all active operations
|
||||
public float GetAggregateLoadProgress()
|
||||
{
|
||||
if (_activeLoads.Count == 0) return 1f;
|
||||
float sum = 0f;
|
||||
foreach (var op in _activeLoads.Values) sum += op.progress;
|
||||
return sum / _activeLoads.Count;
|
||||
}
|
||||
public float GetAggregateUnloadProgress()
|
||||
{
|
||||
if (_activeUnloads.Count == 0) return 1f;
|
||||
float sum = 0f;
|
||||
foreach (var op in _activeUnloads.Values) sum += op.progress;
|
||||
return sum / _activeUnloads.Count;
|
||||
}
|
||||
|
||||
// Tracks the currently loaded gameplay scene (not persistent/bootstrapper)
|
||||
public string CurrentGameplayScene { get; private set; } = "MainMenu";
|
||||
|
||||
// Switches from current gameplay scene to a new one
|
||||
public async Task SwitchSceneAsync(string newSceneName, IProgress<float> progress = null)
|
||||
{
|
||||
// Remove all AstarPath (A* Pathfinder) singletons before loading the new scene
|
||||
var astarPaths = FindObjectsByType<AstarPath>(FindObjectsSortMode.None);
|
||||
foreach (var astar in astarPaths)
|
||||
{
|
||||
if (Application.isPlaying)
|
||||
Destroy(astar.gameObject);
|
||||
else
|
||||
DestroyImmediate(astar.gameObject);
|
||||
}
|
||||
// Unload previous gameplay scene (if not BootstrapScene and not same as new)
|
||||
if (!string.IsNullOrEmpty(CurrentGameplayScene) && CurrentGameplayScene != newSceneName && CurrentGameplayScene != BootstrapSceneName)
|
||||
{
|
||||
var prevScene = SceneManager.GetSceneByName(CurrentGameplayScene);
|
||||
if (prevScene.isLoaded)
|
||||
{
|
||||
await UnloadSceneAsync(CurrentGameplayScene);
|
||||
total++;
|
||||
var op = SceneManager.LoadSceneAsync(name, LoadSceneMode.Additive);
|
||||
_activeLoads[name] = op;
|
||||
ops.Add(op);
|
||||
SceneLoadStarted?.Invoke(name);
|
||||
}
|
||||
else
|
||||
|
||||
while (done < total)
|
||||
{
|
||||
Debug.LogWarning($"SceneManagerService: Previous scene '{CurrentGameplayScene}' is not loaded, skipping unload.");
|
||||
done = 0;
|
||||
float aggregate = 0f;
|
||||
foreach (var op in ops)
|
||||
{
|
||||
if (op.isDone) done++;
|
||||
aggregate += op.progress;
|
||||
}
|
||||
float avgProgress = aggregate / total;
|
||||
progress?.Report(avgProgress);
|
||||
|
||||
await Task.Yield();
|
||||
}
|
||||
|
||||
foreach (var name in sceneNames)
|
||||
{
|
||||
_activeLoads.Remove(name);
|
||||
SceneLoadCompleted?.Invoke(name);
|
||||
}
|
||||
|
||||
// Hide loading screen after all scenes are loaded
|
||||
if (loadingScreen != null)
|
||||
{
|
||||
loadingScreen.HideLoadingScreen();
|
||||
}
|
||||
}
|
||||
// Ensure BootstrapScene is loaded before loading new scene
|
||||
var bootstrap = SceneManager.GetSceneByName(BootstrapSceneName);
|
||||
if (!bootstrap.isLoaded)
|
||||
|
||||
/// <summary>
|
||||
/// Unload multiple scenes asynchronously.
|
||||
/// </summary>
|
||||
/// <param name="sceneNames">Enumerable of scene names to unload.</param>
|
||||
/// <param name="progress">Optional progress reporter.</param>
|
||||
public async Task UnloadScenesAsync(IEnumerable<string> sceneNames, IProgress<float> progress = null)
|
||||
{
|
||||
SceneManager.LoadScene(BootstrapSceneName, LoadSceneMode.Additive);
|
||||
// Show loading screen at the start of multiple scene unloading
|
||||
if (loadingScreen != null)
|
||||
{
|
||||
loadingScreen.ShowLoadingScreen();
|
||||
}
|
||||
|
||||
int total = 0;
|
||||
int done = 0;
|
||||
var ops = new List<AsyncOperation>();
|
||||
foreach (var name in sceneNames)
|
||||
{
|
||||
total++;
|
||||
var op = SceneManager.UnloadSceneAsync(name);
|
||||
_activeUnloads[name] = op;
|
||||
ops.Add(op);
|
||||
SceneUnloadStarted?.Invoke(name);
|
||||
}
|
||||
|
||||
while (done < total)
|
||||
{
|
||||
done = 0;
|
||||
float aggregate = 0f;
|
||||
foreach (var op in ops)
|
||||
{
|
||||
aggregate += op.progress;
|
||||
if (op.isDone) done++;
|
||||
}
|
||||
float avg = aggregate / total;
|
||||
progress?.Report(avg);
|
||||
|
||||
await Task.Yield();
|
||||
}
|
||||
|
||||
foreach (var name in sceneNames)
|
||||
{
|
||||
_activeUnloads.Remove(name);
|
||||
SceneUnloadCompleted?.Invoke(name);
|
||||
}
|
||||
|
||||
// Hide loading screen after all scenes are unloaded
|
||||
if (loadingScreen != null)
|
||||
{
|
||||
loadingScreen.HideLoadingScreen();
|
||||
}
|
||||
}
|
||||
|
||||
// Optionally: expose current progress for all active operations
|
||||
public float GetAggregateLoadProgress()
|
||||
{
|
||||
if (_activeLoads.Count == 0) return 1f;
|
||||
float sum = 0f;
|
||||
foreach (var op in _activeLoads.Values) sum += op.progress;
|
||||
return sum / _activeLoads.Count;
|
||||
}
|
||||
public float GetAggregateUnloadProgress()
|
||||
{
|
||||
if (_activeUnloads.Count == 0) return 1f;
|
||||
float sum = 0f;
|
||||
foreach (var op in _activeUnloads.Values) sum += op.progress;
|
||||
return sum / _activeUnloads.Count;
|
||||
}
|
||||
|
||||
// Tracks the currently loaded gameplay scene (not persistent/bootstrapper)
|
||||
public string CurrentGameplayScene { get; private set; } = "MainMenu";
|
||||
|
||||
// Switches from current gameplay scene to a new one
|
||||
public async Task SwitchSceneAsync(string newSceneName, IProgress<float> progress = null)
|
||||
{
|
||||
// Remove all AstarPath (A* Pathfinder) singletons before loading the new scene
|
||||
var astarPaths = FindObjectsByType<AstarPath>(FindObjectsSortMode.None);
|
||||
foreach (var astar in astarPaths)
|
||||
{
|
||||
if (Application.isPlaying)
|
||||
Destroy(astar.gameObject);
|
||||
else
|
||||
DestroyImmediate(astar.gameObject);
|
||||
}
|
||||
// Unload previous gameplay scene (if not BootstrapScene and not same as new)
|
||||
if (!string.IsNullOrEmpty(CurrentGameplayScene) && CurrentGameplayScene != newSceneName && CurrentGameplayScene != BootstrapSceneName)
|
||||
{
|
||||
var prevScene = SceneManager.GetSceneByName(CurrentGameplayScene);
|
||||
if (prevScene.isLoaded)
|
||||
{
|
||||
await UnloadSceneAsync(CurrentGameplayScene);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning($"SceneManagerService: Previous scene '{CurrentGameplayScene}' is not loaded, skipping unload.");
|
||||
}
|
||||
}
|
||||
// Ensure BootstrapScene is loaded before loading new scene
|
||||
var bootstrap = SceneManager.GetSceneByName(BootstrapSceneName);
|
||||
if (!bootstrap.isLoaded)
|
||||
{
|
||||
SceneManager.LoadScene(BootstrapSceneName, LoadSceneMode.Additive);
|
||||
}
|
||||
// Load new gameplay scene
|
||||
await LoadSceneAsync(newSceneName, progress);
|
||||
// Update tracker
|
||||
CurrentGameplayScene = newSceneName;
|
||||
}
|
||||
// Load new gameplay scene
|
||||
await LoadSceneAsync(newSceneName, progress);
|
||||
// Update tracker
|
||||
CurrentGameplayScene = newSceneName;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
using Input;
|
||||
using Interactions;
|
||||
using UnityEngine;
|
||||
using AppleHills.Core.Settings; // Added for IInteractionSettings
|
||||
using AppleHills.Core.Settings;
|
||||
using Core; // Added for IInteractionSettings
|
||||
|
||||
/// <summary>
|
||||
/// Handles level switching when interacted with. Applies switch data and triggers scene transitions.
|
||||
|
||||
168
Assets/Scripts/UI/LoadingScreenController.cs
Normal file
168
Assets/Scripts/UI/LoadingScreenController.cs
Normal file
@@ -0,0 +1,168 @@
|
||||
using System.Collections;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using Core;
|
||||
|
||||
namespace UI
|
||||
{
|
||||
/// <summary>
|
||||
/// Controls the loading screen UI display, progress updates, and timing
|
||||
/// </summary>
|
||||
public class LoadingScreenController : MonoBehaviour
|
||||
{
|
||||
[Header("UI References")]
|
||||
[SerializeField] private GameObject loadingScreenContainer;
|
||||
[SerializeField] private Image progressBarImage;
|
||||
|
||||
[Header("Settings")]
|
||||
[SerializeField] private float minimumDisplayTime = 1.0f;
|
||||
[SerializeField] private float progressUpdateInterval = 0.1f;
|
||||
|
||||
private float _displayStartTime;
|
||||
private Coroutine _progressCoroutine;
|
||||
private bool _loadingComplete = false;
|
||||
private bool _animationComplete = false;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (loadingScreenContainer == null)
|
||||
loadingScreenContainer = gameObject;
|
||||
|
||||
// Ensure the loading screen is initially hidden
|
||||
if (loadingScreenContainer != null)
|
||||
{
|
||||
loadingScreenContainer.SetActive(false);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Shows the loading screen and resets the progress bar to zero
|
||||
/// </summary>
|
||||
public void ShowLoadingScreen()
|
||||
{
|
||||
// Stop any existing progress coroutine
|
||||
if (_progressCoroutine != null)
|
||||
{
|
||||
StopCoroutine(_progressCoroutine);
|
||||
_progressCoroutine = null;
|
||||
}
|
||||
|
||||
_displayStartTime = Time.time;
|
||||
_loadingComplete = false;
|
||||
_animationComplete = false;
|
||||
|
||||
if (progressBarImage != null)
|
||||
{
|
||||
progressBarImage.fillAmount = 0f;
|
||||
}
|
||||
|
||||
if (loadingScreenContainer != null)
|
||||
{
|
||||
loadingScreenContainer.SetActive(true);
|
||||
}
|
||||
|
||||
// Start the progress filling coroutine
|
||||
_progressCoroutine = StartCoroutine(AnimateProgressBar());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Animates the progress bar at a steady pace over the minimum display time,
|
||||
/// while also checking actual loading progress from SceneManagerService
|
||||
/// </summary>
|
||||
private IEnumerator AnimateProgressBar()
|
||||
{
|
||||
float startTime = Time.time;
|
||||
|
||||
// Continue until both animation and loading are complete
|
||||
while (!_animationComplete)
|
||||
{
|
||||
// Calculate the steady progress based on elapsed time
|
||||
float elapsedTime = Time.time - startTime;
|
||||
float steadyProgress = Mathf.Clamp01(elapsedTime / minimumDisplayTime);
|
||||
|
||||
// Get the actual loading progress from SceneManagerService
|
||||
float actualProgress = 0f;
|
||||
if (SceneManagerService.Instance != null)
|
||||
{
|
||||
actualProgress = SceneManagerService.Instance.GetAggregateLoadProgress();
|
||||
}
|
||||
|
||||
// If loading is complete, actualProgress should be 1.0
|
||||
if (_loadingComplete)
|
||||
{
|
||||
actualProgress = 1.0f;
|
||||
}
|
||||
|
||||
// Use the minimum of steady progress and actual progress
|
||||
// This ensures we don't show more progress than actual loading
|
||||
float displayProgress = Mathf.Min(steadyProgress, actualProgress);
|
||||
|
||||
// Log the progress values for debugging
|
||||
Debug.Log($"[LoadingScreen] Progress - Default: {steadyProgress:F2}, Actual: {actualProgress:F2}, Display: {displayProgress:F2}");
|
||||
|
||||
// Directly set the progress bar fill amount without smoothing
|
||||
if (progressBarImage != null)
|
||||
{
|
||||
progressBarImage.fillAmount = displayProgress;
|
||||
}
|
||||
|
||||
// Check if the animation has completed
|
||||
// Animation is complete when we've reached the minimum display time AND we're at 100% progress
|
||||
if (steadyProgress >= 1.0f && displayProgress >= 1.0f)
|
||||
{
|
||||
_animationComplete = true;
|
||||
Debug.Log("[LoadingScreen] Animation complete");
|
||||
break;
|
||||
}
|
||||
|
||||
// Wait for the configured interval before updating again
|
||||
yield return new WaitForSeconds(progressUpdateInterval);
|
||||
}
|
||||
|
||||
// Ensure we end at 100% progress
|
||||
if (progressBarImage != null)
|
||||
{
|
||||
progressBarImage.fillAmount = 1.0f;
|
||||
Debug.Log("[LoadingScreen] Final progress set to 1.0");
|
||||
}
|
||||
|
||||
// Hide the screen if loading is also complete
|
||||
if (_loadingComplete)
|
||||
{
|
||||
if (loadingScreenContainer != null)
|
||||
{
|
||||
loadingScreenContainer.SetActive(false);
|
||||
Debug.Log("[LoadingScreen] Animation AND loading complete, hiding screen");
|
||||
}
|
||||
}
|
||||
|
||||
_progressCoroutine = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when the actual loading process is complete
|
||||
/// </summary>
|
||||
public void HideLoadingScreen()
|
||||
{
|
||||
Debug.Log("[LoadingScreen] Loading complete, marking loading as finished");
|
||||
|
||||
// Mark that loading is complete
|
||||
_loadingComplete = true;
|
||||
|
||||
// If animation is already complete, we can hide the screen now
|
||||
if (_animationComplete)
|
||||
{
|
||||
if (loadingScreenContainer != null)
|
||||
{
|
||||
loadingScreenContainer.SetActive(false);
|
||||
Debug.Log("[LoadingScreen] Animation already complete, hiding screen immediately");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.Log("[LoadingScreen] Animation still in progress, waiting for it to complete");
|
||||
// The coroutine will handle hiding when animation completes
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Assets/Scripts/UI/LoadingScreenController.cs.meta
Normal file
3
Assets/Scripts/UI/LoadingScreenController.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1494b10574e74acd880f9101b4248239
|
||||
timeCreated: 1760341032
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using Core;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using Core;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
using Input;
|
||||
|
||||
Reference in New Issue
Block a user