Files
gold_dolphin/unity/Assets/UI/GameManager.cs
T
2026-07-04 16:15:57 +08:00

166 lines
5.8 KiB
C#

using System;
using System.Collections;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using IndianOceanAssets.Engine2_5D;
namespace GameFramework
{
/// <summary>
/// 全局游戏状态管理器(持久化单例)。
/// 维护 GameState,提供 GameOver / Win 触发入口与对应事件。
/// </summary>
public class GameManager : PersistentSingleton<GameManager>
{
/// <summary>游戏结束(失败)时触发。</summary>
public static Action onGameOver;
/// <summary>游戏胜利时触发。</summary>
public static Action onGameWin;
public static GameState GameState
{
get => Instance.gameState;
set => Instance.gameState = value;
}
[SerializeField] private GameState gameState = GameState.Playing;
[Header("过场动画")]
[Tooltip("光源扩大的持续时间(秒)")]
[SerializeField] private float lightExpandDuration = 1.5f;
[Tooltip("光源扩大目标半径")]
[SerializeField] private float lightExpandTargetRadius = 20f;
[Tooltip("淡出持续时间(秒)")]
[SerializeField] private float fadeOutDuration = 1f;
/// <summary>触发游戏失败:设状态 + 触发事件 + 播放过场动画。</summary>
public static void GameOver()
{
if (Instance == null) return;
GameState = GameState.GameOver;
onGameOver?.Invoke();
Instance.StartCoroutine(Instance.DeathTransition());
}
/// <summary>触发游戏胜利:设状态 + 触发事件 + 播放过场动画。</summary>
public static void Win()
{
if (Instance == null) return;
GameState = GameState.Victory;
onGameWin?.Invoke();
Instance.StartCoroutine(Instance.VictoryTransition());
}
/// <summary>
/// 死亡过场协程:禁用控制 → 光源放大 → 淡出 → 跳转 Scoring。
/// 使用 unscaledDeltaTime 确保不受 timeScale 影响。
/// </summary>
private IEnumerator DeathTransition()
{
// 等待一帧,让 HUD 先更新血量显示(最后一滴血消失)
yield return null;
// 1. 查找玩家并禁用控制
var player = GameObject.FindGameObjectWithTag("Player");
if (player != null)
{
// 禁用玩家移动
var playerController = player.GetComponent<PlayerController>();
if (playerController != null) playerController.enabled = false;
// 禁用相机跟随
var camFollow = Camera.main != null ? Camera.main.GetComponent<CameraFollow>() : null;
if (camFollow != null) camFollow.enabled = false;
// 2. 光源扩大
var lightSource = player.GetComponent<LightSource>();
if (lightSource != null)
{
float startRadius = lightSource.Radius;
float elapsed = 0f;
while (elapsed < lightExpandDuration)
{
elapsed += Time.unscaledDeltaTime;
float t = Mathf.Clamp01(elapsed / lightExpandDuration);
float smoothT = t * t * (3f - 2f * t); // SmoothStep
lightSource.SetRadius(Mathf.Lerp(startRadius, lightExpandTargetRadius, smoothT));
yield return null;
}
lightSource.SetRadius(lightExpandTargetRadius);
}
else
{
// 没有光源,等待同样时间
yield return new WaitForSecondsRealtime(lightExpandDuration);
}
}
else
{
// 没有玩家,等待同样时间
yield return new WaitForSecondsRealtime(lightExpandDuration);
}
// 3. 淡出到黑色
yield return StartCoroutine(FadeOutAndLoad());
}
/// <summary>
/// 胜利过场协程(与死亡相同,可后续扩展不同效果)。
/// </summary>
private IEnumerator VictoryTransition()
{
// 胜利也使用相同的光源扩散 + 淡出效果
yield return DeathTransition();
}
/// <summary>
/// 创建全屏黑色遮罩并淡出,然后加载 Scoring 场景。
/// </summary>
private IEnumerator FadeOutAndLoad()
{
// 创建全屏黑色遮罩
var canvasObj = new GameObject("FadeOverlay");
var canvas = canvasObj.AddComponent<Canvas>();
canvas.renderMode = RenderMode.ScreenSpaceOverlay;
canvas.sortingOrder = 99999;
canvasObj.AddComponent<CanvasScaler>();
var overlay = canvasObj.AddComponent<Image>();
overlay.color = new Color(0, 0, 0, 0);
// 淡出到黑色
float elapsed = 0f;
while (elapsed < fadeOutDuration)
{
elapsed += Time.unscaledDeltaTime;
float t = Mathf.Clamp01(elapsed / fadeOutDuration);
overlay.color = new Color(0, 0, 0, t);
yield return null;
}
overlay.color = new Color(0, 0, 0, 1);
// 等待一帧确保淡出渲染完成
yield return null;
// 加载 Scoring 场景(直接使用 SceneManager,避免 SceneLoader 的异步加载可能卡住)
Debug.Log("[GameManager] 过场完成,正在加载 Scoring 场景...");
SceneManager.LoadScene("Scoring");
}
}
public enum GameState
{
Playing,
Paused,
GameOver,
Victory,
Scoring
}
}