Files
zeling_v2/Assets/Scripts/Core/GameManager.cs
2026-05-12 15:34:08 +08:00

152 lines
6.6 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System.Collections;
using UnityEngine;
using BaseGames.Core.Events;
using BaseGames.Core.States;
namespace BaseGames.Core
{
/// <summary>
/// 全局游戏管理器。
/// 生命周期Persistent → 第一个执行DefaultExecutionOrder(-1000))。
/// 持有 <see cref="GameStateMachine"/> 并协调所有顶层服务。
/// </summary>
[DefaultExecutionOrder(-1000)]
public class GameManager : MonoBehaviour
{
// ── Inspector 引用 ────────────────────────────────────────────────
[Header("Managers")]
[SerializeField] private SettingsManager _settingsManager;
[Header("Event Channels - Listen")]
[SerializeField] private VoidEventChannelSO _onPlayerDied;
[SerializeField] private VoidEventChannelSO _onPauseRequested;
[SerializeField] private VoidEventChannelSO _onResumeRequested;
[SerializeField] private StringEventChannelSO _onBossFightStarted;
[SerializeField] private BoolEventChannelSO _onBossFightEnded;
[SerializeField] private VoidEventChannelSO _onDeathScreenConfirmed;
[Header("Event Channels - Raise")]
[SerializeField] private BaseEventChannelSO<GameStateId> _onGameStateChanged;
[SerializeField] private VoidEventChannelSO _onPlayerRespawned;
// ── 状态机 ────────────────────────────────────────────────────────
private readonly GameStateMachine _fsm = new GameStateMachine();
private readonly CompositeDisposable _subs = new();
public GameStateId CurrentState => _fsm.CurrentStateId;
private static GameManager _instance;
// ──────────────────────────────────────────────────────────────────
private void Awake()
{
if (_instance != null) { Destroy(gameObject); return; }
_instance = this;
DontDestroyOnLoad(transform.root.gameObject);
RegisterStates();
_settingsManager?.Initialize();
_fsm.TransitionTo(GameStates.Initializing, out _);
}
private void Start()
{
// 在 Start 广播初始状态,确保其他组件已在 OnEnable 中完成订阅。
_onGameStateChanged?.Raise(new Events.GameStateId(GameStates.Initializing.Id));
}
private void OnEnable()
{
_onPlayerDied? .Subscribe(HandlePlayerDied).AddTo(_subs);
_onPauseRequested? .Subscribe(HandlePauseRequested).AddTo(_subs);
_onResumeRequested? .Subscribe(HandleResumeRequested).AddTo(_subs);
_onBossFightStarted? .Subscribe(HandleBossFightStarted).AddTo(_subs);
_onBossFightEnded? .Subscribe(HandleBossFightEnded).AddTo(_subs);
_onDeathScreenConfirmed?.Subscribe(HandleDeathScreenConfirmed).AddTo(_subs);
}
private void OnDisable() => _subs.Clear();
private void OnDestroy()
{
if (_instance == this) _instance = null;
}
private void Update() => _fsm.Tick(Time.deltaTime);
// ── 初始化 ────────────────────────────────────────────────────────
private void RegisterStates()
{
_fsm.Register(new InitializingState());
_fsm.Register(new MainMenuState());
_fsm.Register(new LoadingSceneState());
_fsm.Register(new GameplayState());
_fsm.Register(new BossFightState());
_fsm.Register(new PausedState());
_fsm.Register(new DeadState());
_fsm.Register(new CutsceneState());
_fsm.Register(new GameOverState());
}
// ── 状态转换公共 API ──────────────────────────────────────────────
public bool RequestTransition(GameStateId nextState)
{
if (_fsm.TransitionTo(nextState, out string error))
{
// 通知 UI 等监听者GameStateId in Core.Events 是 string-based
_onGameStateChanged?.Raise(new Events.GameStateId(nextState.Id));
return true;
}
Debug.LogWarning($"[GameManager] {error}");
return false;
}
// ── 事件处理 ──────────────────────────────────────────────────────
private void HandlePlayerDied() => StartCoroutine(DeathFlow());
private void HandlePauseRequested()
{
_prePauseState = _fsm.CurrentStateId;
RequestTransition(GameStates.Paused);
}
private void HandleResumeRequested() => RequestTransition(_prePauseState);
private void HandleBossFightStarted(string bossId)
=> RequestTransition(GameStates.BossFight);
private void HandleBossFightEnded(bool victory)
{
if (victory) RequestTransition(GameStates.Gameplay);
else RequestTransition(GameStates.GameOver);
}
private bool _deathScreenConfirmed;
private GameStateId _prePauseState = GameStates.Gameplay;
private void HandleDeathScreenConfirmed() => _deathScreenConfirmed = true;
private IEnumerator DeathFlow()
{
RequestTransition(GameStates.Dead);
var deathService = ServiceLocator.Get<IDeathRespawnService>();
// SteelSoul 模式:清档后返回主菜单(架构 19 §6
var scaler = ServiceLocator.GetOrDefault<IDifficultyService>()?.CurrentScaler;
if (scaler != null && scaler.InstantDeathOnZeroHP)
{
yield return deathService.StartGameOverCoroutine();
yield break;
}
yield return deathService.StartDeathSequenceCoroutine();
// 等待玩家在死亡画面点击重试
_deathScreenConfirmed = false;
yield return new WaitUntil(() => _deathScreenConfirmed);
yield return deathService.StartRespawnCoroutine();
RequestTransition(GameStates.LoadingScene);
_onPlayerRespawned?.Raise();
}
}
}