跑通一个版本
This commit is contained in:
@@ -0,0 +1,316 @@
|
||||
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 + Frame,GlassSea/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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user