Files
aibis-dream/Assets/Scripts/SceneManagement/DreamDoorSystem.cs
T
2026-03-06 18:09:15 +08:00

317 lines
9.9 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 AibisDream.Kit;
using AibisDream.UI;
using AibisDream.Utility;
using DG.Tweening;
using UnityEngine;
namespace AibisDream
{
public class DreamDoorSystem : Singleton<DreamDoorSystem>
{
[Header("Door Root")]
[Tooltip("Door 根节点。默认仅 background 和 Frame 显示,整个 Door 初始隐藏。show_door 命令激活后显示。")]
[SerializeField] private Transform doorRoot;
[Header("Door Sprites")]
[SerializeField] private SpriteRenderer glassSea;
[SerializeField] private SpriteRenderer codeSea;
[SerializeField] private SpriteRenderer flashOverlay;
[Header("Terminal(挂在 Door 子节点上即可,无需 Canvas")]
[SerializeField] private DreamTerminalUI terminalUI;
[Header("Morph Settings")]
[SerializeField] private Vector3 seaCollapseScale = new(0.9f, 0.84f, 1f);
[SerializeField] private Ease morphEase = Ease.InOutCubic;
private Transform _codeSeaTransform;
private Vector3 _codeSeaOriginalScale;
private Color _codeSeaOriginalColor;
private Transform _terminalUiTransform;
private Vector3 _terminalUiOriginalScale;
public override void OnSingletonInit()
{
if (doorRoot != null)
doorRoot.gameObject.SetActive(false);
if (glassSea != null)
{
glassSea.SetAlpha(0);
glassSea.gameObject.SetActive(false);
}
if (codeSea != null)
{
codeSea.SetAlpha(0);
codeSea.gameObject.SetActive(false);
_codeSeaTransform = codeSea.transform;
_codeSeaOriginalScale = _codeSeaTransform.localScale;
_codeSeaOriginalColor = codeSea.color;
}
if (flashOverlay != null)
{
flashOverlay.SetAlpha(0);
flashOverlay.gameObject.SetActive(true);
}
if (terminalUI != null)
{
terminalUI.ResetVisualState();
terminalUI.Alpha = 0f;
_terminalUiTransform = terminalUI.transform;
_terminalUiOriginalScale = _terminalUiTransform.localScale;
}
}
/// <summary>
/// 显示整个门(仅 background + FrameGlassSea/CodeSea 保持隐藏直到各自命令调用)
/// </summary>
public IEnumerator ShowDoor(float duration = 0f)
{
if (doorRoot != null)
doorRoot.gameObject.SetActive(true);
if (duration > 0f)
yield return new WaitForSeconds(duration);
}
/// <summary>
/// 隐藏整个门
/// </summary>
public void HideDoor()
{
if (doorRoot != null)
doorRoot.gameObject.SetActive(false);
}
#region Phase 1: GlassSea 浮现
public IEnumerator ShowGlassSea(float duration = 2f)
{
glassSea.gameObject.SetActive(true);
yield return glassSea.DOFade(1f, duration)
.SetEase(Ease.InOutSine)
.WaitForCompletion();
}
public IEnumerator HideGlassSea(float duration = 1f)
{
yield return glassSea.DOFade(0f, duration)
.SetEase(Ease.InOutSine)
.WaitForCompletion();
glassSea.gameObject.SetActive(false);
}
#endregion
#region Phase 2: CodeSea 浮现 (GlassSea 交叉淡出)
public IEnumerator ShowCodeSea(float duration = 2f)
{
codeSea.gameObject.SetActive(true);
var seq = DOTween.Sequence();
seq.Append(codeSea.DOFade(1f, duration).SetEase(Ease.InOutSine));
if (glassSea != null && glassSea.gameObject.activeSelf)
{
seq.Join(glassSea.DOFade(0f, duration * 0.7f).SetEase(Ease.InSine));
}
yield return seq.WaitForCompletion();
if (glassSea != null)
glassSea.gameObject.SetActive(false);
}
#endregion
#region Phase 3: CodeSea 变形为终端
public IEnumerator ShowTerminal()
{
yield return AnimateDoorToTerminal();
if (terminalUI != null)
terminalUI.Begin();
}
private IEnumerator AnimateDoorToTerminal()
{
if (terminalUI != null)
{
terminalUI.ResetVisualState();
terminalUI.Alpha = 0f;
terminalUI.MorphProgress = 0f;
}
if (_terminalUiTransform != null)
_terminalUiTransform.localScale = Vector3.Scale(_terminalUiOriginalScale, new Vector3(1.04f, 1.04f, 1f));
var seq = DOTween.Sequence();
// Step 1: 短暂闪白(CRT 切换感)
if (flashOverlay != null)
{
seq.Append(flashOverlay.DOFade(0.8f, 0.05f));
seq.Append(flashOverlay.DOFade(0f, 0.12f));
}
// Step 2: 海浪内容退场,终端框架在门内成型
if (codeSea != null)
{
codeSea.gameObject.SetActive(true);
seq.Append(codeSea.DOColor(new Color(0.04f, 0.04f, 0.04f, 1f), 0.3f)
.SetEase(Ease.OutSine));
seq.Join(codeSea.DOFade(0f, 0.78f).SetEase(Ease.InSine));
}
if (_codeSeaTransform != null)
{
seq.Join(_codeSeaTransform.DOScale(Vector3.Scale(_codeSeaOriginalScale, seaCollapseScale), 0.78f)
.SetEase(morphEase));
}
if (terminalUI != null)
{
float uiAlpha = 0f;
float morph = 0f;
seq.Join(DOTween.To(() => uiAlpha, v =>
{
uiAlpha = v;
terminalUI.Alpha = v;
}, 1f, 0.24f).SetEase(Ease.OutQuad));
seq.Join(DOTween.To(() => morph, v =>
{
morph = v;
terminalUI.MorphProgress = v;
}, 1f, 0.82f).SetEase(morphEase));
}
if (_terminalUiTransform != null)
{
seq.Join(_terminalUiTransform.DOScale(_terminalUiOriginalScale, 0.82f)
.SetEase(Ease.OutCubic));
}
// Step 3: 第二次微闪(终端稳定)
if (flashOverlay != null)
{
seq.Append(flashOverlay.DOFade(0.5f, 0.03f));
seq.Append(flashOverlay.DOFade(0f, 0.15f));
}
yield return seq.WaitForCompletion();
if (codeSea != null)
codeSea.gameObject.SetActive(false);
}
#endregion
#region 终端结局动效
public IEnumerator PlayShutdownEffect()
{
var target = _terminalUiTransform != null ? _terminalUiTransform : _codeSeaTransform;
if (target == null) yield break;
var seq = DOTween.Sequence();
if (flashOverlay != null)
seq.Append(flashOverlay.DOFade(0.6f, 0.15f));
// 压扁成白线
float scaleY = _terminalUiTransform != null ? _terminalUiOriginalScale.y * 0.02f : 0.005f;
seq.Join(target.DOScaleY(scaleY, 0.35f).SetEase(Ease.OutQuad));
// 横向收缩消失
seq.Append(target.DOScaleX(0f, 0.3f).SetEase(Ease.InQuad));
if (flashOverlay != null)
seq.Join(flashOverlay.DOFade(0f, 0.5f));
// 同步淡出 Shapes 终端
if (terminalUI != null)
{
float a = terminalUI.Alpha;
seq.Join(DOTween.To(() => a, v => { a = v; terminalUI.Alpha = v; }, 0f, 0.4f));
}
yield return seq.WaitForCompletion();
}
public void PlayCrashEffect()
{
var target = _terminalUiTransform != null ? _terminalUiTransform : _codeSeaTransform;
if (target != null)
target.DOShakePosition(1.2f, 0.08f, 35, fadeOut: false);
}
public void StopAllEffects()
{
DOTween.Kill(_codeSeaTransform);
DOTween.Kill(codeSea);
DOTween.Kill(_terminalUiTransform);
DOTween.Kill(flashOverlay);
}
#endregion
#region 清理
public void HideAll()
{
StopAllEffects();
HideDoor();
if (glassSea != null)
{
glassSea.SetAlpha(0);
glassSea.gameObject.SetActive(false);
}
if (codeSea != null)
{
codeSea.color = _codeSeaOriginalColor;
codeSea.SetAlpha(0);
codeSea.gameObject.SetActive(false);
if (_codeSeaTransform != null)
_codeSeaTransform.localScale = _codeSeaOriginalScale;
}
if (terminalUI != null)
{
terminalUI.Alpha = 0f;
terminalUI.ResetVisualState();
}
if (_terminalUiTransform != null)
_terminalUiTransform.localScale = _terminalUiOriginalScale;
if (flashOverlay != null)
flashOverlay.SetAlpha(0);
}
#endregion
#if UNITY_EDITOR
private void OnDrawGizmosSelected()
{
if (codeSea == null) return;
Gizmos.color = new Color(1f, 0.7f, 0f, 0.4f);
var bounds = codeSea.bounds;
Gizmos.DrawWireCube(bounds.center, bounds.size);
Gizmos.color = new Color(0f, 1f, 1f, 0.3f);
Vector3 termSize = new(
bounds.size.x * seaCollapseScale.x,
bounds.size.y * seaCollapseScale.y,
bounds.size.z
);
Gizmos.DrawWireCube(bounds.center, termSize);
}
#endif
}
}