diff --git a/Assets/Scripts/MiniGame/HuoShan/Language/LanguageParticleManager.cs b/Assets/Scripts/MiniGame/HuoShan/Language/LanguageParticleManager.cs
index 3c8735f27..c7f07abf0 100644
--- a/Assets/Scripts/MiniGame/HuoShan/Language/LanguageParticleManager.cs
+++ b/Assets/Scripts/MiniGame/HuoShan/Language/LanguageParticleManager.cs
@@ -1623,6 +1623,98 @@ namespace AibisDream.MiniGame.Language
.SetTarget(this);
}
+ ///
+ /// 真话聚合挣扎(非等待):向 target 推进的途中反复"够到一点又被拽回去"。
+ /// 回抽幅度必须跨过 UpdateTruthGatherLock 的 0.08 解锁带,已锁的字才会崩开重新乱跳——
+ /// 挣扎感来自进度曲线本身的往复,不依赖任何颜色或额外特效。
+ ///
+ /// 最终停留的聚合进度
+ /// 整段时长
+ /// 回抽次数;<=0 时退化为普通聚合
+ public void BeginTruthStrain(float target, float duration, int tugs)
+ {
+ if (completionPhase != CompletionPhase.FocusHolding)
+ {
+ Debug.LogWarning(
+ $"[LanguageParticleManager] 真话挣扎在 {completionPhase} 状态被调用;已安全跳过。");
+ return;
+ }
+
+ int tugCount = Mathf.Clamp(tugs, 0, 4);
+ if (tugCount <= 0)
+ {
+ BeginTruthGather(target, duration);
+ return;
+ }
+
+ float clampedTarget = Mathf.Clamp01(target);
+ float start = truthGatherProgress;
+ float total = Mathf.Max(0.2f, duration);
+ // 末尾留一段单纯的推进,让整句最后停在 target 而不是停在回抽底部
+ float settleDuration = total * 0.18f;
+ float cycleDuration = (total - settleDuration) / tugCount;
+ float pushDuration = Mathf.Max(0.05f, cycleDuration * 0.72f);
+ float recoilDuration = Mathf.Max(0.04f, cycleDuration - pushDuration);
+
+ DOTween.Kill(TruthGatherTweenId);
+ Sequence sequence = DOTween.Sequence().SetId(TruthGatherTweenId).SetTarget(this);
+ for (int i = 1; i <= tugCount; i++)
+ {
+ // 每次比上一次够得更远,最后一次刚好摸到 target 再被拽回来
+ float peak = Mathf.Lerp(start, clampedTarget, i / (float)tugCount);
+ // 回抽越往后越狠;下限 0.1 保证越过 0.08 解锁带
+ float recoil = 0.10f + 0.03f * (i - 1);
+ float valley = Mathf.Max(0f, peak - recoil);
+
+ sequence.Append(
+ DOTween.To(
+ () => truthGatherProgress,
+ value => truthGatherProgress = value,
+ peak,
+ pushDuration)
+ .SetEase(Ease.OutCubic));
+ sequence.Append(
+ DOTween.To(
+ () => truthGatherProgress,
+ value => truthGatherProgress = value,
+ valley,
+ recoilDuration)
+ .SetEase(Ease.OutExpo));
+ }
+
+ sequence.Append(
+ DOTween.To(
+ () => truthGatherProgress,
+ value => truthGatherProgress = value,
+ clampedTarget,
+ Mathf.Max(0.05f, settleDuration))
+ .SetEase(Ease.OutCubic));
+ }
+
+ ///
+ /// 真话聚合崩塌(非等待):进度被一口气拽回 0,所有已锁的字沿原路退回悬浮位并恢复乱跳。
+ /// Ease.InBack 会先向上顶一点点再垮掉——"又够了一下下,然后整个塌了"。
+ ///
+ public void CollapseTruthGather(float duration)
+ {
+ if (completionPhase != CompletionPhase.FocusHolding)
+ {
+ Debug.LogWarning(
+ $"[LanguageParticleManager] 真话崩塌在 {completionPhase} 状态被调用;已安全跳过。");
+ return;
+ }
+
+ DOTween.Kill(TruthGatherTweenId);
+ DOTween.To(
+ () => truthGatherProgress,
+ value => truthGatherProgress = value,
+ 0f,
+ Mathf.Max(0.08f, duration))
+ .SetEase(Ease.InBack)
+ .SetId(TruthGatherTweenId)
+ .SetTarget(this);
+ }
+
/// 真话聚合被打断:目标字向外爆散并恢复乱跳(非等待)。
public void ScatterTruthGather(float burstDistance)
{
diff --git a/Assets/Scripts/MiniGame/HuoShan/Language/LanguageYarnCommand.cs b/Assets/Scripts/MiniGame/HuoShan/Language/LanguageYarnCommand.cs
index e40a76deb..3bdd58140 100644
--- a/Assets/Scripts/MiniGame/HuoShan/Language/LanguageYarnCommand.cs
+++ b/Assets/Scripts/MiniGame/HuoShan/Language/LanguageYarnCommand.cs
@@ -337,34 +337,6 @@ namespace AibisDream.MiniGame.Language
presentation.SqueezeTruthCharacters(duration, jitter, alpha);
}
- [YarnCommand("expression_lie_show")]
- public static void ExpressionLieShow(string keyword, float duration, float characterSpacing)
- {
- if (TryGetPresentation(out LogReleasePresentationController presentation))
- presentation.ShowLieKeyword(keyword, duration, characterSpacing);
- }
-
- [YarnCommand("expression_scanline")]
- public static void ExpressionScanline(float duration, bool stalled)
- {
- if (TryGetPresentation(out LogReleasePresentationController presentation))
- presentation.PlayScreenScanline(duration, stalled);
- }
-
- [YarnCommand("expression_system_message")]
- public static void ExpressionSystemMessage(string value, string style, float fadeDuration)
- {
- if (TryGetPresentation(out LogReleasePresentationController presentation))
- presentation.ShowSystemMessage(value, style, fadeDuration);
- }
-
- [YarnCommand("expression_system_message_hide")]
- public static void ExpressionSystemMessageHide(float fadeDuration)
- {
- if (TryGetPresentation(out LogReleasePresentationController presentation))
- presentation.HideSystemMessage(fadeDuration);
- }
-
[YarnCommand("expression_lie_crack_begin")]
public static void ExpressionLieCrackBegin(float lieAlpha)
{
@@ -420,8 +392,41 @@ namespace AibisDream.MiniGame.Language
presentation.ScatterTruthGatherAttempt(burst);
}
+ ///
+ /// 真话聚合挣扎(非阻塞):向 target 推进的途中反复"够到一点又被拽回去",
+ /// 已锁的字会崩开重新乱跳。挣扎感来自聚合曲线本身,不使用任何颜色或额外特效。
+ /// <>
+ ///
+ /// 最终停留的聚合进度
+ /// 整段时长
+ /// 回抽次数(0~4);<=0 时退化为 expression_truth_gather
+ [YarnCommand("expression_truth_strain")]
+ public static void ExpressionTruthStrain(float target = 0.85f, float duration = 3f, float tugs = 2f)
+ {
+ if (TryGetPresentation(out LogReleasePresentationController presentation))
+ {
+ presentation.BeginTruthStrainAttempt(
+ target,
+ duration,
+ UnityEngine.Mathf.RoundToInt(tugs));
+ }
+ }
+
+ ///
+ /// 真话聚合崩塌(非阻塞):进度被一口气拽回 0,字沿原路退回悬浮位并恢复乱跳。
+ /// 与 expression_truth_scatter 的区别:scatter 是径向爆散,collapse 是"被拽回去"。
+ /// <>
+ ///
+ [YarnCommand("expression_truth_collapse")]
+ public static void ExpressionTruthCollapse(float duration = 0.45f)
+ {
+ if (TryGetPresentation(out LogReleasePresentationController presentation))
+ presentation.CollapseTruthGatherAttempt(duration);
+ }
+
///
/// 火山脸错误闪红(非阻塞):聚合失败时短暂替换红屏 Sprite,随后恢复,并轻微下沉。
+ /// 注意:LOG1/LOG2 的失败信号已明确不使用红色与脸部报错,此命令仅保留兼容。
/// <>
///
[YarnCommand("expression_face_error")]
@@ -691,6 +696,27 @@ namespace AibisDream.MiniGame.Language
presentation.PlayGlitchPulse(peak, riseDuration, fallDuration);
}
+ ///
+ /// 火山「屏幕」Sprite 直驱撕裂花屏(非阻塞)。作用在屏幕材质,不是叠一层噪波。
+ /// 是 0–1 的目标档位, 是推到该档位的时间;
+ /// 到位后一直保持(Shader 自带憋气/发力循环,不会变成静止花屏),要收掉就再调一次 level=0。
+ /// <> … <>
+ ///
+ [YarnCommand("expression_screen_glitch")]
+ public static void ExpressionScreenGlitch(
+ float level = 0.5f,
+ float duration = 1f)
+ {
+ if (ExpressionManager == null)
+ {
+ UnityEngine.Debug.LogError(
+ "[LanguageYarnCommand] expression_screen_glitch 找不到 ExpressionManager;已安全跳过。");
+ return;
+ }
+
+ ExpressionManager.SetScreenGlitchLevel(level, duration);
+ }
+
///
/// 用现有目标粒子完整显示一个红色攻击词,并等待确定性的冲击动作结束。
/// 超过目标粒子数量时会安全跳过,不会截断。
diff --git a/Assets/Scripts/MiniGame/HuoShan/Language/LogReleasePresentationController.cs b/Assets/Scripts/MiniGame/HuoShan/Language/LogReleasePresentationController.cs
index 50ced39bf..324ae765f 100644
--- a/Assets/Scripts/MiniGame/HuoShan/Language/LogReleasePresentationController.cs
+++ b/Assets/Scripts/MiniGame/HuoShan/Language/LogReleasePresentationController.cs
@@ -9,8 +9,8 @@ using UnityEngine;
namespace AibisDream.MiniGame.Language
{
///
- /// Owns the post-output performance for Huoshan's three blocked logs. Memory effects
- /// stay on their own SpriteRenderers, while the opaque face and dialogue UI remain clean.
+ /// Owns the post-output performance for Huoshan's three blocked logs. All memory
+ /// distortion lives on the HuoshanMemory material; face / dialogue stay clean.
///
public sealed class LogReleasePresentationController : MonoBehaviour
{
@@ -71,6 +71,7 @@ namespace AibisDream.MiniGame.Language
[SerializeField] private LanguageParticleManager particleManager;
[SerializeField] private SpriteRenderer faceRenderer;
[SerializeField] private Sprite errorFaceSprite;
+ [Tooltip("可选。记忆演出不再驱动 noise;仅在进入/退出时清零遗留 Intensity,避免 glitch_transition 残留。")]
[SerializeField] private SpriteNoiseGlitchController glitchController;
[SerializeField] private RectTransform expressionScreenMaskRect;
[SerializeField] private TMP_FontAsset screenFont;
@@ -82,10 +83,10 @@ namespace AibisDream.MiniGame.Language
[SerializeField] private Material memoryMaterial;
[Header("Memory Simulation")]
- [Tooltip("三档演出预设下记忆的轻微失真强度;随记忆透明度一起浮现。")]
- [SerializeField, Range(0f, 1f)] private float simGlitchLight = 0.20f;
- [SerializeField, Range(0f, 1f)] private float simGlitchMedium = 0.26f;
- [SerializeField, Range(0f, 1f)] private float simGlitchHeavy = 0.32f;
+ [Tooltip("三档演出预设下记忆材质的轻微失真强度;随记忆透明度一起浮现。")]
+ [SerializeField, Range(0f, 1f)] private float simGlitchLight = 0.28f;
+ [SerializeField, Range(0f, 1f)] private float simGlitchMedium = 0.36f;
+ [SerializeField, Range(0f, 1f)] private float simGlitchHeavy = 0.44f;
[Header("Timing")]
[SerializeField, Min(0.01f)] private float faceFadeDuration = 0.45f;
@@ -145,7 +146,6 @@ namespace AibisDream.MiniGame.Language
private int actorFlashCount;
private Coroutine actorOverdriveRoutine;
private Coroutine actorFlashLoopRoutine;
-
private Texture2D runtimeWhiteTexture;
private Sprite runtimeWhiteSprite;
private MaterialPropertyBlock memoryBlockA;
@@ -158,6 +158,7 @@ namespace AibisDream.MiniGame.Language
private float vignette;
private float noise;
private float simGlitch;
+ private float memoryBaseSimGlitch;
private float horizontalTear;
private float memoryImpact;
private float memoryDamage;
@@ -279,12 +280,7 @@ namespace AibisDream.MiniGame.Language
state = PresentationState.FaceEntering;
// 梳理完成起:目标字切到白色(并取消加粗),玩法阶段颜色不受影响。
particleManager?.ApplyPresentationResolvedVisuals(presentationResolvedColor);
- if (glitchController != null)
- {
- glitchController.SetCompositeMode(SpriteNoiseGlitchController.CompositeMode.TransparentOverlay);
- glitchController.Intensity = 0f;
- glitchController.SetAmbientNoise(0f, 320f, 0f);
- }
+ SilenceNoiseOverlayIfPresent();
if (faceRenderer == null)
{
@@ -346,15 +342,9 @@ namespace AibisDream.MiniGame.Language
state = PresentationState.Memory;
// 兜底:跳过 face_fade_in 直进记忆时,目标字仍切到演出白。
particleManager?.ApplyPresentationResolvedVisuals(presentationResolvedColor);
-
- if (glitchController != null)
- {
- glitchController.SetCompositeMode(SpriteNoiseGlitchController.CompositeMode.TransparentOverlay);
- if (!preserveGlitch)
- glitchController.Intensity = 0f;
- glitchController.SetAmbientNoise(0f, 320f, 0f);
- glitchController.ClearCalmField(true);
- }
+ // 记忆失真全部走 HuoshanMemory 材质;清掉 noise 叠层残留。
+ _ = preserveGlitch;
+ SilenceNoiseOverlayIfPresent();
SpriteRenderer incoming = activeMemoryRenderer == memoryRendererA ? memoryRendererB : memoryRendererA;
SpriteRenderer outgoing = activeMemoryRenderer;
@@ -488,16 +478,20 @@ namespace AibisDream.MiniGame.Language
DOTween.Kill(this);
float duration = Mathf.Max(0.01f, freezeDuration);
// 谎话期间把模拟感压到目标值:记忆被伪装得"过分干净"。
- DOTween.To(() => simGlitch, value => simGlitch = value, Mathf.Clamp01(noiseTarget), duration)
+ float resolved = Mathf.Clamp01(noiseTarget);
+ memoryBaseSimGlitch = resolved;
+ DOTween.To(() => simGlitch, value => simGlitch = value, resolved, duration)
.SetEase(Ease.OutQuad)
.SetTarget(this);
}
- /// 调节记忆的轻微失真扰动(非等待)。
+ /// 调节记忆材质的轻微失真扰动(非等待)。
public void SetSimulationGlitch(float target, float duration)
{
EnsureRuntimeObjects();
- DOTween.To(() => simGlitch, value => simGlitch = value, Mathf.Clamp01(target), Mathf.Max(0.01f, duration))
+ float resolved = Mathf.Clamp01(target);
+ memoryBaseSimGlitch = resolved;
+ DOTween.To(() => simGlitch, value => simGlitch = value, resolved, Mathf.Max(0.01f, duration))
.SetEase(Ease.OutQuad)
.SetTarget(this);
}
@@ -705,14 +699,7 @@ namespace AibisDream.MiniGame.Language
DisableMemoryRenderer(memoryRendererB);
activeMemoryRenderer = null;
StopTruthLieFlicker();
-
- if (glitchController != null)
- {
- glitchController.Intensity = 0f;
- glitchController.SetAmbientNoise(0f, 320f, 0f);
- glitchController.ClearCalmField(true);
- glitchController.SetCompositeMode(SpriteNoiseGlitchController.CompositeMode.TransparentOverlay);
- }
+ SilenceNoiseOverlayIfPresent();
}
///
@@ -772,10 +759,8 @@ namespace AibisDream.MiniGame.Language
Mathf.Lerp(0.26f, 0.16f, flashProgress)));
try
{
- if (glitchController != null)
- {
+ if (resolvedGlitchPeak > 0.001f)
StartCoroutine(PulseGlitch(resolvedGlitchPeak, 0.04f, 0.14f));
- }
particleManager?.SetTargetParticlesAlpha(0f, 0f);
@@ -960,13 +945,10 @@ namespace AibisDream.MiniGame.Language
Mathf.Max(0.05f, duration),
Mathf.Max(0.02f, interval),
truthCharacters));
- if (glitchController != null)
- {
- StartCoroutine(PulseGlitch(
- 0.64f,
- Mathf.Max(0.05f, duration * 0.82f),
- Mathf.Max(0.05f, duration * 0.18f)));
- }
+ StartCoroutine(PulseGlitch(
+ 0.64f,
+ Mathf.Max(0.05f, duration * 0.82f),
+ Mathf.Max(0.05f, duration * 0.18f)));
}
public IEnumerator PlayActorWordHit(
@@ -1113,9 +1095,6 @@ namespace AibisDream.MiniGame.Language
effectStrength = Mathf.Clamp01(peripheral);
calmRadius = Mathf.Clamp01(calmTarget);
particleManager?.SnapTruthImmediate();
-
- if (glitchController != null)
- glitchController.Intensity = 0f;
state = PresentationState.TruthHolding;
}
@@ -1135,6 +1114,22 @@ namespace AibisDream.MiniGame.Language
particleManager?.ScatterTruthGather(burstDistance);
}
+ /// 真话聚合挣扎(非等待):推进途中反复"够到又被拽回去",字会锁上再崩开。
+ public void BeginTruthStrainAttempt(float target, float duration, int tugs)
+ {
+ if (!ExpectState(nameof(BeginTruthStrainAttempt), PresentationState.Memory))
+ return;
+ particleManager?.BeginTruthStrain(target, duration, tugs);
+ }
+
+ /// 真话聚合崩塌(非等待):进度被拽回 0,所有字沿原路退回并恢复乱跳。
+ public void CollapseTruthGatherAttempt(float duration)
+ {
+ if (!ExpectState(nameof(CollapseTruthGatherAttempt), PresentationState.Memory))
+ return;
+ particleManager?.CollapseTruthGather(duration);
+ }
+
/// 火山脸错误闪红:聚合失败的报错信号(非等待)。
public void PlayFaceErrorFlash(float duration, float intensity)
{
@@ -1371,6 +1366,10 @@ namespace AibisDream.MiniGame.Language
yield return new WaitForSeconds(Mathf.Max(0.05f, total - scrambleDuration));
}
+ ///
+ /// 记忆材质上的瞬时失真脉冲(抬升 _SimGlitch 后回落),不再驱动 noise 叠层。
+ /// 撕裂仍走 PlayMemoryTear / impact,避免两路抢同一参数。
+ ///
public void PlayGlitchPulse(float peak, float riseDuration, float fallDuration)
{
if (!ExpectState(
@@ -1387,6 +1386,16 @@ namespace AibisDream.MiniGame.Language
Mathf.Max(0.01f, fallDuration)));
}
+ ///
+ /// 已弃用:屏幕 Glitch 请走 ExpressionManager.SetScreenGlitchLevel(屏幕自身材质)。
+ /// 记忆阶段失真请用 PlayGlitchPulse / 记忆 impact。
+ ///
+ public void PlayScreenGlitch(float intensity, float duration)
+ {
+ _ = intensity;
+ _ = duration;
+ }
+
public IEnumerator PlayTruthAttack(
string text,
float duration,
@@ -1463,8 +1472,21 @@ namespace AibisDream.MiniGame.Language
PresentationState.TruthHolding))
yield break;
- if (glitchController != null)
- glitchController.TransitionTo(0f, Mathf.Max(0.08f, duration * 0.65f));
+ float settleDuration = Mathf.Max(0.08f, duration * 0.65f);
+ DOTween.To(
+ () => simGlitch,
+ value => simGlitch = value,
+ memoryBaseSimGlitch,
+ settleDuration)
+ .SetEase(Ease.OutQuad)
+ .SetTarget(this);
+ DOTween.To(
+ () => horizontalTear,
+ value => horizontalTear = value,
+ 0f,
+ settleDuration)
+ .SetEase(Ease.OutQuad)
+ .SetTarget(this);
if (particleManager != null)
yield return particleManager.SettleTruthPhraseAndWait(text, duration);
@@ -1495,12 +1517,21 @@ namespace AibisDream.MiniGame.Language
DOTween.To(() => memoryOverdrive, value => memoryOverdrive = value, 1f, rise)
.SetEase(Ease.InQuad)
.SetTarget(this);
-
- if (glitchController != null)
- {
- glitchController.SetCompositeMode(SpriteNoiseGlitchController.CompositeMode.TransparentOverlay);
- glitchController.TransitionTo(Mathf.Clamp01(glitchPeak), rise);
- }
+ float peak = Mathf.Clamp01(glitchPeak);
+ DOTween.To(
+ () => simGlitch,
+ value => simGlitch = value,
+ Mathf.Lerp(memoryBaseSimGlitch, 1f, peak),
+ rise)
+ .SetEase(Ease.InQuad)
+ .SetTarget(this);
+ DOTween.To(
+ () => horizontalTear,
+ value => horizontalTear = value,
+ Mathf.Lerp(0.18f, 0.72f, peak),
+ rise)
+ .SetEase(Ease.InQuad)
+ .SetTarget(this);
if (actorFlashText != null)
{
@@ -1699,8 +1730,12 @@ namespace AibisDream.MiniGame.Language
StopScanline();
StopScreenDim();
ReleaseScreenTextClipMaterials();
- if (glitchController != null)
- glitchController.TransitionTo(0f, 0.18f);
+ DOTween.To(() => simGlitch, value => simGlitch = value, memoryBaseSimGlitch, 0.18f)
+ .SetEase(Ease.OutQuad)
+ .SetTarget(this);
+ DOTween.To(() => horizontalTear, value => horizontalTear = value, 0f, 0.18f)
+ .SetEase(Ease.OutQuad)
+ .SetTarget(this);
state = PresentationState.TruthHolding;
}
@@ -1732,26 +1767,20 @@ namespace AibisDream.MiniGame.Language
HideSystemMessageImmediate();
StopScanline();
StopScreenDim();
- if (glitchController != null)
- {
- glitchController.ClearCalmField(true);
- glitchController.TransitionTo(0f, 0.12f);
- glitchController.SetAmbientNoise(0f, 320f, 0f);
- }
+ SilenceNoiseOverlayIfPresent();
+ DOTween.To(() => simGlitch, value => simGlitch = value, 0f, 0.12f)
+ .SetEase(Ease.OutQuad)
+ .SetTarget(this);
+ DOTween.To(() => horizontalTear, value => horizontalTear = value, 0f, 0.12f)
+ .SetEase(Ease.OutQuad)
+ .SetTarget(this);
yield return new WaitForSeconds(memoryExitDuration);
DisableMemoryRenderer(memoryRendererA);
DisableMemoryRenderer(memoryRendererB);
if (currentMemoryKind == MemoryKind.PrivateOffice)
- {
particleManager?.SetTargetParticlesAlpha(0.6f, 0.18f);
- if (glitchController != null)
- {
- glitchController.SetAmbientNoise(0.012f, 430f, 0.24f);
- glitchController.Intensity = 0.03f;
- }
- }
state = PresentationState.TruthHolding;
}
@@ -1787,13 +1816,7 @@ namespace AibisDream.MiniGame.Language
}
}
- if (glitchController != null)
- {
- glitchController.Intensity = 0f;
- glitchController.ClearCalmField(true);
- glitchController.SetAmbientNoise(0f, 320f, 0f);
- glitchController.SetCompositeMode(SpriteNoiseGlitchController.CompositeMode.OpaqueBackground);
- }
+ ResetNoiseOverlayForGlitchTransition();
particleManager?.RestoreTargetPresentationDefaults();
state = PresentationState.Idle;
@@ -1805,6 +1828,7 @@ namespace AibisDream.MiniGame.Language
horizontalTear = 0f;
noise = 0f;
simGlitch = 0f;
+ memoryBaseSimGlitch = 0f;
memoryImpact = 0f;
memoryDamage = 0f;
memoryOverdrive = 0f;
@@ -2028,14 +2052,48 @@ namespace AibisDream.MiniGame.Language
.WaitForCompletion();
}
+ /// 记忆材质瞬时失真:抬升 _SimGlitch 后回到基线。
private IEnumerator PulseGlitch(float peak, float riseDuration, float fallDuration)
{
- if (glitchController == null)
+ float clampedPeak = Mathf.Clamp01(peak);
+ if (clampedPeak <= 0.001f)
yield break;
- glitchController.SetCompositeMode(SpriteNoiseGlitchController.CompositeMode.TransparentOverlay);
- yield return glitchController.TransitionToAndWait(Mathf.Clamp01(peak), riseDuration);
- yield return glitchController.TransitionToAndWait(0f, fallDuration);
+ float rise = Mathf.Max(0.01f, riseDuration);
+ float fall = Mathf.Max(0.01f, fallDuration);
+ float startSim = simGlitch;
+ float restoreSim = memoryBaseSimGlitch > 0.001f ? memoryBaseSimGlitch : startSim;
+ float targetSim = Mathf.Max(startSim, Mathf.Lerp(restoreSim, 1f, clampedPeak));
+
+ yield return DOTween.To(() => simGlitch, value => simGlitch = value, targetSim, rise)
+ .SetEase(Ease.OutQuad)
+ .SetTarget(this)
+ .WaitForCompletion();
+ yield return DOTween.To(() => simGlitch, value => simGlitch = value, restoreSim, fall)
+ .SetEase(Ease.InQuad)
+ .SetTarget(this)
+ .WaitForCompletion();
+ }
+
+ private void SilenceNoiseOverlayIfPresent()
+ {
+ if (glitchController == null)
+ return;
+
+ glitchController.Intensity = 0f;
+ glitchController.SetAmbientNoise(0f, 320f, 0f);
+ glitchController.ClearCalmField(true);
+ }
+
+ private void ResetNoiseOverlayForGlitchTransition()
+ {
+ if (glitchController == null)
+ return;
+
+ SilenceNoiseOverlayIfPresent();
+ // 回到 glitch_transition 原始合成;Layer 保持 Default,勿改 HuoshanScreen。
+ glitchController.SetCompositeMode(SpriteNoiseGlitchController.CompositeMode.OpaqueBackground);
+ glitchController.gameObject.layer = 0;
}
private IEnumerator ShuffleLieCharactersRoutine(
@@ -2116,7 +2174,6 @@ namespace AibisDream.MiniGame.Language
}
calmRadius = 0f;
calmFeather = 0.20f;
- glitchController?.SetCalmField(truthBounds);
}
private void ConfigureMemoryLook(MemoryKind kind, Preset preset)
@@ -2140,7 +2197,7 @@ namespace AibisDream.MiniGame.Language
MemoryKind.Sunset => 0.18f,
_ => 0.46f
};
- // 颗粒噪点弃用;仅由 _SimGlitch 保留轻微 UV 失真扰动。
+ // 颗粒噪点与 noise 叠层均弃用;失真只走记忆材质 _SimGlitch。
noise = 0f;
simGlitch = preset.Name switch
{
@@ -2148,6 +2205,7 @@ namespace AibisDream.MiniGame.Language
"Heavy" => simGlitchHeavy,
_ => simGlitchLight
};
+ memoryBaseSimGlitch = simGlitch;
horizontalTear = 0f;
memoryTint = kind switch
{