diff --git a/Assets/Scripts/FixSystemNew/Screen System/Core/FixPanelLight.cs b/Assets/Scripts/FixSystemNew/Screen System/Core/FixPanelLight.cs
index a5e8b1453..78e18b827 100644
--- a/Assets/Scripts/FixSystemNew/Screen System/Core/FixPanelLight.cs
+++ b/Assets/Scripts/FixSystemNew/Screen System/Core/FixPanelLight.cs
@@ -73,6 +73,16 @@ namespace AibisDream.FixSystem
[SerializeField] private float emergencyOutroDuration = 0.18f;
[SerializeField, Range(0f, 1f)] private float emergencyIntroDipIntensityScale = 0.55f;
+ [Header("普通状态转场")]
+ [Tooltip("Normal→Warning 等非紧急切换的过渡时长")]
+ [SerializeField] private float softStateTransitionDuration = 0.55f;
+ [Tooltip("Warning→Normal:先闪几次再淡出,让镇静回落更明显")]
+ [SerializeField, Min(1)] private int warningSettleBlinkCount = 2;
+ [SerializeField, Min(0.02f)] private float warningSettleBlinkOnDuration = 0.14f;
+ [SerializeField, Min(0.02f)] private float warningSettleBlinkOffDuration = 0.12f;
+ [SerializeField, Min(0.1f)] private float warningSettleFadeDuration = 1.15f;
+ [SerializeField, Range(0f, 1f)] private float warningSettleBlinkDipScale = 0.28f;
+
private Tween alarmTween;
private Tween lightStateTransitionTween;
private LightState currentState = LightState.Normal;
@@ -240,7 +250,7 @@ namespace AibisDream.FixSystem
#region 光照系统 - 状态更新方法
///
- /// 根据紧急状态的进入/退出选择短转场,其他状态保持即时切换。
+ /// Emergency 用专属进出场;Warning→Normal 闪两下再淡出;其余短过渡。
///
private void TransitionLightsState(LightState previousState, LightState newState)
{
@@ -261,10 +271,13 @@ namespace AibisDream.FixSystem
{
PlayEmergencyOutro(stateConfig);
}
+ else if (previousState == LightState.Warning && newState == LightState.Normal)
+ {
+ PlayWarningSettleOutro(stateConfig);
+ }
else
{
- UpdateAlarmLight(stateConfig);
- UpdateEnvironmentLight(stateConfig);
+ PlaySoftStateTransition(stateConfig);
}
}
@@ -336,21 +349,118 @@ namespace AibisDream.FixSystem
private void PlayEmergencyOutro((bool alarmEnabled, Color alarmColor, float alarmMaxIntensity,
float alarmBlinkDuration, Color envColor, float envIntensity) config)
{
- float duration = Mathf.Max(0.01f, emergencyOutroDuration);
+ PlaySoftStateTransition(config, emergencyOutroDuration);
+ }
+
+ ///
+ /// Warning→Normal:警报/红调先明显闪两下,再较慢落到正常光。
+ ///
+ private void PlayWarningSettleOutro(
+ (bool alarmEnabled, Color alarmColor, float alarmMaxIntensity,
+ float alarmBlinkDuration, Color envColor, float envIntensity) config)
+ {
+ var warningConfig = GetStateConfig(LightState.Warning);
+ float blinkOn = Mathf.Max(0.02f, warningSettleBlinkOnDuration);
+ float blinkOff = Mathf.Max(0.02f, warningSettleBlinkOffDuration);
+ float fadeDuration = Mathf.Max(0.1f, warningSettleFadeDuration);
+ int blinkCount = Mathf.Max(1, warningSettleBlinkCount);
+
+ float startEnvIntensity = environmentLight != null
+ ? environmentLight.intensity
+ : warningConfig.envIntensity;
+ Color startEnvColor = environmentLight != null
+ ? environmentLight.color
+ : warningConfig.envColor;
+ float startAlarmIntensity = alarmLight != null
+ ? Mathf.Max(alarmLight.intensity, warningConfig.alarmMaxIntensity * 0.65f)
+ : warningConfig.alarmMaxIntensity;
+
+ if (alarmLight != null)
+ {
+ alarmLight.color = warningConfig.alarmColor;
+ alarmLight.intensity = startAlarmIntensity;
+ }
+
+ Color blinkDipColor = Color.Lerp(startEnvColor, config.envColor, 0.55f);
+ float blinkDipIntensity = startEnvIntensity * Mathf.Clamp01(warningSettleBlinkDipScale);
DG.Tweening.Sequence sequence = DOTween.Sequence();
+ for (int i = 0; i < blinkCount; i++)
+ {
+ // 灭:警报关 + 红调明显压一下
+ if (alarmLight != null)
+ {
+ sequence.Append(DOTween.To(
+ () => alarmLight.intensity,
+ value => alarmLight.intensity = value,
+ 0f,
+ blinkOff).SetEase(Ease.InQuad));
+ }
+ else
+ {
+ sequence.AppendInterval(blinkOff);
+ }
+
+ if (environmentLight != null)
+ {
+ sequence.Join(DOTween.To(
+ () => environmentLight.intensity,
+ value => environmentLight.intensity = value,
+ blinkDipIntensity,
+ blinkOff).SetEase(Ease.InQuad));
+ sequence.Join(DOTween.To(
+ () => environmentLight.color,
+ value => environmentLight.color = value,
+ blinkDipColor,
+ blinkOff).SetEase(Ease.InQuad));
+ }
+
+ // 亮:警报弹回 + 红调回满(第二下更像“挣扎熄灭”)
+ if (alarmLight != null)
+ {
+ sequence.Append(DOTween.To(
+ () => alarmLight.intensity,
+ value => alarmLight.intensity = value,
+ startAlarmIntensity,
+ blinkOn).SetEase(Ease.OutQuad));
+ }
+ else
+ {
+ sequence.AppendInterval(blinkOn);
+ }
+
+ if (environmentLight != null)
+ {
+ sequence.Join(DOTween.To(
+ () => environmentLight.intensity,
+ value => environmentLight.intensity = value,
+ startEnvIntensity,
+ blinkOn).SetEase(Ease.OutQuad));
+ sequence.Join(DOTween.To(
+ () => environmentLight.color,
+ value => environmentLight.color = value,
+ startEnvColor,
+ blinkOn).SetEase(Ease.OutQuad));
+ }
+ }
+
+ // 末段:红调与警报一起慢淡到 Normal
if (environmentLight != null)
{
- sequence.Join(DOTween.To(
+ sequence.Append(DOTween.To(
() => environmentLight.intensity,
value => environmentLight.intensity = value,
config.envIntensity,
- duration).SetEase(Ease.OutQuad));
+ fadeDuration).SetEase(Ease.InOutSine));
sequence.Join(DOTween.To(
() => environmentLight.color,
value => environmentLight.color = value,
config.envColor,
- duration).SetEase(Ease.OutQuad));
+ fadeDuration).SetEase(Ease.InOutSine));
+ }
+ else
+ {
+ sequence.AppendInterval(fadeDuration);
}
if (alarmLight != null)
@@ -359,7 +469,57 @@ namespace AibisDream.FixSystem
() => alarmLight.intensity,
value => alarmLight.intensity = value,
0f,
- duration).SetEase(Ease.OutQuad));
+ fadeDuration).SetEase(Ease.InQuad));
+ }
+
+ LightState targetState = currentState;
+ lightStateTransitionTween = sequence.OnComplete(() =>
+ {
+ lightStateTransitionTween = null;
+ if (currentState != targetState) return;
+ StopAlarmLight();
+ });
+ }
+
+ ///
+ /// Warning ↔ Normal 等普通切换:环境色/强度与警报灯一起短过渡。
+ ///
+ private void PlaySoftStateTransition(
+ (bool alarmEnabled, Color alarmColor, float alarmMaxIntensity,
+ float alarmBlinkDuration, Color envColor, float envIntensity) config,
+ float? overrideDuration = null)
+ {
+ float duration = Mathf.Max(0.01f, overrideDuration ?? softStateTransitionDuration);
+ DG.Tweening.Sequence sequence = DOTween.Sequence();
+
+ if (environmentLight != null)
+ {
+ sequence.Join(DOTween.To(
+ () => environmentLight.intensity,
+ value => environmentLight.intensity = value,
+ config.envIntensity,
+ duration).SetEase(Ease.InOutSine));
+ sequence.Join(DOTween.To(
+ () => environmentLight.color,
+ value => environmentLight.color = value,
+ config.envColor,
+ duration).SetEase(Ease.InOutSine));
+ }
+
+ if (alarmLight != null)
+ {
+ float targetAlarmIntensity = config.alarmEnabled ? config.alarmMaxIntensity : 0f;
+ alarmLight.color = Color.Lerp(alarmLight.color, config.alarmColor, 0.35f);
+ sequence.Join(DOTween.To(
+ () => alarmLight.color,
+ value => alarmLight.color = value,
+ config.alarmColor,
+ duration).SetEase(Ease.InOutSine));
+ sequence.Join(DOTween.To(
+ () => alarmLight.intensity,
+ value => alarmLight.intensity = value,
+ targetAlarmIntensity,
+ duration).SetEase(Ease.InOutSine));
}
if (environmentLight == null && alarmLight == null)
@@ -375,7 +535,7 @@ namespace AibisDream.FixSystem
if (config.alarmEnabled)
{
- StartAlarmLightBlink(config);
+ StartAlarmLightBlink(config, startLit: true);
}
else
{
diff --git a/Assets/Yarn/FP/FP_Prologue/Stage2-5_切割.yarn b/Assets/Yarn/FP/FP_Prologue/Stage2-5_切割.yarn
index 411a27d55..56f3928b7 100644
--- a/Assets/Yarn/FP/FP_Prologue/Stage2-5_切割.yarn
+++ b/Assets/Yarn/FP/FP_Prologue/Stage2-5_切割.yarn
@@ -261,10 +261,13 @@ gts??: 医生…我好困…… #line:0fc221c
me: 很快就好了。 #line:0b41425
<>
<>
+// 等 Warning 闪两下 + 慢淡出落稳(约 1.7s),再接镇静台词
+<>
EmoModule: 指令执行完成!正在刷新... #line:05ce8bb
gts?: 它消失了,医生。谢谢你。
Error: 原型泄漏:35.2% #line:09ef3b8
<>
+<>
<>
// 情绪/逻辑/记忆进入损坏状态:文字闪烁+间歇火花
<>