Files
gold_dolphin/unity/Assets/UI/SceneLoader.cs
T
2026-07-06 00:26:13 +08:00

131 lines
4.9 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System.Collections;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
namespace GameFramework
{
/// <summary>
/// 场景异步加载器(持久化单例)。带黑色淡入淡出过渡。
/// 场景名可在 Inspector 配置,默认 MainMenu / Gameplay / Scoring。
///
/// 搭建:把 SceneLoader 挂到一个空物体上(放第一个场景 MainMenu 里),
/// 它会 DontDestroyOnLoad。transitionImage 是它子物体 Canvas 上的 Image(全屏黑),
/// Canvas 设为 Screen Space - Overlay、sortingOrder 设很高(如 9999)。
/// </summary>
public class SceneLoader : PersistentSingleton<SceneLoader>
{
[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()
{
// 重置 GameManager 状态
if (GameManager.Instance != null)
{
GameManager.GameState = GameState.Playing;
GameManager.onGameOver = null;
GameManager.onGameWin = null;
}
// 重置 ScoreManager
if (ScoreManager.Instance != null)
ScoreManager.Instance.ResetScore();
// 清理静态事件残留订阅
IndianOceanAssets.Engine2_5D.HealthSystem.onPlayerDamaged = null;
Load(gameplayScene);
}
public void LoadMainMenuScene() => Load(mainMenuScene);
public void LoadScoringScene() => Load(scoringScene);
public void Load(string sceneName)
{
if (isLoading)
{
Debug.LogWarning($"[SceneLoader] 上次加载未完成,强制重置并加载: {sceneName}");
StopAllCoroutines();
isLoading = false;
}
isLoading = true;
StartCoroutine(LoadingCoroutine(sceneName));
}
private IEnumerator LoadingCoroutine(string sceneName)
{
if (transitionImage == null)
{
Debug.LogWarning("[SceneLoader] transitionImage 未赋值! " +
"请在 SceneLoader 子物体上创建 Canvas (Overlay, SortOrder=9999) + 全屏黑色 Image" +
"拖到 SceneLoader 的 transitionImage 字段。");
}
Debug.Log($"[SceneLoader] 开始加载场景: {sceneName}");
var loadingOperation = SceneManager.LoadSceneAsync(sceneName);
if (loadingOperation == null)
{
Debug.LogError($"[SceneLoader] 场景 '{sceneName}' 加载失败!请检查 Build Settings 中是否包含该场景。");
isLoading = false;
yield break;
}
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);
}
Debug.Log($"[SceneLoader] 场景加载完成: {sceneName}");
isLoading = false;
}
}
}