feat(fix-panel): Warning回落增加闪烁淡出并对齐等待

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-07-21 01:18:03 +08:00
co-authored by Cursor
parent ecfefa5b87
commit 2ac0b4695d
2 changed files with 172 additions and 9 deletions
@@ -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 -
/// <summary>
/// 根据紧急状态的进入/退出选择短转场,其他状态保持即时切换
/// Emergency 用专属进出场;Warning→Normal 闪两下再淡出;其余短过渡
/// </summary>
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);
}
/// <summary>
/// Warning→Normal:警报/红调先明显闪两下,再较慢落到正常光。
/// </summary>
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();
});
}
/// <summary>
/// Warning ↔ Normal 等普通切换:环境色/强度与警报灯一起短过渡。
/// </summary>
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
{
@@ -261,10 +261,13 @@ gts??: <speed=1><i>医生…我好困……</i> #line:0fc221c
me: 很快就好了。 #line:0b41425
<<set_global_param emergencyLevel 0.2>>
<<set_light_state Normal>>
// 等 Warning 闪两下 + 慢淡出落稳(约 1.7s),再接镇静台词
<<wait 1.55>>
EmoModule: 指令执行完成!正在刷新... #line:05ce8bb
gts?: <speed=0.3><wiggle a=0.1 s=0.01>它消失了,医生。谢谢你。</wiggle>
Error: 原型泄漏:35.2% #line:09ef3b8
<<set_light_state Warning>>
<<wait 0.4>>
<<StartHeadContinuousPain>>
// 情绪/逻辑/记忆进入损坏状态:文字闪烁+间歇火花
<<SetModuleState Emo Damaged>>