using System.Collections; using UnityEngine; using UnityEngine.SceneManagement; using UnityEngine.UI; namespace GameFramework { /// /// 场景异步加载器(持久化单例)。带黑色淡入淡出过渡。 /// 场景名可在 Inspector 配置,默认 MainMenu / Gameplay / Scoring。 /// /// 修复:协程结束后将 isLoading 重置为 false,允许后续加载。 /// public class SceneLoader : PersistentSingleton { [Header("过渡")] [SerializeField] private Image transitionImage; [SerializeField] private float fadeTime = 1.5f; [Header("场景名(按你工程中的实际名称填)")] [SerializeField] private string mainMenuScene = "MainMenu"; [SerializeField] private string gameplayScene = "Gameplay"; [SerializeField] private string scoringScene = "Scoring"; private Color color; private bool isLoading = false; public void LoadGameplayScene() => Load(gameplayScene); public void LoadMainMenuScene() => Load(mainMenuScene); public void LoadScoringScene() => Load(scoringScene); public void Load(string sceneName) { if (isLoading) return; isLoading = true; StopAllCoroutines(); StartCoroutine(LoadingCoroutine(sceneName)); } private IEnumerator LoadingCoroutine(string sceneName) { if (transitionImage == null) { Debug.LogWarning("[SceneLoader] transitionImage 未赋值! " + "请在 SceneLoader 子物体上创建 Canvas (Overlay, SortOrder=9999) + 全屏黑色 Image," + "拖到 SceneLoader 的 transitionImage 字段。"); } var loadingOperation = SceneManager.LoadSceneAsync(sceneName); loadingOperation.allowSceneActivation = false; if (transitionImage != null) { transitionImage.gameObject.SetActive(true); color = transitionImage.color; color.a = 0f; // 淡入到黑(LoadSceneAsync 在后台并行加载) while (color.a < 1f) { color.a = Mathf.Clamp01(color.a + Time.unscaledDeltaTime / fadeTime); transitionImage.color = color; yield return null; } color.a = 1f; transitionImage.color = color; // 淡入完成后,确保场景已加载就绪(大多数情况下已经加载好了) yield return new WaitUntil(() => loadingOperation.progress >= 0.9f); } else { // 没有过渡图,直接等加载 yield return new WaitUntil(() => loadingOperation.progress >= 0.9f); } loadingOperation.allowSceneActivation = true; // 等待场景切换完全完成(旧场景卸载 + 新场景渲染就绪) // 没有这一步会在场景交接时闪一帧旧场景的内容 yield return null; yield return null; if (transitionImage != null) { // 淡出到透明 while (color.a > 0f) { color.a = Mathf.Clamp01(color.a - Time.unscaledDeltaTime / fadeTime); transitionImage.color = color; yield return null; } transitionImage.gameObject.SetActive(false); } // 加载完成,重置标志,允许下一次加载 isLoading = false; } } }