100 lines
3.7 KiB
C#
100 lines
3.7 KiB
C#
using System.Collections;
|
||
using UnityEngine;
|
||
using UnityEngine.SceneManagement;
|
||
using UnityEngine.UI;
|
||
|
||
namespace GameFramework
|
||
{
|
||
/// <summary>
|
||
/// 场景异步加载器(持久化单例)。带黑色淡入淡出过渡。
|
||
/// 场景名可在 Inspector 配置,默认 MainMenu / Gameplay / Scoring。
|
||
///
|
||
/// 修复:协程结束后将 isLoading 重置为 false,允许后续加载。
|
||
/// </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() => 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;
|
||
}
|
||
}
|
||
}
|