梦境表现跑通

This commit is contained in:
2026-03-06 22:38:17 +08:00
parent 3fdca23cd3
commit 508eddee47
8 changed files with 3660 additions and 3252 deletions
+165 -60
View File
@@ -17,25 +17,58 @@ namespace AibisDream
[SerializeField] private SpriteRenderer glassSea;
[SerializeField] private SpriteRenderer codeSea;
[SerializeField] private SpriteRenderer flashOverlay;
[Tooltip("仅放门的静态 background,不要把 glassSea/codeSea/overlay 拖进来。")]
[SerializeField] private Renderer[] backgroundRenderers;
[SerializeField] private Renderer[] frameRenderers;
[SerializeField] private SpriteRenderer sceneBlackOverlay;
[Header("Terminal(挂在 Door 子节点上即可,无需 Canvas")]
[SerializeField] private DreamTerminalUI terminalUI;
[Header("Morph Settings")]
[Tooltip("负责门壳贴合的节点;不填则退回到 doorRoot。")]
[SerializeField] private Transform doorShellTransform;
[Tooltip("线框先贴合的图片目标。建议拖一个 SpriteRenderer 作为参考形状。")]
[SerializeField] private SpriteRenderer terminalShapeReference;
[SerializeField] private Vector3 seaCollapseScale = new(0.9f, 0.84f, 1f);
[SerializeField] private Vector3 doorSnapScale = new(0.95f, 1.06f, 1f);
[SerializeField] private Ease morphEase = Ease.InOutCubic;
[SerializeField] private FrameHidePhase frameHidePhase = FrameHidePhase.OnTerminal;
[SerializeField] private float doorSnapDuration = 0.2f;
[SerializeField] private float backgroundCutDelay = 0.04f;
[SerializeField] private float preMorphHoldDuration = 0.16f;
[SerializeField] private float postMorphBootDelay = 0.12f;
[SerializeField] private float referenceSnapMorphProgress = 0.08f;
[SerializeField] private Vector2 referenceSnapPadding = new(0.18f, 0.18f);
[SerializeField] private float blackoutAlpha = 0.92f;
[SerializeField] private float blackoutFadeInDuration = 0.08f;
[SerializeField] private float blackoutFadeOutDuration = 0.12f;
private Transform _codeSeaTransform;
private Vector3 _codeSeaOriginalScale;
private Color _codeSeaOriginalColor;
private Transform _terminalUiTransform;
private Vector3 _terminalUiOriginalScale;
private Vector3 _terminalUiOriginalLocalPosition;
private Transform _doorShellTransform;
private Vector3 _doorShellOriginalScale;
private enum FrameHidePhase
{
Never,
OnCodeSea,
OnTerminal
}
public override void OnSingletonInit()
{
if (doorRoot != null)
doorRoot.gameObject.SetActive(false);
_doorShellTransform = doorShellTransform != null ? doorShellTransform : doorRoot;
if (_doorShellTransform != null)
_doorShellOriginalScale = _doorShellTransform.localScale;
if (glassSea != null)
{
glassSea.SetAlpha(0);
@@ -57,12 +90,19 @@ namespace AibisDream
flashOverlay.gameObject.SetActive(true);
}
if (sceneBlackOverlay != null)
{
sceneBlackOverlay.SetAlpha(0);
sceneBlackOverlay.gameObject.SetActive(true);
}
if (terminalUI != null)
{
terminalUI.ResetVisualState();
terminalUI.Alpha = 0f;
_terminalUiTransform = terminalUI.transform;
_terminalUiOriginalScale = _terminalUiTransform.localScale;
_terminalUiOriginalLocalPosition = _terminalUiTransform.localPosition;
}
}
@@ -74,6 +114,10 @@ namespace AibisDream
if (doorRoot != null)
doorRoot.gameObject.SetActive(true);
SetBackgroundVisible(true);
SetFrameVisible(true);
ResetDoorShellScale();
if (duration > 0f)
yield return new WaitForSeconds(duration);
}
@@ -112,6 +156,8 @@ namespace AibisDream
public IEnumerator ShowCodeSea(float duration = 2f)
{
codeSea.gameObject.SetActive(true);
if (frameHidePhase == FrameHidePhase.OnCodeSea)
SetFrameVisible(false);
var seq = DOTween.Sequence();
seq.Append(codeSea.DOFade(1f, duration).SetEase(Ease.InOutSine));
@@ -134,78 +180,59 @@ namespace AibisDream
{
yield return AnimateDoorToTerminal();
if (terminalUI != null)
{
if (postMorphBootDelay > 0f)
yield return new WaitForSeconds(postMorphBootDelay);
terminalUI.Begin();
}
}
private IEnumerator AnimateDoorToTerminal()
{
StopAllEffects();
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));
terminalUI.Alpha = 1f;
}
if (_terminalUiTransform != null)
{
seq.Join(_terminalUiTransform.DOScale(_terminalUiOriginalScale, 0.82f)
.SetEase(Ease.OutCubic));
_terminalUiTransform.localPosition = _terminalUiOriginalLocalPosition;
_terminalUiTransform.localScale = _terminalUiOriginalScale;
}
// Step 3: 第二次微闪(终端稳定)
if (flashOverlay != null)
{
seq.Append(flashOverlay.DOFade(0.5f, 0.03f));
seq.Append(flashOverlay.DOFade(0f, 0.15f));
}
SetBackgroundVisible(false);
SetFrameVisible(false);
yield return seq.WaitForCompletion();
if (glassSea != null)
glassSea.gameObject.SetActive(false);
if (codeSea != null)
codeSea.gameObject.SetActive(false);
if (flashOverlay != null)
flashOverlay.SetAlpha(0f);
if (sceneBlackOverlay != null)
sceneBlackOverlay.SetAlpha(0f);
if (preMorphHoldDuration > 0f)
yield return new WaitForSeconds(preMorphHoldDuration);
if (terminalUI != null)
{
float morph = 0f;
yield return DOTween.To(() => morph, v =>
{
morph = v;
terminalUI.MorphProgress = v;
}, 1f, 0.82f).SetEase(morphEase).WaitForCompletion();
}
ResetDoorShellScale();
}
#endregion
@@ -231,13 +258,6 @@ namespace AibisDream
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();
}
@@ -253,7 +273,9 @@ namespace AibisDream
DOTween.Kill(_codeSeaTransform);
DOTween.Kill(codeSea);
DOTween.Kill(_terminalUiTransform);
DOTween.Kill(_doorShellTransform);
DOTween.Kill(flashOverlay);
DOTween.Kill(sceneBlackOverlay);
}
#endregion
@@ -264,6 +286,9 @@ namespace AibisDream
{
StopAllEffects();
HideDoor();
SetBackgroundVisible(true);
SetFrameVisible(true);
ResetDoorShellScale();
if (glassSea != null)
{
@@ -287,14 +312,87 @@ namespace AibisDream
}
if (_terminalUiTransform != null)
{
_terminalUiTransform.localPosition = _terminalUiOriginalLocalPosition;
_terminalUiTransform.localScale = _terminalUiOriginalScale;
}
if (flashOverlay != null)
flashOverlay.SetAlpha(0);
if (sceneBlackOverlay != null)
sceneBlackOverlay.SetAlpha(0);
}
#endregion
private void SetFrameVisible(bool visible)
{
if (frameRenderers == null) return;
foreach (var frameRenderer in frameRenderers)
{
if (frameRenderer != null)
frameRenderer.enabled = visible;
}
}
private void SetBackgroundVisible(bool visible)
{
if (backgroundRenderers == null) return;
foreach (var backgroundRenderer in backgroundRenderers)
{
if (backgroundRenderer != null)
backgroundRenderer.enabled = visible;
}
}
private void ResetDoorShellScale()
{
if (_doorShellTransform != null)
_doorShellTransform.localScale = _doorShellOriginalScale;
}
private bool HasShapeReference()
{
return terminalShapeReference != null && terminalUI != null && _terminalUiTransform != null;
}
private void FitTerminalFrameToReference()
{
if (!HasShapeReference())
return;
var bounds = terminalShapeReference.bounds;
var targetLocalPosition = _terminalUiTransform.parent != null
? _terminalUiTransform.parent.InverseTransformPoint(bounds.center)
: bounds.center;
_terminalUiTransform.localPosition = new Vector3(
targetLocalPosition.x,
targetLocalPosition.y,
_terminalUiOriginalLocalPosition.z
);
Vector2 baseSize = terminalUI.EvaluateFrameSize(referenceSnapMorphProgress);
float targetWidth = Mathf.Max(0.01f, bounds.size.x + referenceSnapPadding.x);
float targetHeight = Mathf.Max(0.01f, bounds.size.y + referenceSnapPadding.y);
Vector3 parentLossyScale = _terminalUiTransform.parent != null ? _terminalUiTransform.parent.lossyScale : Vector3.one;
float parentScaleX = Mathf.Max(0.0001f, Mathf.Abs(parentLossyScale.x));
float parentScaleY = Mathf.Max(0.0001f, Mathf.Abs(parentLossyScale.y));
float localScaleX = targetWidth / Mathf.Max(0.0001f, baseSize.x * parentScaleX);
float localScaleY = targetHeight / Mathf.Max(0.0001f, baseSize.y * parentScaleY);
_terminalUiTransform.localScale = new Vector3(
Mathf.Sign(_terminalUiOriginalScale.x) * localScaleX,
Mathf.Sign(_terminalUiOriginalScale.y) * localScaleY,
_terminalUiOriginalScale.z
);
}
#if UNITY_EDITOR
private void OnDrawGizmosSelected()
{
@@ -303,6 +401,13 @@ namespace AibisDream
var bounds = codeSea.bounds;
Gizmos.DrawWireCube(bounds.center, bounds.size);
if (terminalShapeReference != null)
{
Gizmos.color = new Color(1f, 1f, 1f, 0.45f);
var referenceBounds = terminalShapeReference.bounds;
Gizmos.DrawWireCube(referenceBounds.center, referenceBounds.size);
}
Gizmos.color = new Color(0f, 1f, 1f, 0.3f);
Vector3 termSize = new(
bounds.size.x * seaCollapseScale.x,