using AibisDream.Framework; using AibisDream.Kit; using UnityEngine; using UnityEngine.Rendering.Universal; using DG.Tweening; using System.Collections; namespace AibisDream.FixSystem { /// /// 灯光状态 /// public enum LightState { Normal, // 正常状态 Warning, // 警告状态 Emergency // 紧急状态 } /// /// 维修面板光照系统 - 管理所有光照效果 /// public class FixPanelLight : MonoBehaviour { #region 光照系统常量 private const float SYSTEM_OFF_ENVIRONMENT_INTENSITY = 0.4f; private const float ALARM_LIGHT_MAX_INTENSITY = 4f; private const float MIN_FLICKER_BLINK_COUNT = 2; private const float MAX_FLICKER_BLINK_COUNT = 4; private const string PANEL_LIGHT_ON_SFX = "event:/ActionFB/light_flicker_on"; private const string PANEL_LIGHT_OFF_SFX = "event:/ActionFB/light_flicker_off"; private const float MIN_FLICKER_INTERVAL = 3f; private const float MAX_FLICKER_INTERVAL = 8f; private const float ENVIRONMENT_COLOR_INFLUENCE = 0.65f; private const float ENVIRONMENT_INTENSITY_INFLUENCE = 0.35f; #endregion #region 光照系统字段 [Header("环境灯设置")] [SerializeField] private Light2D environmentLight; [SerializeField] private Light2D deepEnvironmentLight; [SerializeField, Min(0.01f)] private float deepEnvironmentNormalIntensity = 0.9f; [SerializeField, Range(0f, 1f)] private float deepEnvironmentAlpha = 0.8509804f; [SerializeField] private bool isEnvironmentLightFlickering = false; [SerializeField] private float normalEnvironmentIntensity = 2f; [SerializeField] private float warningEnvironmentIntensity = 1.25f; [SerializeField] private float emergencyEnvironmentIntensity = 2f; [SerializeField] private float brokenLightFlickerInterval = 0.1f; [SerializeField] private float brokenLightFlickerDuration = 0.05f; [SerializeField] private Color normalEnvironmentColor = Color.white; [SerializeField] private Color warningEnvironmentColor = new Color(1f, 0.46f, 0.4f); [SerializeField] private Color emergencyEnvironmentColor = Color.red; [Header("面板灯设置")] [SerializeField] private Light2D panelLight; [SerializeField] private float panelLightIntensity = 0.3f; [SerializeField] private float panelLightBlinkDuration = 0.12f; [SerializeField] private int panelLightBlinkCount = 2; [SerializeField] private Color panelLightColor = Color.white; [Header("警报灯设置")] [SerializeField] private Light2D alarmLight; [SerializeField] private float warningAlarmBlinkSpeed = 1.5f; [SerializeField] private float warningAlarmMaxIntensity = 1.2f; [SerializeField] private Color warningAlarmLightColor = new Color(1f, 0.42f, 0.35f); [SerializeField] private float alarmBlinkSpeed = 0.5f; [SerializeField] private Color alarmLightColor = Color.red; [Header("紧急状态转场")] [SerializeField] private float emergencyIntroDipDuration = 0.08f; [SerializeField] private float emergencyIntroRiseDuration = 0.18f; [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; /// /// 当前环境灯相对于 Normal 状态的实时色调。 /// 用于无法直接接收 URP 2D Light 的动态网格等渲染对象。 /// public Color CurrentEnvironmentTint { get { if (environmentLight == null) return Color.white; float currentIntensity = Mathf.Max(0f, environmentLight.intensity); if (currentIntensity <= Mathf.Epsilon) return Color.black; float intensityScale = currentIntensity / Mathf.Max(0.01f, normalEnvironmentIntensity); Color lightColor = environmentLight.color; Color softenedColor = Color.Lerp( Color.white, new Color(lightColor.r, lightColor.g, lightColor.b, 1f), ENVIRONMENT_COLOR_INFLUENCE); float softenedIntensity = Mathf.Lerp( 1f, intensityScale, ENVIRONMENT_INTENSITY_INFLUENCE); return new Color( softenedColor.r * softenedIntensity, softenedColor.g * softenedIntensity, softenedColor.b * softenedIntensity, 1f); } } #endregion #region 生命周期 private void LateUpdate() { SyncDeepEnvironmentLight(); } private void OnDisable() { lightStateTransitionTween?.Kill(); lightStateTransitionTween = null; StopAlarmLight(); StopAllCoroutines(); } #endregion #region 光照系统 - 公共方法 public void Initialize(bool isSystemOn, LightState state = LightState.Normal) { lightStateTransitionTween?.Kill(); lightStateTransitionTween = null; alarmTween?.Kill(); alarmTween = null; StopAllCoroutines(); currentState = state; if (!isSystemOn) { if (panelLight != null) { panelLight.color = panelLightColor; panelLight.intensity = 0f; } if (environmentLight != null) { environmentLight.color = normalEnvironmentColor; environmentLight.intensity = SYSTEM_OFF_ENVIRONMENT_INTENSITY; } if (alarmLight != null) { alarmLight.intensity = 0f; } SyncDeepEnvironmentLight(); return; } UpdateLightsState(); if (isEnvironmentLightFlickering) { StartCoroutine(EnvironmentLightFlickerRoutine()); } SyncDeepEnvironmentLight(); } private void SyncDeepEnvironmentLight() { if (deepEnvironmentLight == null || environmentLight == null) return; Color deepColor = environmentLight.color; deepColor.a = deepEnvironmentAlpha; deepEnvironmentLight.color = deepColor; float intensityRatio = Mathf.Max(0f, environmentLight.intensity / Mathf.Max(0.01f, normalEnvironmentIntensity)); deepEnvironmentLight.intensity = deepEnvironmentNormalIntensity * intensityRatio; } /// /// 设置灯光状态 /// public void SetLightState(LightState newState) { if (currentState != newState) { LightState previousState = currentState; currentState = newState; TransitionLightsState(previousState, newState); Debug.Log($"灯光状态已切换为: {newState}"); } } /// /// 压暗光照强度 /// public void DarkenLights() { panelLight.intensity = 0f; } /// /// 设置环境灯闪烁状态 /// public void SetEnvironmentLightFlickering(bool isFlickering) { if (isEnvironmentLightFlickering != isFlickering) { isEnvironmentLightFlickering = isFlickering; if (isFlickering) { StartCoroutine(EnvironmentLightFlickerRoutine()); } } } /// /// 设置环境灯损坏状态 /// public void SetEnvironmentLightBroken() { if (environmentLight != null) { environmentLight.color = GetEnvironmentColorByState(currentState); } } /// /// 设置警报灯闪烁速度 /// public void SetAlarmBlinkSpeed(float speed) { if (speed > 0) { if (currentState == LightState.Warning) { warningAlarmBlinkSpeed = speed; } else { alarmBlinkSpeed = speed; } // 如果当前正在闪烁,立即使用新速度重启。 if (currentState != LightState.Normal && alarmLight != null) { lightStateTransitionTween?.Kill(); lightStateTransitionTween = null; StartAlarmLightBlink(GetStateConfig(currentState)); } } } /// /// 停止警报灯 /// public void StopAlarmLight() { if (alarmLight != null) { alarmTween?.Kill(); alarmTween = null; alarmLight.intensity = 0f; } } #endregion #region 光照系统 - 状态更新方法 /// /// Emergency 用专属进出场;Warning→Normal 闪两下再淡出;其余短过渡。 /// private void TransitionLightsState(LightState previousState, LightState newState) { lightStateTransitionTween?.Kill(); lightStateTransitionTween = null; alarmTween?.Kill(); alarmTween = null; var stateConfig = GetStateConfig(newState); UpdatePanelLight(); if (newState == LightState.Emergency) { PlayEmergencyIntro(stateConfig); } else if (previousState == LightState.Emergency) { PlayEmergencyOutro(stateConfig); } else if (previousState == LightState.Warning && newState == LightState.Normal) { PlayWarningSettleOutro(stateConfig); } else { PlaySoftStateTransition(stateConfig); } } /// /// Emergency 进入:极短压暗后快速升起红光,再接循环警报。 /// private void PlayEmergencyIntro((bool alarmEnabled, Color alarmColor, float alarmMaxIntensity, float alarmBlinkDuration, Color envColor, float envIntensity) config) { float dipDuration = Mathf.Max(0.01f, emergencyIntroDipDuration); float riseDuration = Mathf.Max(0.01f, emergencyIntroRiseDuration); DG.Tweening.Sequence sequence = DOTween.Sequence(); if (environmentLight != null) { float dipIntensity = environmentLight.intensity * emergencyIntroDipIntensityScale; Color dipColor = Color.Lerp(environmentLight.color, config.envColor, 0.35f); sequence.Append(DOTween.To( () => environmentLight.intensity, value => environmentLight.intensity = value, dipIntensity, dipDuration).SetEase(Ease.OutQuad)); sequence.Join(DOTween.To( () => environmentLight.color, value => environmentLight.color = value, dipColor, dipDuration).SetEase(Ease.OutQuad)); sequence.Append(DOTween.To( () => environmentLight.intensity, value => environmentLight.intensity = value, config.envIntensity, riseDuration).SetEase(Ease.OutCubic)); sequence.Join(DOTween.To( () => environmentLight.color, value => environmentLight.color = value, config.envColor, riseDuration).SetEase(Ease.OutCubic)); } else { sequence.AppendInterval(dipDuration + riseDuration); } if (alarmLight != null) { alarmLight.color = config.alarmColor; alarmLight.intensity = 0f; sequence.Insert(dipDuration, DOTween.To( () => alarmLight.intensity, value => alarmLight.intensity = value, config.alarmMaxIntensity, riseDuration).SetEase(Ease.OutCubic)); } lightStateTransitionTween = sequence.OnComplete(() => { lightStateTransitionTween = null; if (currentState == LightState.Emergency) { StartAlarmLightBlink(config, true); } }); } /// /// Emergency 退出:快速收起紧急红光,平滑落到目标状态。 /// private void PlayEmergencyOutro((bool alarmEnabled, Color alarmColor, float alarmMaxIntensity, float alarmBlinkDuration, Color envColor, float envIntensity) config) { 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.Append(DOTween.To( () => environmentLight.intensity, value => environmentLight.intensity = value, config.envIntensity, fadeDuration).SetEase(Ease.InOutSine)); sequence.Join(DOTween.To( () => environmentLight.color, value => environmentLight.color = value, config.envColor, fadeDuration).SetEase(Ease.InOutSine)); } else { sequence.AppendInterval(fadeDuration); } if (alarmLight != null) { sequence.Join(DOTween.To( () => alarmLight.intensity, value => alarmLight.intensity = value, 0f, 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) { sequence.AppendInterval(duration); } LightState targetState = currentState; lightStateTransitionTween = sequence.OnComplete(() => { lightStateTransitionTween = null; if (currentState != targetState) return; if (config.alarmEnabled) { StartAlarmLightBlink(config, startLit: true); } else { StopAlarmLight(); } }); } /// /// 更新所有灯光状态 /// private void UpdateLightsState() { var stateConfig = GetStateConfig(currentState); UpdateAlarmLight(stateConfig); UpdateEnvironmentLight(stateConfig); UpdatePanelLight(); } /// /// 获取状态配置 /// private (bool alarmEnabled, Color alarmColor, float alarmMaxIntensity, float alarmBlinkDuration, Color envColor, float envIntensity) GetStateConfig(LightState state) { return state switch { LightState.Normal => (false, alarmLightColor, 0f, alarmBlinkSpeed, normalEnvironmentColor, normalEnvironmentIntensity), LightState.Warning => (true, warningAlarmLightColor, warningAlarmMaxIntensity, warningAlarmBlinkSpeed, warningEnvironmentColor, warningEnvironmentIntensity), LightState.Emergency => (true, alarmLightColor, ALARM_LIGHT_MAX_INTENSITY, alarmBlinkSpeed, emergencyEnvironmentColor, emergencyEnvironmentIntensity), _ => (false, alarmLightColor, 0f, alarmBlinkSpeed, normalEnvironmentColor, normalEnvironmentIntensity) }; } /// /// 更新警报灯 /// private void UpdateAlarmLight((bool alarmEnabled, Color alarmColor, float alarmMaxIntensity, float alarmBlinkDuration, Color envColor, float envIntensity) config) { if (alarmLight == null) return; if (config.alarmEnabled) { StartAlarmLightBlink(config); } else { StopAlarmLight(); } } /// /// 启动警报灯闪烁 /// private void StartAlarmLightBlink((bool alarmEnabled, Color alarmColor, float alarmMaxIntensity, float alarmBlinkDuration, Color envColor, float envIntensity) config, bool startLit = false) { if (alarmLight == null) return; alarmTween?.Kill(); alarmLight.intensity = startLit ? config.alarmMaxIntensity : 0f; alarmLight.color = config.alarmColor; alarmTween = DOTween.To( () => alarmLight.intensity, x => alarmLight.intensity = x, startLit ? 0f : config.alarmMaxIntensity, config.alarmBlinkDuration ) .SetLoops(-1, LoopType.Yoyo) .SetEase(Ease.InOutSine); } /// /// 更新环境灯 /// private void UpdateEnvironmentLight((bool alarmEnabled, Color alarmColor, float alarmMaxIntensity, float alarmBlinkDuration, Color envColor, float envIntensity) config) { if (environmentLight == null) return; environmentLight.color = config.envColor; environmentLight.intensity = config.envIntensity; } /// /// 更新面板灯 /// private void UpdatePanelLight() { if (panelLight == null) return; panelLight.color = panelLightColor; panelLight.intensity = panelLightIntensity; } #endregion #region 光照系统 - 环境灯相关方法 /// /// 环境灯闪烁协程 /// private IEnumerator EnvironmentLightFlickerRoutine() { while (isEnvironmentLightFlickering) { if (environmentLight == null) { yield return new WaitForSeconds(0.1f); continue; } float currentIntensity = GetEnvironmentIntensityByState(currentState); environmentLight.intensity = currentIntensity; // 等待随机间隔 yield return new WaitForSeconds(Random.Range(MIN_FLICKER_INTERVAL, MAX_FLICKER_INTERVAL)); // 随机闪烁 int blinkCount = Random.Range((int)MIN_FLICKER_BLINK_COUNT, (int)MAX_FLICKER_BLINK_COUNT); for (int i = 0; i < blinkCount; i++) { environmentLight.intensity = 0f; yield return new WaitForSeconds(brokenLightFlickerDuration); environmentLight.intensity = currentIntensity; yield return new WaitForSeconds(brokenLightFlickerInterval); } } // 确保灯光在停止闪烁时是亮着的 if (environmentLight != null) { environmentLight.intensity = GetEnvironmentIntensityByState(currentState); } } /// /// 根据状态获取环境灯强度 /// private float GetEnvironmentIntensityByState(LightState state) { return state switch { LightState.Normal => normalEnvironmentIntensity, LightState.Warning => warningEnvironmentIntensity, LightState.Emergency => emergencyEnvironmentIntensity, _ => normalEnvironmentIntensity }; } /// /// 根据状态获取环境灯颜色 /// private Color GetEnvironmentColorByState(LightState state) { return state switch { LightState.Normal => normalEnvironmentColor, LightState.Warning => warningEnvironmentColor, LightState.Emergency => emergencyEnvironmentColor, _ => normalEnvironmentColor }; } #endregion #region 光照系统 - 面板灯相关方法 /// /// 面板灯启动序列 /// public IEnumerator PanelLightStartSequence() { if (panelLight == null) yield break; for (int i = 0; i < panelLightBlinkCount; i++) { // 渐亮 AudioManager.Instance?.PlaySfx(PANEL_LIGHT_ON_SFX); DOTween.To(() => panelLight.intensity, x => panelLight.intensity = x, panelLightIntensity, panelLightBlinkDuration * 0.5f) .SetEase(Ease.InOutQuad); if (environmentLight != null) { DOTween.To(() => environmentLight.intensity, x => environmentLight.intensity = x, normalEnvironmentIntensity, panelLightBlinkDuration * 0.5f) .SetEase(Ease.InOutQuad); } yield return new WaitForSeconds(panelLightBlinkDuration); // 渐暗 AudioManager.Instance?.PlaySfx(PANEL_LIGHT_OFF_SFX); DOTween.To(() => panelLight.intensity, x => panelLight.intensity = x, 0f, panelLightBlinkDuration * 0.5f) .SetEase(Ease.InOutQuad); if (environmentLight != null) { DOTween.To(() => environmentLight.intensity, x => environmentLight.intensity = x, 0f, panelLightBlinkDuration * 0.5f) .SetEase(Ease.InOutQuad); } yield return new WaitForSeconds(panelLightBlinkDuration); } // 最后渐亮到常亮状态 AudioManager.Instance?.PlaySfx(PANEL_LIGHT_ON_SFX); DG.Tweening.Sequence finalRise = DOTween.Sequence(); finalRise.Join(DOTween.To(() => panelLight.intensity, x => panelLight.intensity = x, panelLightIntensity, panelLightBlinkDuration * 0.5f) .SetEase(Ease.InOutQuad)); if (environmentLight != null) { finalRise.Join(DOTween.To(() => environmentLight.intensity, x => environmentLight.intensity = x, normalEnvironmentIntensity, panelLightBlinkDuration * 0.5f) .SetEase(Ease.InOutQuad)); } yield return finalRise.WaitForCompletion(); } #endregion } }