using System.Collections; using UnityEngine; using UnityEngine.SceneManagement; using BaseGames.Core.Events; namespace BaseGames.Core { /// /// 场景管理服务接口。 /// public interface ISceneService { /// 异步加载指定场景(Additive)。 IEnumerator LoadSceneCoroutine(SceneLoadRequest request); /// 卸载当前房间场景(保留 Persistent)。 IEnumerator UnloadCurrentRoomCoroutine(); /// 加载主菜单。 IEnumerator LoadMainMenuCoroutine(); } /// /// 场景管理服务。 /// [DefaultExecutionOrder(-900)] public class SceneService : MonoBehaviour, ISceneService { [Header("Event Channels - Listen")] [SerializeField] private SceneLoadRequestEventChannelSO _onSceneLoadRequest; [Header("Event Channels - Raise")] [SerializeField] private StringEventChannelSO _onSceneLoaded; [SerializeField] private VoidEventChannelSO _onFadeInRequest; [SerializeField] private VoidEventChannelSO _onFadeOutRequest; [SerializeField] private float _fadeDuration = 0.3f; private string _currentRoomScene; private readonly CompositeDisposable _subscriptions = new(); private void OnEnable() { _onSceneLoadRequest?.Subscribe(HandleSceneLoadRequest).AddTo(_subscriptions); } private void OnDisable() => _subscriptions.Clear(); private void HandleSceneLoadRequest(SceneLoadRequest request) => StartCoroutine(LoadSceneCoroutine(request)); public IEnumerator LoadSceneCoroutine(SceneLoadRequest request) { _onFadeOutRequest?.Raise(); yield return new WaitForSeconds(_fadeDuration); if (!string.IsNullOrEmpty(_currentRoomScene)) { var unload = SceneManager.UnloadSceneAsync(_currentRoomScene); yield return new WaitUntil(() => unload.isDone); } var load = SceneManager.LoadSceneAsync(request.SceneName, LoadSceneMode.Additive); yield return new WaitUntil(() => load.isDone); _currentRoomScene = request.SceneName; _onSceneLoaded?.Raise(request.SceneName); _onFadeInRequest?.Raise(); } public IEnumerator UnloadCurrentRoomCoroutine() { if (string.IsNullOrEmpty(_currentRoomScene)) yield break; var op = SceneManager.UnloadSceneAsync(_currentRoomScene); yield return new WaitUntil(() => op.isDone); _currentRoomScene = null; } public IEnumerator LoadMainMenuCoroutine() { yield return LoadSceneCoroutine(new SceneLoadRequest { SceneName = "MainMenu", EntryTransitionId = null, ShowLoadingScreen = false, IsRespawn = false }); } } }