feat(fix-system): 整合维修面板灯光系统并重构面板结构

Made-with: Cursor
This commit is contained in:
2026-03-05 19:11:12 +08:00
parent cb49557aed
commit bc369bd86e
17 changed files with 1208 additions and 90 deletions
@@ -69,8 +69,6 @@ namespace AibisDream.FixSystem
FixSystemCenter.SystemDic.Register(this);
// 注册Camera
var virtualCam = transform.Find("Body Module Camera").GetComponent<ICinemachineCamera>();
CameraKit.Instance.RegisterCamera(CameraEnum.BodyModule, virtualCam);
var virtualCam2 = transform.Find("Body Module Camera Center").GetComponent<ICinemachineCamera>();
CameraKit.Instance.RegisterCamera(CameraEnum.BodyModuleCenter, virtualCam2);
}
@@ -78,7 +76,7 @@ namespace AibisDream.FixSystem
private void OnDestroy()
{
StorageSystem.Instance.UnregisterData<ModuleSystemData>();
CameraKit.Instance.UnRegisterCamera(CameraEnum.BodyModule);
CameraKit.Instance.UnRegisterCamera(CameraEnum.BodyModuleCenter);
}
/// <summary>
@@ -149,7 +149,7 @@ namespace AibisDream.FixSystem
public IEnumerator Enter()
{
var bodyModuleSystem = FixSystemCenter.SystemDic.Get<BodyModuleSystem>();
var lightSystem = FixPanelSystem.GetRepairPanel<CablePanel>().FixLightSystem;
var cablePanel = FixPanelSystem.GetRepairPanel<CablePanel>();
// 拔出插头
// 切换Body或Head
if (Enum.TryParse<ModuleState>(_args, out var moduleState))
@@ -157,14 +157,14 @@ namespace AibisDream.FixSystem
bodyModuleSystem.SwitchModuleGroup(moduleState);
}
if (lightSystem && !lightSystem.IsSystemOn())
if (cablePanel != null && !cablePanel.IsSystemOn())
{
// 切换相机
yield return CameraKit.Instance.SwitchCamera(CameraEnum.BodyModuleCenter);
yield return UIManager.Instance.GetPanel<PlayToolPanel>().FadeOutAsync(0.5f);
yield return new WaitForSeconds(0.5f);
yield return CameraKit.Instance.SwitchCamera(CameraEnum.BodyModule);
yield return lightSystem.StartSystem();
yield return cablePanel.StartSystem();
}
else
{
@@ -492,10 +492,7 @@ namespace AibisDream.FixSystem
public IEnumerator Exit()
{
var emoManager = FixSystemCenter.SystemDic.Get<EmoManager>();
var bodyModuleSystem = FixSystemCenter.SystemDic.Get<BodyModuleSystem>();
FixPanelSystem.GetRepairPanel<CablePanel>().ResetPlug();
//emoManager.CloseView();
yield break;
}
}
@@ -383,15 +383,15 @@ public class ShockSystem : MonoBehaviour
yield return new WaitForSeconds(shockFlashDelay);
// 获取ECG波形组件
var lightSystem = FixPanelSystem.GetRepairPanel<CablePanel>()?.FixLightSystem;
var originalWaveType = lightSystem?.GetCurrentWaveType();
var cablePanel = FixPanelSystem.GetRepairPanel<CablePanel>();
var originalWaveType = cablePanel?.GetCurrentWaveType();
flashSequence = DOTween.Sequence();
currentFlashHeadIndex = 0;
// 激活精灵渲染器
if (flashHeadSpriteRenderer != null)
{
{
flashHeadSpriteRenderer.gameObject.SetActive(true);
flashHeadSpriteRenderer.color = new Color(1, 1, 1, 1); // 确保初始alpha为0
}
@@ -402,9 +402,9 @@ public class ShockSystem : MonoBehaviour
}
// 设置ECG为直线
if (lightSystem != null)
if (cablePanel != null)
{
lightSystem.SetWaveType(RobotECGWave.WaveType.Flatline);
cablePanel.SetWaveType(RobotECGWave.WaveType.Flatline);
}
// 创建指定次数的闪烁
@@ -453,9 +453,9 @@ public class ShockSystem : MonoBehaviour
yield return flashSequence.WaitForCompletion();
// 恢复ECG波形
if (lightSystem != null && originalWaveType.HasValue)
if (cablePanel != null && originalWaveType.HasValue)
{
lightSystem.SetWaveType(originalWaveType.Value);
cablePanel.SetWaveType(originalWaveType.Value);
flashHeadSpriteRenderer.gameObject.SetActive(false);
flashHeadSpriteRenderer.color = new Color(1, 1, 1, 0);
flashHeadSpriteRenderer.sprite = flashHeadSprites[0];
@@ -0,0 +1,358 @@
using AibisDream.Framework;
using AibisDream.Kit;
using UnityEngine;
using UnityEngine.Rendering.Universal;
using DG.Tweening;
using System.Collections;
namespace AibisDream.FixSystem
{
/// <summary>
/// 灯光状态
/// </summary>
public enum LightState
{
Normal, // 正常状态
Warning, // 警告状态
Emergency // 紧急状态
}
/// <summary>
/// 维修面板光照系统 - 管理所有光照效果
/// </summary>
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 float MIN_FLICKER_INTERVAL = 3f;
private const float MAX_FLICKER_INTERVAL = 8f;
#endregion
#region
[Header("环境灯设置")]
[SerializeField] private Light2D environmentLight;
[SerializeField] private bool isEnvironmentLightFlickering = false;
[SerializeField] private float normalEnvironmentIntensity = 2f;
[SerializeField] private float warningEnvironmentIntensity = 2f;
[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 = Color.yellow;
[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 alarmBlinkSpeed = 0.5f;
[SerializeField] private Color alarmLightColor = Color.red;
private Tween alarmTween;
private LightState currentState = LightState.Normal;
#endregion
#region
private void OnDisable()
{
alarmTween?.Kill();
StopAllCoroutines();
}
#endregion
#region -
/// <summary>
/// 设置灯光状态
/// </summary>
public void SetLightState(LightState newState)
{
if (currentState != newState)
{
currentState = newState;
UpdateLightsState();
Debug.Log($"灯光状态已切换为: {newState}");
}
}
/// <summary>
/// 设置环境灯闪烁状态
/// </summary>
public void SetEnvironmentLightFlickering(bool isFlickering)
{
if (isEnvironmentLightFlickering != isFlickering)
{
isEnvironmentLightFlickering = isFlickering;
if (isFlickering)
{
StartCoroutine(EnvironmentLightFlickerRoutine());
}
}
}
/// <summary>
/// 设置环境灯损坏状态
/// </summary>
public void SetEnvironmentLightBroken()
{
if (environmentLight != null)
{
environmentLight.color = GetEnvironmentColorByState(currentState);
}
}
/// <summary>
/// 设置警报灯闪烁速度
/// </summary>
public void SetAlarmBlinkSpeed(float speed)
{
if (speed > 0)
{
alarmBlinkSpeed = speed;
// 如果当前正在闪烁,更新闪烁速度
if (currentState == LightState.Emergency && alarmLight != null)
{
StartAlarmLightBlink();
}
}
}
/// <summary>
/// 停止警报灯
/// </summary>
public void StopAlarmLight()
{
if (alarmLight != null)
{
alarmTween?.Kill();
alarmLight.intensity = 0f;
}
}
/// <summary>
/// 启动面板灯光序列(纯灯光效果,不包含其他面板的协调)
/// </summary>
public IEnumerator StartPanelLightSequence()
{
yield return StartCoroutine(PanelLightStartSequence());
}
#endregion
#region -
/// <summary>
/// 更新所有灯光状态
/// </summary>
private void UpdateLightsState()
{
var stateConfig = GetStateConfig(currentState);
UpdateAlarmLight(stateConfig);
UpdateEnvironmentLight(stateConfig);
UpdatePanelLight();
}
/// <summary>
/// 获取状态配置
/// </summary>
private (Color alarmColor, Color envColor, float envIntensity) GetStateConfig(LightState state)
{
return state switch
{
LightState.Normal => (alarmLightColor, normalEnvironmentColor, normalEnvironmentIntensity),
LightState.Warning => (alarmLightColor, warningEnvironmentColor, warningEnvironmentIntensity),
LightState.Emergency => (alarmLightColor, emergencyEnvironmentColor, emergencyEnvironmentIntensity),
_ => (alarmLightColor, normalEnvironmentColor, normalEnvironmentIntensity)
};
}
/// <summary>
/// 更新警报灯
/// </summary>
private void UpdateAlarmLight((Color alarmColor, Color envColor, float envIntensity) config)
{
if (alarmLight == null) return;
if (currentState == LightState.Emergency)
{
alarmLight.color = alarmLightColor;
StartAlarmLightBlink();
}
else
{
StopAlarmLight();
}
}
/// <summary>
/// 启动警报灯闪烁
/// </summary>
private void StartAlarmLightBlink()
{
if (alarmLight == null) return;
alarmTween?.Kill();
alarmTween = DOTween.To(
() => alarmLight.intensity,
x => alarmLight.intensity = x,
ALARM_LIGHT_MAX_INTENSITY,
alarmBlinkSpeed
)
.SetLoops(-1, LoopType.Yoyo)
.SetEase(Ease.InOutSine);
}
/// <summary>
/// 更新环境灯
/// </summary>
private void UpdateEnvironmentLight((Color alarmColor, Color envColor, float envIntensity) config)
{
if (environmentLight == null) return;
environmentLight.color = config.envColor;
environmentLight.intensity = config.envIntensity;
}
/// <summary>
/// 更新面板灯
/// </summary>
private void UpdatePanelLight()
{
if (panelLight == null) return;
panelLight.color = panelLightColor;
panelLight.intensity = panelLightIntensity;
}
#endregion
#region -
/// <summary>
/// 环境灯闪烁协程
/// </summary>
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);
}
}
/// <summary>
/// 根据状态获取环境灯强度
/// </summary>
private float GetEnvironmentIntensityByState(LightState state)
{
return state switch
{
LightState.Normal => normalEnvironmentIntensity,
LightState.Warning => warningEnvironmentIntensity,
LightState.Emergency => emergencyEnvironmentIntensity,
_ => normalEnvironmentIntensity
};
}
/// <summary>
/// 根据状态获取环境灯颜色
/// </summary>
private Color GetEnvironmentColorByState(LightState state)
{
return state switch
{
LightState.Normal => normalEnvironmentColor,
LightState.Warning => warningEnvironmentColor,
LightState.Emergency => emergencyEnvironmentColor,
_ => normalEnvironmentColor
};
}
#endregion
#region -
/// <summary>
/// 面板灯启动序列
/// </summary>
private IEnumerator PanelLightStartSequence()
{
if (panelLight == null) yield break;
for (int i = 0; i < panelLightBlinkCount; i++)
{
// 渐亮
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);
// 渐暗
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);
}
// 最后渐亮到常亮状态
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);
}
}
#endregion
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c94fcbfddb452b54eadb3f27fdefbf78
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -1,6 +1,8 @@
using AibisDream.Framework;
using AibisDream.Kit;
using UnityEngine;
using Cinemachine;
using System.Collections;
namespace AibisDream.FixSystem
{
@@ -12,12 +14,14 @@ namespace AibisDream.FixSystem
{
private void OnEnable()
{
RegisterCanvasCamera();
RegisterPanels();
RegisterScreenView();
}
private void OnDisable()
{
UnRegisterCanvasCamera();
_panelContainer.Clear();
UnRegisterScreenView();
}
@@ -42,12 +46,68 @@ namespace AibisDream.FixSystem
#endregion
#region
[Header("光照系统")]
[SerializeField] private FixPanelLight panelLight;
public FixPanelLight PanelLight => panelLight;
#endregion
#region
/// <summary>
/// 启动所有系统(协调灯光系统和 CablePanel 的启动顺序)
/// </summary>
public IEnumerator StartAllSystems()
{
// 1. 先启动 CablePanel 的系统自检
var cablePanel = GetRepairPanel<CablePanel>();
if (cablePanel != null)
{
yield return cablePanel.StartSystem();
}
// 2. 再启动灯光序列
if (panelLight != null)
{
yield return panelLight.StartPanelLightSequence();
}
}
/// <summary>
/// 设置灯光状态,并同步更新相关面板的灯光效果
/// </summary>
public void SetLightState(LightState newState)
{
// 1. 更新主灯光系统
if (panelLight != null)
{
panelLight.SetLightState(newState);
}
// 2. 同步更新 CablePanel 的灯光效果
var cablePanel = GetRepairPanel<CablePanel>();
if (cablePanel != null)
{
cablePanel.UpdateBreathingLight(newState);
cablePanel.UpdateECGWave(newState);
}
}
#endregion
#region
[Header("默认相机")]
[SerializeField] private CinemachineVirtualCamera fixPanelCamera;
[Header("默认气泡")]
[SerializeField] private BubbleSlotGroup bubbleSlotGroup;
public BubbleSlotGroup BubbleSlotGroup => bubbleSlotGroup;
[Header("默认画布")]
[SerializeField] private Canvas canvas;
[Header("任务面板")]
[SerializeField] private TaskPanel taskPanel;
public TaskPanel TaskPanel => taskPanel;
@@ -58,14 +118,29 @@ namespace AibisDream.FixSystem
private void RegisterScreenView()
{
// DialogUIManager.Instance.RegisterScreenView(DialogViewType.Screen, screenPanel);
// DialogUIManager.Instance.RegisterScreenView(DialogViewType.Task, taskPanel);
// 注册相机
CameraKit.Instance.RegisterCamera(CameraEnum.BodyModule, fixPanelCamera);
DialogUIManager.Instance.RegisterScreenView(DialogViewType.Screen, screenPanel);
DialogUIManager.Instance.RegisterScreenView(DialogViewType.Task, taskPanel);
}
private void UnRegisterScreenView()
{
// DialogUIManager.Instance.UnRegisterScreenView(DialogViewType.Screen);
// DialogUIManager.Instance.UnRegisterScreenView(DialogViewType.Task);
CameraKit.Instance.UnRegisterCamera(CameraEnum.BodyModule);
DialogUIManager.Instance.UnRegisterScreenView(DialogViewType.Screen);
DialogUIManager.Instance.UnRegisterScreenView(DialogViewType.Task);
}
private void RegisterCanvasCamera()
{
canvas.worldCamera = Camera.main;
}
private void UnRegisterCanvasCamera()
{
canvas.worldCamera = null;
}
#endregion
@@ -1,20 +1,6 @@
namespace AibisDream.FixSystem
namespace AibisDream.FixSystem
{
public interface IOperatorPanel
{
/// <summary>
/// 初始化面板, 直接显示,不播进入动画
/// </summary>
void Init();
/// <summary>
/// 显示面板, 播进入动画
/// </summary>
void Open();
/// <summary>
/// 隐藏面板, 播退出动画
/// </summary>
void Close();
}
}
@@ -3,6 +3,7 @@ using AibisDream.UI;
using UnityEngine.UI;
using System;
using UnityEngine.Events;
using AibisDream.Framework;
namespace AibisDream.FixSystem
{
@@ -11,6 +12,16 @@ namespace AibisDream.FixSystem
public UnityEvent OnSubmit => lockButton.onClick;
public UnityEvent OnPopUp => popUpButton.onClick;
private void Awake()
{
EnumEventSystem.Global.Register<ScreenEventEnum, GameObject>(ScreenEventEnum.Selected, OnSelected);
}
private void OnDestroy()
{
EnumEventSystem.Global.UnRegister(ScreenEventEnum.Selected);
}
// ------------------------ 屏幕显示 -------------------------
[Header("屏幕")]
[SerializeField] private UniversalScreen blockPuzzleScreen;
@@ -22,7 +33,7 @@ namespace AibisDream.FixSystem
public void ShowShapeInScreen(BlockShapeInfo shape)
{
blockPuzzleScreen.gameObject.SetActive(true);
EnumEventSystem.Global.Send(ScreenEventEnum.Selected, blockPuzzleScreen.gameObject);
blockPuzzleScreen.SetImage("设备缩略图", shape.GetDetailImage());
@@ -46,6 +57,11 @@ namespace AibisDream.FixSystem
}
}
private void OnSelected(GameObject obj)
{
gameObject.SetActive(obj == blockPuzzleScreen.gameObject);
}
public void ClearShapeInScreen()
{
blockPuzzleScreen.SetImage("设备缩略图", null);
@@ -19,10 +19,6 @@ namespace AibisDream.FixSystem
#region
[Header("其他索引")]
[SerializeField] private FixLightSystem fixLightSystem;
public FixLightSystem FixLightSystem => fixLightSystem;
[Header("插线组件索引")]
[SerializeField] private Plug plugRef;
[SerializeField] private Cable cableRef;
@@ -30,11 +26,15 @@ namespace AibisDream.FixSystem
[SerializeField] private Transform cableRootPos;
[SerializeField] private CableReel cableReelRef;
[Header("灯光系统")]
[SerializeField] private CablePanelLight panelLight;
public Plug PlugRef => plugRef;
public Cable CableRef => cableRef;
public PhysicCable PhysicCableRef => physicCableRef;
public Transform CableRootPos => cableRootPos;
public CableReel CableReelRef => cableReelRef;
public CablePanelLight PanelLight => panelLight;
public BodyModuleSystem BodyModuleSystem { get; private set; }
@@ -52,6 +52,7 @@ namespace AibisDream.FixSystem
private void Start()
{
InitComponentRefs();
panelLight?.Initialize();
InitSystem();
LoadCableState();
@@ -88,19 +89,19 @@ namespace AibisDream.FixSystem
PlugRef.ReturnToStartPosition();
}
// // 从存储系统读取
// if (!StorageSystem.Instance.TryGetValue(CableRetractedKey, out bool savedRetractedState))
// return;
// 从存储系统读取
if (!StorageSystem.Instance.TryGetValue(CableRetractedKey, out bool savedRetractedState))
return;
// if (savedRetractedState)
// {
// SetRetractCable();
// }
// else
// {
// if (isCableRetracted)
// DropDownCable();
// }
if (savedRetractedState)
{
SetRetractCable();
}
else
{
if (isCableRetracted)
DropDownCable();
}
}
private void SaveCableState()
@@ -175,7 +176,7 @@ namespace AibisDream.FixSystem
{
return curSocket != null;
}
// ------------------------------ 线缆操作 ------------------------------
/// <summary>
@@ -189,19 +190,19 @@ namespace AibisDream.FixSystem
{
case CableMode.None:
CableRef.HideCable();
PhysicCableRef.HideCable();
PhysicCableRef.SetEnabled(false);
PhysicCableRef.SetTarget(null);
break;
case CableMode.Visual:
CableRef.ShowCable();
PhysicCableRef.HideCable();
PhysicCableRef.SetEnabled(false);
PhysicCableRef.SetTarget(null);
break;
case CableMode.Physic:
CableRef.HideCable();
PhysicCableRef.ShowCable();
PhysicCableRef.SetEnabled(true);
PhysicCableRef.Init(PlugRef.transform.position);
PhysicCableRef.SetTarget(followTarget != null ? followTarget : PlugRef.transform);
break;
@@ -229,7 +230,7 @@ namespace AibisDream.FixSystem
{
PlugRef.PullUpSocket();
}
BodyModuleSystem.CloseModuleSlots(null);
PlugRef.transform.DOMove(retractedPos.position, 0.1f).OnComplete(() =>
@@ -276,6 +277,61 @@ namespace AibisDream.FixSystem
isCableRetracted = true;
}
#region -
/// <summary>
/// 检查系统是否开启
/// </summary>
public bool IsSystemOn()
{
return panelLight != null && panelLight.IsSystemOn();
}
/// <summary>
/// 启动系统
/// </summary>
public System.Collections.IEnumerator StartSystem()
{
if (panelLight != null)
{
yield return panelLight.StartSystem();
}
}
/// <summary>
/// 更新呼吸灯
/// </summary>
public void UpdateBreathingLight(LightState state)
{
panelLight?.UpdateBreathingLight(state);
}
/// <summary>
/// 更新ECG波形
/// </summary>
public void UpdateECGWave(LightState state)
{
panelLight?.UpdateECGWave(state);
}
/// <summary>
/// 获取当前波形类型
/// </summary>
public RobotECGWave.WaveType GetCurrentWaveType()
{
return panelLight != null ? panelLight.GetCurrentWaveType() : RobotECGWave.WaveType.RobotECG;
}
/// <summary>
/// 设置波形类型
/// </summary>
public void SetWaveType(RobotECGWave.WaveType waveType)
{
panelLight?.SetWaveType(waveType);
}
#endregion
public void Init()
{
@@ -285,10 +341,10 @@ namespace AibisDream.FixSystem
{
}
public void Close()
{
}
}
}
}
@@ -0,0 +1,598 @@
using UnityEngine;
using UnityEngine.Rendering.Universal;
using DG.Tweening;
using AibisDream.Kit;
using AibisDream.Framework;
using System.Collections;
using System.Collections.Generic;
namespace AibisDream.FixSystem
{
/// <summary>
/// CablePanel 灯光系统 - 管理呼吸灯、小灯和ECG波形
/// </summary>
public class CablePanelLight : MonoBehaviour
{
// 灯光系统常量
private const float SELF_CHECK_DELAY = 0.05f;
private const float SELF_CHECK_INTERVAL = 0.1f;
private const float ECG_WAVE_TOGGLE_DELAY = 0.1f;
private const float ECG_WAVE_FINAL_DELAY = 0.2f;
private const float BREATHING_LIGHT_START_DELAY = 0.5f;
private const float BREATHING_LIGHT_MAX_INTENSITY = 1f;
private const int SELF_CHECK_COUNT = 2;
#region
[Header("呼吸灯设置")]
[SerializeField] private Light2D breathingLight;
[SerializeField] private float normalBreathingSpeed = 1f;
[SerializeField] private float warningBreathingSpeed = 2f;
[SerializeField] private float emergencyBreathingSpeed = 3f;
[SerializeField] private Color normalColor = Color.green;
[SerializeField] private Color warningColor = Color.yellow;
[SerializeField] private Color emergencyColor = Color.red;
[SerializeField] private RobotECGWave ecgWave;
private SpriteRenderer breathingLightSprite;
private Tween breathingTween;
#endregion
#region
[Header("小灯设置")]
[SerializeField] private List<Light2D> smallLights = new List<Light2D>();
[SerializeField] private float smallLightBlinkInterval = 0.5f;
[SerializeField] private Color smallLightDefaultColor = Color.yellow;
[SerializeField] private Color smallLightNormalColor = Color.green;
[SerializeField] private Color smallLightErrorColor = Color.red;
[SerializeField] private float operationBlinkDuration = 1f;
[SerializeField] private float operationBlinkInterval = 0.1f;
private List<SpriteRenderer> smallLightSprites = new List<SpriteRenderer>();
private FixLightSystem.SmallLightState smallLightState = FixLightSystem.SmallLightState.Default;
private FixLightSystem.SmallLightStatus smallLightStatus = FixLightSystem.SmallLightStatus.Normal;
#endregion
#region
[SerializeField] private bool isSystemOn = false;
private bool isSystemStarting = false;
private Coroutine smallLightsBlinkCoroutine;
#endregion
#region
private void OnEnable()
{
// 启动小灯闪烁协程
if (smallLightsBlinkCoroutine == null)
{
smallLightsBlinkCoroutine = StartCoroutine(SmallLightsBlinkRoutine());
}
}
private void OnDisable()
{
// 清理所有Tween
breathingTween?.Kill();
breathingTween = null;
// 停止协程
if (smallLightsBlinkCoroutine != null)
{
StopCoroutine(smallLightsBlinkCoroutine);
smallLightsBlinkCoroutine = null;
}
StopAllCoroutines();
}
#endregion
#region
/// <summary>
/// 初始化灯光系统
/// </summary>
public void Initialize()
{
// 初始化SpriteRenderer引用
InitializeSpriteRenderers();
// 初始化系统状态
if (isSystemOn)
{
InitializeSystemOn();
}
else
{
InitializeSystemOff();
}
SetSmallLightState(FixLightSystem.SmallLightState.Default);
}
/// <summary>
/// 初始化SpriteRenderer引用
/// </summary>
private void InitializeSpriteRenderers()
{
// 自动获取呼吸灯的SpriteRenderer
if (breathingLight != null)
{
breathingLightSprite = breathingLight.GetComponentInParent<SpriteRenderer>();
}
// 自动获取小灯的SpriteRenderer
smallLightSprites.Clear();
foreach (var light in smallLights)
{
if (light != null)
{
var spriteRenderer = light.GetComponentInParent<SpriteRenderer>();
smallLightSprites.Add(spriteRenderer);
}
}
}
/// <summary>
/// 系统开启时的初始化
/// </summary>
private void InitializeSystemOn()
{
SetBreathingLight(normalColor, BREATHING_LIGHT_MAX_INTENSITY);
InitializeSmallLights(smallLightDefaultColor, BREATHING_LIGHT_MAX_INTENSITY);
SetECGWaveActive(true);
}
/// <summary>
/// 系统关闭时的初始化
/// </summary>
private void InitializeSystemOff()
{
SetBreathingLight(normalColor, 0f, true);
TurnOffAllSmallLights();
SetECGWaveActive(false);
}
#endregion
#region -
/// <summary>
/// 检查系统是否开启
/// </summary>
public bool IsSystemOn()
{
return isSystemOn;
}
/// <summary>
/// 设置系统电源状态
/// </summary>
public void SetSystemPower(bool isOn)
{
isSystemOn = isOn;
if (!isOn)
{
TurnOffAllLights();
}
else
{
InitializeSystemOn();
}
}
/// <summary>
/// 启动系统
/// </summary>
public IEnumerator StartSystem()
{
if (isSystemStarting || isSystemOn) yield break;
isSystemStarting = true;
yield return StartCoroutine(SystemStartSequence());
isSystemStarting = false;
}
#endregion
#region -
/// <summary>
/// 更新呼吸灯
/// </summary>
public void UpdateBreathingLight(LightState state)
{
if (breathingLight == null) return;
var (color, breathingSpeed) = GetBreathingConfig(state);
SetBreathingLight(color, BREATHING_LIGHT_MAX_INTENSITY);
StartBreathingEffect(breathingSpeed);
}
/// <summary>
/// 更新ECG波形
/// </summary>
public void UpdateECGWave(LightState state)
{
if (ecgWave != null)
{
ecgWave.SetWaveType(GetWaveTypeByState(state));
}
}
#endregion
#region -
/// <summary>
/// 设置小灯状态
/// </summary>
public void SetSmallLightState(FixLightSystem.SmallLightState newState)
{
if (smallLightState != newState)
{
smallLightState = newState;
if (newState == FixLightSystem.SmallLightState.Default)
{
smallLightStatus = FixLightSystem.SmallLightStatus.Normal;
}
StartCoroutine(HandleSmallLightStateChange());
}
}
/// <summary>
/// 设置小灯状态状态
/// </summary>
public void SetSmallLightStatus(FixLightSystem.SmallLightStatus newStatus)
{
if (smallLightStatus != newStatus)
{
smallLightStatus = newStatus;
UpdateSmallLightsStatus();
}
}
#endregion
#region -
/// <summary>
/// 获取当前波形类型
/// </summary>
public RobotECGWave.WaveType GetCurrentWaveType()
{
return ecgWave?.waveType ?? RobotECGWave.WaveType.RobotECG;
}
/// <summary>
/// 设置波形类型
/// </summary>
public void SetWaveType(RobotECGWave.WaveType waveType)
{
if (ecgWave != null)
{
ecgWave.SetWaveType(waveType);
}
}
#endregion
#region
/// <summary>
/// 系统启动序列
/// </summary>
private IEnumerator SystemStartSequence()
{
// 1. ECG波形闪烁
yield return StartCoroutine(ECGWaveToggleSequence());
// 2. 小灯自检
yield return StartCoroutine(SmallLightsSelfCheck());
// 3. 启动呼吸灯
SetBreathingLight(normalColor, BREATHING_LIGHT_MAX_INTENSITY);
yield return new WaitForSeconds(BREATHING_LIGHT_START_DELAY);
// 4. 设置系统状态为开启
SetSystemPower(true);
}
/// <summary>
/// ECG波形闪烁序列
/// </summary>
private IEnumerator ECGWaveToggleSequence()
{
if (ecgWave == null) yield break;
ecgWave.gameObject.SetActive(true);
yield return new WaitForSeconds(ECG_WAVE_TOGGLE_DELAY);
ecgWave.gameObject.SetActive(false);
yield return new WaitForSeconds(ECG_WAVE_TOGGLE_DELAY);
ecgWave.gameObject.SetActive(true);
yield return new WaitForSeconds(ECG_WAVE_FINAL_DELAY);
}
/// <summary>
/// 小灯自检序列
/// </summary>
private IEnumerator SmallLightsSelfCheck()
{
// 关闭所有小灯
SetSmallLightsColorAndIntensity(Color.clear, 0f);
// 自检两次
for (int check = 0; check < SELF_CHECK_COUNT; check++)
{
// 从左到右点亮
for (int i = 0; i < smallLights.Count; i++)
{
if (smallLights[i] != null)
{
smallLights[i].color = smallLightDefaultColor;
smallLights[i].intensity = BREATHING_LIGHT_MAX_INTENSITY;
}
if (i < smallLightSprites.Count && smallLightSprites[i] != null)
{
smallLightSprites[i].color = smallLightDefaultColor;
}
yield return new WaitForSeconds(SELF_CHECK_DELAY);
}
// 关闭所有灯
SetSmallLightsColorAndIntensity(Color.clear, 0f);
yield return new WaitForSeconds(SELF_CHECK_INTERVAL);
}
// 恢复到默认状态(只有第一个灯闪烁)
ResetSmallLightsToDefault();
}
#endregion
#region
/// <summary>
/// 处理小灯状态变化
/// </summary>
private IEnumerator HandleSmallLightStateChange()
{
if (smallLightState == FixLightSystem.SmallLightState.Operation)
{
yield return StartCoroutine(OperationBlinkSequence());
SetSmallLightsToOperationState();
}
else
{
ResetSmallLightsToDefault();
}
}
/// <summary>
/// 运行状态闪烁序列
/// </summary>
private IEnumerator OperationBlinkSequence()
{
float endTime = Time.time + operationBlinkDuration;
while (Time.time < endTime)
{
foreach (var light in smallLights)
{
if (light != null)
{
light.intensity = Random.value > 0.5f ? BREATHING_LIGHT_MAX_INTENSITY : 0f;
}
}
yield return new WaitForSeconds(operationBlinkInterval);
}
}
/// <summary>
/// 设置小灯为运行状态
/// </summary>
private void SetSmallLightsToOperationState()
{
Color targetColor = GetSmallLightColorByStatus();
SetSmallLightsColorAndIntensity(targetColor, BREATHING_LIGHT_MAX_INTENSITY);
}
/// <summary>
/// 根据当前状态获取小灯颜色
/// </summary>
private Color GetSmallLightColorByStatus()
{
return smallLightStatus == FixLightSystem.SmallLightStatus.Normal ? smallLightNormalColor : smallLightErrorColor;
}
/// <summary>
/// 重置小灯为默认状态
/// </summary>
private void ResetSmallLightsToDefault()
{
SetSmallLightsColorAndIntensity(smallLightDefaultColor, 0f);
// 只有第一个灯闪烁
if (smallLights.Count > 0 && smallLights[0] != null)
{
smallLights[0].intensity = BREATHING_LIGHT_MAX_INTENSITY;
if (smallLightSprites.Count > 0 && smallLightSprites[0] != null)
{
smallLightSprites[0].color = smallLightDefaultColor;
}
}
}
/// <summary>
/// 更新小灯状态状态
/// </summary>
private void UpdateSmallLightsStatus()
{
Color targetColor = smallLightStatus == FixLightSystem.SmallLightStatus.Normal
? smallLightNormalColor
: smallLightErrorColor;
SetSmallLightsColorAndIntensity(targetColor, BREATHING_LIGHT_MAX_INTENSITY);
}
/// <summary>
/// 小灯闪烁协程
/// </summary>
private IEnumerator SmallLightsBlinkRoutine()
{
while (true)
{
if (!isSystemOn)
{
TurnOffAllSmallLights();
}
else if (smallLightState == FixLightSystem.SmallLightState.Default)
{
ResetSmallLightsToDefault();
}
yield return new WaitForSeconds(smallLightBlinkInterval);
}
}
/// <summary>
/// 初始化小灯
/// </summary>
private void InitializeSmallLights(Color color, float intensity)
{
SetSmallLightsColorAndIntensity(color, intensity);
}
/// <summary>
/// 设置小灯颜色和强度
/// </summary>
private void SetSmallLightsColorAndIntensity(Color color, float intensity)
{
for (int i = 0; i < smallLights.Count; i++)
{
if (smallLights[i] != null)
{
smallLights[i].color = color;
smallLights[i].intensity = intensity;
}
if (i < smallLightSprites.Count && smallLightSprites[i] != null)
{
smallLightSprites[i].color = color;
}
}
}
/// <summary>
/// 关闭所有小灯
/// </summary>
private void TurnOffAllSmallLights()
{
SetSmallLightsColorAndIntensity(Color.clear, 0f);
}
#endregion
#region
/// <summary>
/// 设置呼吸灯
/// </summary>
private void SetBreathingLight(Color color, float intensity, bool useTransparent = false)
{
if (breathingLight != null)
{
breathingLight.color = color;
breathingLight.intensity = intensity;
}
if (breathingLightSprite != null)
{
breathingLightSprite.color = useTransparent
? new Color(color.r, color.g, color.b, 0f)
: color;
}
}
/// <summary>
/// 启动呼吸效果
/// </summary>
private void StartBreathingEffect(float breathingSpeed)
{
breathingTween?.Kill();
breathingTween = DOTween.To(
() => breathingLight.intensity,
x => breathingLight.intensity = x,
BREATHING_LIGHT_MAX_INTENSITY,
1f / breathingSpeed
)
.SetLoops(-1, LoopType.Yoyo)
.SetEase(Ease.InOutSine);
}
/// <summary>
/// 获取呼吸灯配置
/// </summary>
private (Color color, float breathingSpeed) GetBreathingConfig(LightState state)
{
return state switch
{
LightState.Normal => (normalColor, normalBreathingSpeed),
LightState.Warning => (warningColor, warningBreathingSpeed),
LightState.Emergency => (emergencyColor, emergencyBreathingSpeed),
_ => (normalColor, normalBreathingSpeed)
};
}
#endregion
#region ECG波形相关方法
/// <summary>
/// 根据状态获取波形类型
/// </summary>
private RobotECGWave.WaveType GetWaveTypeByState(LightState state)
{
return state switch
{
LightState.Normal => RobotECGWave.WaveType.RobotECG,
LightState.Warning => RobotECGWave.WaveType.Warning,
LightState.Emergency => RobotECGWave.WaveType.Noise,
_ => RobotECGWave.WaveType.RobotECG
};
}
/// <summary>
/// 设置ECG波形激活状态
/// </summary>
private void SetECGWaveActive(bool active)
{
if (ecgWave != null)
{
ecgWave.gameObject.SetActive(active);
}
}
#endregion
#region
/// <summary>
/// 关闭所有灯光
/// </summary>
private void TurnOffAllLights()
{
SetBreathingLight(normalColor, 0f, true);
TurnOffAllSmallLights();
SetECGWaveActive(false);
}
#endregion
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b4c48f8562d6b3648b9b7ca0922aee14
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -11,14 +11,21 @@ namespace AibisDream.FixSystem
[SerializeField] private TMP_Text title;
[SerializeField] private TerminalText logText;
private void OnEnable()
private void Awake()
{
EnumEventSystem.Global.Register<ScreenEventEnum, GameObject>(ScreenEventEnum.Selected, OnSelected);
EnumEventSystem.Global.Register(EventEnum.PlugOut, ClearScreen);
}
private void OnDisable()
private void OnDestroy()
{
EnumEventSystem.Global.UnRegister(EventEnum.PlugOut, ClearScreen);
EnumEventSystem.Global.UnRegister(ScreenEventEnum.Selected);
EnumEventSystem.Global.UnRegister(EventEnum.PlugOut);
}
private void OnSelected(GameObject obj)
{
gameObject.SetActive(obj == gameObject);
}
// ---------------------- 对话框功能 ----------------------
@@ -26,6 +33,8 @@ namespace AibisDream.FixSystem
{
if (logText != null)
{
EnumEventSystem.Global.Send(ScreenEventEnum.Selected, gameObject);
logText.OnTextShown += () => token.TextShown();
title.text = token.lineInfo.character.GetActorName();
@@ -27,9 +27,6 @@ namespace AibisDream.FixSystem
public TaskScreen TaskScreen { get; private set; }
[SerializeField] private FixLightSystem fixLightSystem;
public FixLightSystem FixLightSystem => fixLightSystem;
#endregion
private void Awake()
@@ -44,12 +41,6 @@ namespace AibisDream.FixSystem
_lineQueue = new Queue<TypewriterByCharacter>();
_textItemPrefab = ResourceKit.LoadAssetSync<GameObject>(ConstRef.ScreenTextName);
BubbleSlotGroup = GetComponentInChildren<BubbleSlotGroup>();
// 如果没有手动指定,尝试自动获取 FixLightSystem
if (fixLightSystem == null)
{
fixLightSystem = GetComponentInChildren<FixLightSystem>();
}
}
private void Register()
@@ -6,7 +6,9 @@ namespace AibisDream
{
public static class ScreenYarnCommand
{
private static FixLightSystem LightSystem => FixPanelSystem.GetRepairPanel<CablePanel>().FixLightSystem;
private static CablePanel CablePanel => FixPanelSystem.GetRepairPanel<CablePanel>();
private static CablePanelLight CablePanelLight => CablePanel?.PanelLight;
private static FixPanelLight PanelLight => FixPanelSystem.Instance?.PanelLight;
private static TaskPanel TaskPanel => FixPanelSystem.Instance.TaskPanel;
private static ScreenPanel ScreenPanel => FixPanelSystem.Instance.ScreenPanel;
@@ -39,64 +41,64 @@ namespace AibisDream
#endregion
#region FixLightSystem相关命令
#region
[YarnCommand("set_light_state")]
public static void SetLightState(string state)
{
if (LightSystem == null) return;
if (System.Enum.TryParse<FixLightSystem.LightState>(state, true, out var lightState))
if (FixPanelSystem.Instance == null) return;
if (System.Enum.TryParse<LightState>(state, true, out var lightState))
{
LightSystem.SetLightState(lightState);
FixPanelSystem.Instance.SetLightState(lightState);
}
}
[YarnCommand("set_small_light_state")]
public static void SetSmallLightState(string state)
{
if (LightSystem == null) return;
if (CablePanelLight == null) return;
if (System.Enum.TryParse<FixLightSystem.SmallLightState>(state, true, out var smallLightState))
{
LightSystem.SetSmallLightState(smallLightState);
CablePanelLight.SetSmallLightState(smallLightState);
}
}
[YarnCommand("set_small_light_status")]
public static void SetSmallLightStatus(string status)
{
if (LightSystem == null) return;
if (CablePanelLight == null) return;
if (System.Enum.TryParse<FixLightSystem.SmallLightStatus>(status, true, out var smallLightStatus))
{
LightSystem.SetSmallLightStatus(smallLightStatus);
CablePanelLight.SetSmallLightStatus(smallLightStatus);
}
}
[YarnCommand("set_environment_light_flickering")]
public static void SetEnvironmentLightFlickering(bool isFlickering)
{
if (LightSystem == null) return;
LightSystem.SetEnvironmentLightFlickering(isFlickering);
if (PanelLight == null) return;
PanelLight.SetEnvironmentLightFlickering(isFlickering);
}
[YarnCommand("set_alarm_blink_speed")]
public static void SetAlarmBlinkSpeed(float speed)
{
if (LightSystem == null) return;
LightSystem.SetAlarmBlinkSpeed(speed);
if (PanelLight == null) return;
PanelLight.SetAlarmBlinkSpeed(speed);
}
[YarnCommand("stop_alarm_light")]
public static void StopAlarmLight()
{
if (LightSystem == null) return;
LightSystem.StopAlarmLight();
if (PanelLight == null) return;
PanelLight.StopAlarmLight();
}
[YarnCommand("start_system")]
public static IEnumerator StartSystem()
{
if (LightSystem == null) yield break;
yield return LightSystem.StartSystem();
if (FixPanelSystem.Instance == null) yield break;
yield return FixPanelSystem.Instance.StartAllSystems();
}
#endregion
+5
View File
@@ -39,6 +39,11 @@ namespace AibisDream
DialogEnd
}
public enum ScreenEventEnum
{
Selected
}
public struct DialogText
{
public bool isOption;
@@ -15,9 +15,10 @@ namespace AibisDream
// 物体索引
[SerializeField] public BlockPuzzleGrid grid;
[SerializeField] private Transform shapeRoot;
[SerializeField] public BlockPuzzlePanel blockPuzzlePanel;
[SerializeField] private ShapeRecycleSlot shapeRecycleSlot;
private BlockPuzzlePanel blockPuzzlePanel;
[Header("数据")]
[SerializeField] private BlockPuzzleData puzzleData;
[SerializeField] private bool initializeOnStart = true;
@@ -33,6 +34,9 @@ namespace AibisDream
private void Start()
{
FixSystemCenter.SystemDic.Register(this);
blockPuzzlePanel = FixPanelSystem.GetRepairPanel<BlockPuzzlePanel>();
if (initializeOnStart)
{
Initialize();
@@ -43,6 +47,7 @@ namespace AibisDream
public override void OnSingletonDestroy()
{
FixSystemCenter.SystemDic.Unregister<BlockPuzzleSystem>();
CameraKit.Instance?.UnRegisterCamera(CameraEnum.BlockPuzzle);
}