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; } } } }