Files
zeling_v2/Assets/_Game/Scripts/UI/Splash/SplashScreenController.cs
2026-05-19 23:20:44 +08:00

139 lines
5.8 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;
namespace BaseGames.UI.Splash
{
/// <summary>
/// 游戏启动 Logo 演出控制器。挂载在 Persistent 场景的 Canvas_Splash 根节点。
///
/// 演出顺序:工作室 Logo 淡入 → 停留 → 淡出 → 游戏标题淡入 → 停留 → 黑幕整体淡出。
/// 任意按键 / 手柄键可跳过整段演出。
///
/// 与 Core 程序集完全解耦:
/// 监听 EVT_SplashStartRequestVoidEventChannelSO→ 开始演出。
/// 完成后发布 EVT_SplashCompleteVoidEventChannelSO→ 通知 BootSequencer 继续。
/// </summary>
public class SplashScreenController : MonoBehaviour
{
[Header("Canvas Groups")]
[Tooltip("整个 Splash 画布的根节点 CanvasGroup用于整体淡出黑幕")]
[SerializeField] private CanvasGroup _splashRoot;
[Tooltip("工作室 Logo CanvasGroup")]
[SerializeField] private CanvasGroup _studioLogoGroup;
[Tooltip("游戏标题 Logo CanvasGroup")]
[SerializeField] private CanvasGroup _gameTitleGroup;
[Header("时序(秒)")]
[SerializeField] private float _fadeInDuration = 0.8f;
[SerializeField] private float _holdDuration = 1.5f;
[SerializeField] private float _fadeOutDuration = 0.6f;
[SerializeField] private float _stageGapDuration = 0.3f;
[Header("Event Channels")]
[SerializeField] private VoidEventChannelSO _onSplashStartRequest; // Listen
[SerializeField] private VoidEventChannelSO _onSplashComplete; // Raise
private bool _skipRequested;
private readonly CompositeDisposable _subs = new();
// ── 生命周期 ─────────────────────────────────────────────────────────
private void Awake()
{
// 初始态:根节点完全不透明(充当开场黑幕),各 Logo 完全透明
SetAlpha(_splashRoot, 1f, blocksRaycasts: true);
SetAlpha(_studioLogoGroup, 0f, blocksRaycasts: false);
SetAlpha(_gameTitleGroup, 0f, blocksRaycasts: false);
}
private void OnEnable() => _onSplashStartRequest?.Subscribe(OnStartRequested).AddTo(_subs);
private void OnDisable() => _subs.Clear();
// ── 入口 ─────────────────────────────────────────────────────────────
private void OnStartRequested() => StartCoroutine(PlayAndNotify());
private IEnumerator PlayAndNotify()
{
yield return StartCoroutine(PlayAsync());
_onSplashComplete?.Raise();
}
// ── 演出主逻辑 ───────────────────────────────────────────────────────
private IEnumerator PlayAsync()
{
_skipRequested = false;
// Stage 1工作室 Logo
if (_studioLogoGroup != null)
{
yield return StartCoroutine(FadeGroup(_studioLogoGroup, 0f, 1f, _fadeInDuration));
yield return StartCoroutine(WaitOrSkip(_holdDuration));
yield return StartCoroutine(FadeGroup(_studioLogoGroup, 1f, 0f, _fadeOutDuration));
}
if (!_skipRequested)
yield return new WaitForSecondsRealtime(_stageGapDuration);
// Stage 2游戏标题
if (_gameTitleGroup != null)
{
yield return StartCoroutine(FadeGroup(_gameTitleGroup, 0f, 1f, _fadeInDuration));
yield return StartCoroutine(WaitOrSkip(_holdDuration));
yield return StartCoroutine(FadeGroup(_gameTitleGroup, 1f, 0f, _fadeOutDuration));
}
// 黑幕整体淡出(显露主菜单场景)
yield return StartCoroutine(FadeGroup(_splashRoot, 1f, 0f, _fadeOutDuration));
if (_splashRoot != null)
_splashRoot.blocksRaycasts = false;
gameObject.SetActive(false);
}
// ── Unity 输入(任意按键跳过)────────────────────────────────────────
private void Update()
{
if (Input.anyKeyDown)
_skipRequested = true;
}
// ── 内部工具 ─────────────────────────────────────────────────────────
private IEnumerator FadeGroup(CanvasGroup group, float from, float to, float duration)
{
if (group == null) yield break;
group.alpha = from;
float elapsed = 0f;
while (elapsed < duration && !_skipRequested)
{
group.alpha = Mathf.Lerp(from, to, elapsed / duration);
elapsed += Time.unscaledDeltaTime;
yield return null;
}
group.alpha = to;
}
private IEnumerator WaitOrSkip(float duration)
{
float elapsed = 0f;
while (elapsed < duration && !_skipRequested)
{
elapsed += Time.unscaledDeltaTime;
yield return null;
}
}
private static void SetAlpha(CanvasGroup group, float alpha, bool blocksRaycasts)
{
if (group == null) return;
group.alpha = alpha;
group.blocksRaycasts = blocksRaycasts;
}
}
}