using System;
using System.Collections.Generic;
using System.Threading;
using Cysharp.Threading.Tasks;
using MotionFramework;
using UnityEngine;
using UnityEngine.SceneManagement;
namespace Framework.Scripts.Runtime.Engine.Scene
{
///
/// 场景管理器
///
public class SceneManager : ModuleSingleton, IModule
{
private string _currentSceneName;
private string _nextSceneName;
private bool _isLoading;
private float _loadingProgress;
private Action _onLoadingProgressCallback;
private Action _onLoadingCompleteCallback;
private HashSet _preloadedScenes = new HashSet();
private CancellationTokenSource _loadingCancellation;
private bool _isProcessingScene;
public string CurrentSceneName => _currentSceneName;
public bool IsLoading => _isLoading;
public float LoadingProgress => _loadingProgress;
public void OnCreate(object createParam)
{
_currentSceneName = UnityEngine.SceneManagement.SceneManager.GetActiveScene().name;
_loadingCancellation = new CancellationTokenSource();
}
public void OnUpdate()
{
}
public void OnDestroy()
{
_loadingCancellation?.Cancel();
_loadingCancellation?.Dispose();
_loadingCancellation = null;
}
public void OnGUI()
{
}
///
/// 重置加载状态
///
private void ResetLoadingState()
{
_isLoading = false;
_loadingProgress = 0f;
_onLoadingProgressCallback = null;
_onLoadingCompleteCallback = null;
// 取消之前的加载操作
if (_loadingCancellation != null)
{
if (!_loadingCancellation.IsCancellationRequested)
_loadingCancellation.Cancel();
_loadingCancellation.Dispose();
}
_loadingCancellation = new CancellationTokenSource();
}
///
/// 加载场景并等待初始化完成
///
/// 场景名称
/// 场景初始化完成后的回调,在这里执行场景加载后的初始化逻辑
/// 加载进度回调
/// 场景加载完成的回调
public async UniTask LoadSceneAndWaitAsync(
string sceneName,
Action onProgress = null,
Action onComplete = null)
{
if (string.IsNullOrEmpty(sceneName))
{
Debug.LogError("场景名称不能为空!");
return;
}
if (_isProcessingScene)
{
Debug.LogError("已有场景正在处理中,请等待完成!");
return;
}
_isProcessingScene = true;
try
{
// 创建一个TaskCompletionSource来等待场景加载完成
var tcs = new UniTaskCompletionSource();
// 加载场景
LoadSceneAsync(sceneName, onProgress, () => tcs.TrySetResult());
// 等待场景加载完成
await tcs.Task;
// 等待一帧确保场景已经完全准备好
await UniTask.NextFrame();
onComplete?.Invoke();
}
finally
{
_isProcessingScene = false;
}
}
///
/// 异步加载场景
///
/// 场景名称
/// 加载进度回调
/// 加载完成回调
public async UniTaskVoid LoadSceneAsync(string sceneName, Action onProgress = null, Action onComplete = null)
{
if (string.IsNullOrEmpty(sceneName))
{
Debug.LogError("场景名称不能为空!");
return;
}
// 如果正在加载,先重置状态
if (_isLoading)
{
Debug.LogWarning("上一个场景加载被中断!");
ResetLoadingState();
}
_nextSceneName = sceneName;
_onLoadingProgressCallback = onProgress;
_onLoadingCompleteCallback = onComplete;
_isLoading = true;
try
{
await LoadSceneAsyncInternal().AttachExternalCancellation(_loadingCancellation.Token);
}
catch (OperationCanceledException)
{
Debug.LogWarning($"场景 {sceneName} 加载已取消");
ResetLoadingState();
}
catch (Exception e)
{
Debug.LogError($"加载场景 {sceneName} 失败: {e}");
ResetLoadingState();
}
}
///
/// 预加载场景
///
/// 场景名称
public async UniTask PreloadSceneAsync(string sceneName)
{
if (string.IsNullOrEmpty(sceneName))
{
Debug.LogError("场景名称不能为空!");
return;
}
if (_preloadedScenes.Contains(sceneName))
{
return;
}
var operation = UnityEngine.SceneManagement.SceneManager.LoadSceneAsync(sceneName, LoadSceneMode.Additive);
if (operation != null)
{
operation.allowSceneActivation = false;
await operation.ToUniTask(Progress.Create(progress =>
{
Debug.Log($"预加载场景 {sceneName}: {progress}");
}));
_preloadedScenes.Add(sceneName);
}
}
///
/// 卸载预加载的场景
///
/// 场景名称
public async UniTask UnloadPreloadedSceneAsync(string sceneName)
{
if (_preloadedScenes.Contains(sceneName))
{
await UnityEngine.SceneManagement.SceneManager.UnloadSceneAsync(sceneName).ToUniTask();
_preloadedScenes.Remove(sceneName);
}
}
private async UniTask LoadSceneAsyncInternal()
{
try
{
// 开始加载前等待一帧,让UI有时间更新
await UniTask.Yield(_loadingCancellation.Token);
// 开始异步加载场景
var operation = UnityEngine.SceneManagement.SceneManager.LoadSceneAsync(_nextSceneName);
if (operation == null)
{
throw new Exception($"开始加载场景失败: {_nextSceneName}");
}
operation.allowSceneActivation = false;
// 等待加载完成
while (operation.progress < 0.9f)
{
_loadingProgress = operation.progress;
_onLoadingProgressCallback?.Invoke(_loadingProgress);
await UniTask.Yield(_loadingCancellation.Token);
}
// 当进度达到0.9时,场景已经加载完成,等待激活
operation.allowSceneActivation = true;
// 等待场景完全加载完成
await operation.ToUniTask(Progress.Create(progress =>
{
_loadingProgress = progress;
_onLoadingProgressCallback?.Invoke(progress);
}), PlayerLoopTiming.Update, _loadingCancellation.Token);
// 确保新场景已经被激活
await UniTask.WaitUntil(() =>
UnityEngine.SceneManagement.SceneManager.GetActiveScene().name == _nextSceneName,
PlayerLoopTiming.Update, _loadingCancellation.Token);
// 更新当前场景名称
_currentSceneName = _nextSceneName;
_loadingProgress = 1f;
// 调用加载完成回调
_onLoadingProgressCallback?.Invoke(1f);
_onLoadingCompleteCallback?.Invoke();
}
finally
{
_isLoading = false;
// 清理回调
_onLoadingProgressCallback = null;
_onLoadingCompleteCallback = null;
}
}
}
}