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