using System.Collections; using System.Collections.Generic; using System.Linq; using AibisDream; using AibisDream.FixSystem; using AibisDream.Framework; using DG.Tweening; using RainbowArt.CleanFlatUI; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.UI; /// /// 电击器系统。拉杆交互通过 EventTriggerEx 统一管理,支持 EventSystemEx.isLocked 与 IInteraction, /// 光标由 EventTriggerEx → EventSystemEx → CursorManager 自动驱动。 /// public class ShockSystem : MonoBehaviour, IInteraction { [Header("References")] [SerializeField] private Transform shockDevice; // 电击器 [SerializeField] private Transform leftShockDevice; // 左电击装置 [SerializeField] private Transform rightShockDevice; // 右电击装置 [SerializeField] private Transform operationPanel; // 操作面板 [SerializeField] private ProgressBarGridLinear progressBar; // 进度条 [SerializeField] private Transform lever; // 转动杆 [SerializeField] private SpriteRenderer flashHeadSpriteRenderer; // 头部闪烁精灵渲染器 [SerializeField] private SpriteRenderer flashBackgroundSpriteRenderer; // 背景闪烁精灵渲染器 [SerializeField] private SpriteRenderer flashSpriteRenderer; [SerializeField] private List flashHeadSprites; // 当前生效的头部闪烁精灵列表(运行时由两套资源切换) [SerializeField] private List flashHeadSpritesWithMemory; // 切割记忆模块前:带记忆模块 [SerializeField] private List flashHeadSpritesWithoutMemory; // 切割记忆模块后:不带记忆模块 [SerializeField] private bool useMemoryModuleFlashSprites = true; // 是否使用带记忆模块的电击图 [SerializeField] private SpriteFlashSystem spriteFlashSystem; // Sprite闪烁系统 [SerializeField] private GameObject sparkEffect1; // 火花特效1 [SerializeField] private GameObject sparkEffect2; // 火花特效2 [SerializeField] private Image progressBarFg; // 进度条前景 [Header("Settings")] [SerializeField] private bool isSystemOn = false; // 系统开关状态 [SerializeField] private Vector3 leftShockDeviceTargetPos; // 左电击装置目标位置 [SerializeField] private Vector3 rightShockDeviceTargetPos; // 右电击装置目标位置 [SerializeField] private Vector3 leftShockDeviceStartPos; // 左电击装置起始位置 [SerializeField] private Vector3 rightShockDeviceStartPos; // 右电击装置起始位置 [SerializeField] private Vector3 operationPanelTargetPos; // 操作面板目标位置 [SerializeField] private Vector3 operationPanelStartPos; // 操作面板起始位置 [SerializeField] private float moveDuration = 1f; // 移动动画时长 [SerializeField] private float shockDelay = 0.5f; // 释放电击延迟 [SerializeField] private float progressIncreaseSpeed = 1f; // 进度增加基础速度 [SerializeField] private float maxSliderValue = 3f; // 滑块最大值 [SerializeField] private float progressDecreaseDuration = 1f; // 进度下降持续时间 [SerializeField] private string shockEffectNode = "ShockEffect"; // 电击效果节点名称 [Header("Shock Effects")] [SerializeField] private float flashDuration = 0.1f; // 每次闪烁持续时间 [SerializeField] private float flashInterval = 0.1f; // 闪烁间隔 [SerializeField] private int flashCount = 3; // 闪烁次数 [SerializeField] private float strength = 1f; // 震动强度 [SerializeField] private int vibrate = 10; // 震动次数 [SerializeField] private float minVibrateStrength = 0.05f; // 最小震动强度 [SerializeField] private float maxVibrateStrength = 0.2f; // 最大震动强度 [SerializeField] private float vibrateInterval = 0.1f; // 震动间隔 [SerializeField] private float deviceShakeAmount = 0.1f; // 电击器震动幅度 [SerializeField] private float deviceShakeSpeed = 10f; // 电击器震动速度 [Header("Auto Charge Settings")] [SerializeField] private float autoChargeSpeed = 5f; // 自动充能速度 [SerializeField] private float autoChargeDuration = 1f; // 自动充能持续时间 [Header("Lever Settings")] [SerializeField] private float maxLeverAngle = 90f; // 最大转动角度 [SerializeField] private float leverReturnSpeed = 300f; // 杆回弹速度 [SerializeField] private float leverSmoothTime = 0.1f; // 杆转动平滑时间 [Header("Abnormal State Settings")] [SerializeField] private bool isAbnormalState = false; // 是否处于异常状态 [SerializeField] private float abnormalLeverShakeAmount = 30f; // 异常状态下拉杆震动幅度 [SerializeField] private float abnormalLeverShakeSpeed = 20f; // 异常状态下拉杆震动速度 [SerializeField] private float abnormalPanelShakeAmount = 0.1f; // 异常状态下面板震动幅度 [SerializeField] private float abnormalPanelShakeSpeed = 15f; // 异常状态下面板震动速度 [SerializeField] private Color abnormalProgressBarColor = Color.red; // 异常状态下进度条颜色 [Header("Audio Settings")] [SerializeField] private string chargingEvent = "event:/FollowInput/defib/defib_charging"; [SerializeField] private string shockEvent = "event:/FollowInput/defib/defib_shock"; [SerializeField] private string defibProgressParam = "defibProgress"; [SerializeField] private string shockReverbParam = "reverb"; [SerializeField] private float shockFlashDelay = 0.05f; // 声音与闪烁的延迟,可配置 [Range(0,1)] public float shockReverb = 0f; // 0=真实,1=梦境 private string chargingAudioKey = "defib_charging"; private string shockAudioKey = "defib_shock"; private bool isCharging = false; private float currentProgress = 0f; private float currentLeverAngle = 0f; // 当前杆的角度 private float targetLeverAngle = 0f; // 目标杆的角度 private float leverVelocity = 0f; // 用于平滑转动 private bool isDraggingLever = false; // 是否正在拖动杆 private Vector3 lastMousePosition; // 上一帧鼠标位置 private Tweener progressTweener; // 用于存储进度条动画 private Sequence flashSequence; // 用于存储闪烁动画序列 private int currentFlashHeadIndex = 0; // 当前闪烁头部精灵索引 private float lastVibrateTime = 0f; // 上次震动时间 private Vector3 leftDeviceOriginalPos; // 左电击装置原始位置 private Vector3 rightDeviceOriginalPos; // 右电击装置原始位置 private Tweener deviceShakeTweener; // 电击器震动动画 private Tweener abnormalLeverShakeTweener; // 异常状态下拉杆震动动画 private Tweener abnormalPanelShakeTweener; // 异常状态下面板震动动画 private Color normalProgressBarColor; // 正常状态下进度条颜色 private EventTriggerEx _eventTrigger; private ShockLeverInteractionBridge _leverBridge; private bool _useEventTrigger; private bool _leverInputLocked; private bool _leverPointerOver; // 公共访问器 public float FlashDuration => flashDuration; public float FlashInterval => flashInterval; public int FlashCount => flashCount; #region IInteraction public bool IsActive => true; public bool IsAvailable => !isAbnormalState && !_leverInputLocked; public GameObject GetGameObject() => gameObject; #endregion private void Awake() { FixSystemCenter.SystemDic.Register(this); EnsureLeverInteraction(); } /// /// 为拉杆挂接 ShockLeverInteractionBridge + EventTriggerEx(对齐 CrankController)。 /// 悬停光标另用 LateUpdate 射线校正:指针 Collider 细长且会旋转,EventSystem 易丢 PointerExit。 /// private void EnsureLeverInteraction() { if (lever == null) return; var leverGo = lever.gameObject; if (leverGo.GetComponent() == null) { #if UNITY_EDITOR Debug.LogWarning("[ShockSystem] 拉杆未找到 Collider2D!请添加 Collider2D 以接入交互与光标。", this); #endif return; } _leverBridge = leverGo.GetComponent(); if (_leverBridge == null) _leverBridge = leverGo.AddComponent(); _eventTrigger = leverGo.GetComponent(); if (_eventTrigger == null) _eventTrigger = leverGo.AddComponent(); _useEventTrigger = true; EnsureEventTriggerEntries(); _eventTrigger.Register(EventTriggerType.PointerDown, OnEventPointerDown); _eventTrigger.Register(EventTriggerType.PointerUp, OnEventPointerUp); _eventTrigger.Register(EventTriggerType.Drag, OnEventDrag); } private void EnsureEventTriggerEntries() { if (_eventTrigger == null) return; var triggers = _eventTrigger.triggers; var needed = new[] { EventTriggerType.PointerDown, EventTriggerType.PointerUp, EventTriggerType.Drag }; foreach (var t in needed) { if (triggers.Any(e => e.eventID == t)) continue; triggers.Add(new EventTrigger.Entry { eventID = t }); } } private void Start() { // 保存电击器原始位置 if (leftShockDevice != null) { leftDeviceOriginalPos = leftShockDevice.localPosition; } if (rightShockDevice != null) { rightDeviceOriginalPos = rightShockDevice.localPosition; } if (operationPanel != null) { operationPanelStartPos = operationPanel.localPosition; } // 初始化杆的位置 if (lever != null) { lever.localRotation = Quaternion.Euler(0, 0, 0); } // 保存正常状态下的进度条颜色 if (progressBarFg != null) { normalProgressBarColor = progressBarFg.color; } // 确保火花效果初始状态为关闭 if (sparkEffect1 != null) sparkEffect1.SetActive(false); if (sparkEffect2 != null) sparkEffect2.SetActive(false); ApplyFlashHeadSpriteSet(useMemoryModuleFlashSprites); } /// /// 切换电击闪烁用的头部图集:切割记忆模块前用带模块图,切后用不带模块图。 /// public void SetUseMemoryModuleFlashSprites(bool useMemoryModule) { ApplyFlashHeadSpriteSet(useMemoryModule); } private void ApplyFlashHeadSpriteSet(bool useMemoryModule) { useMemoryModuleFlashSprites = useMemoryModule; var source = useMemoryModule ? flashHeadSpritesWithMemory : flashHeadSpritesWithoutMemory; if (source != null && source.Count > 0) { flashHeadSprites = source; } #if UNITY_EDITOR else { Debug.LogWarning( $"[ShockSystem] {(useMemoryModule ? "带记忆" : "不带记忆")}电击闪烁图列表为空,仍使用当前 flashHeadSprites。", this); } #endif } /// /// 按 Yarn $gameStage 同步图集:1–2 带记忆模块,≥3(已切除)不带。兼容读档。 /// private void SyncFlashSpritesFromYarnState() { var storage = YarnVariableStorage.Instance; if (storage == null) return; if (!storage.TryGetValue("$gameStage", out float stage)) return; ApplyFlashHeadSpriteSet(stage < 3f); } private void Update() { if (isAbnormalState) { UpdateAbnormalState(); } else { if (_useEventTrigger) UpdateLeverReturn(); else HandleLeverInputFallback(); UpdateLeverRotation(); UpdateCharging(); } } private void LateUpdate() { SyncLeverHoverCursor(); } #region 拉杆输入(EventTriggerEx 驱动 / 回退) private bool IsMouseOverLever() { if (lever == null) return false; var cam = Camera.main; if (cam == null) return false; Ray ray = cam.ScreenPointToRay(Input.mousePosition); RaycastHit2D hit = Physics2D.GetRayIntersection(ray, float.MaxValue); if (hit.collider != null && hit.collider.transform == lever) return true; hit = Physics2D.Raycast(ray.origin, ray.direction); return hit.collider != null && hit.collider.transform == lever; } /// /// 以射线结果校正悬停光标,弥补细长旋转 Collider 丢失 PointerExit 的情况。 /// private void SyncLeverHoverCursor() { if (_leverBridge == null || EventSystemEx.Instance == null) return; bool over = IsAvailable && IsMouseOverLever(); if (over == _leverPointerOver) return; _leverPointerOver = over; if (over) EventSystemEx.Instance.OnPointerEnter(_leverBridge); else EventSystemEx.Instance.OnPointerExit(_leverBridge); } private void OnEventPointerDown(BaseEventData eventData) { if (!IsAvailable || (EventSystemEx.Instance != null && EventSystemEx.Instance.isLocked)) return; if (eventData is not PointerEventData { button: PointerEventData.InputButton.Left } pointerData) return; isDraggingLever = true; lastMousePosition = pointerData.position; } private void OnEventPointerUp(BaseEventData eventData) { if (eventData is not PointerEventData { button: PointerEventData.InputButton.Left }) return; EndLeverDrag(); } private void OnEventDrag(BaseEventData eventData) { if (!isDraggingLever || !IsAvailable || (EventSystemEx.Instance != null && EventSystemEx.Instance.isLocked)) return; if (eventData is not PointerEventData pointerData) return; ApplyLeverDrag(pointerData.position); } /// 无 EventTriggerEx 时回退到 Input + Raycast。 private void HandleLeverInputFallback() { if (!IsAvailable || (EventSystemEx.Instance != null && EventSystemEx.Instance.isLocked)) { UpdateLeverReturn(); return; } if (Input.GetMouseButtonDown(0)) { var cam = Camera.main; if (cam != null && lever != null) { Ray ray = cam.ScreenPointToRay(Input.mousePosition); RaycastHit2D hit = Physics2D.GetRayIntersection(ray, float.MaxValue); if (hit.collider != null && hit.collider.transform == lever) { isDraggingLever = true; lastMousePosition = Input.mousePosition; } } } else if (Input.GetMouseButtonUp(0)) { EndLeverDrag(); } if (isDraggingLever) ApplyLeverDrag(Input.mousePosition); else UpdateLeverReturn(); } private void ApplyLeverDrag(Vector3 mousePosition) { Vector3 mouseDelta = mousePosition - lastMousePosition; float angleDelta = mouseDelta.x * 0.5f; targetLeverAngle = Mathf.Clamp(targetLeverAngle + angleDelta, 0f, maxLeverAngle); lastMousePosition = mousePosition; float progressRatio = targetLeverAngle / maxLeverAngle; if (progressRatio <= 0f) { if (isCharging) { isCharging = false; ResetProgress(); } return; } if (progressRatio > 0 && !isCharging) { progressTweener?.Kill(); progressTweener = null; isCharging = true; StartCharging(); AibisDream.Kit.AudioManager.Instance.PlaySfx(chargingEvent, chargingAudioKey); } } private void UpdateLeverReturn() { if (isDraggingLever) return; targetLeverAngle = Mathf.MoveTowards(targetLeverAngle, 0f, leverReturnSpeed * Time.deltaTime); if (targetLeverAngle < 0.1f && isCharging) { isCharging = false; if (currentProgress >= progressBar.MaxValue) DialogController.Instance.StartDialogNode(shockEffectNode); ResetProgress(); } } private void EndLeverDrag() { if (!isDraggingLever && !isCharging) { isDraggingLever = false; return; } isDraggingLever = false; if (!isCharging) return; isCharging = false; bool shouldShock = currentProgress >= progressBar.MaxValue; ResetProgress(); // 先清交互光标状态,再开对话(DialogStart 会 isLocked,旧逻辑会跳过 Up/EndDrag 清理) if (_leverBridge != null && EventSystemEx.Instance != null) EventSystemEx.Instance.UnRegister(_leverBridge); _leverPointerOver = false; if (shouldShock) DialogController.Instance.StartDialogNode(shockEffectNode); } private void ForceClearLeverInteraction() { isDraggingLever = false; if (isCharging) { isCharging = false; ResetProgress(); } if (_leverBridge != null && EventSystemEx.Instance != null) EventSystemEx.Instance.UnRegister(_leverBridge); _leverPointerOver = false; } #endregion private void UpdateLeverRotation() { if (lever != null) { currentLeverAngle = Mathf.SmoothDamp(currentLeverAngle, targetLeverAngle, ref leverVelocity, leverSmoothTime); lever.localRotation = Quaternion.Euler(0, 0, -currentLeverAngle); } } // public void InitializeShock() // { // // 移动电击器和操作面板到指定位置 // shockDevice.DOLocalMove(shockDeviceTargetPos, moveDuration); // operationPanel.DOLocalMove(operationPanelTargetPos, moveDuration); // powerSlider.EnableSliderInteraction(); // } // public void SetFlashBack(bool useFlashback,) // { // this.useFlashback = useFlashback; // } public IEnumerator StartShock() { SyncFlashSpritesFromYarnState(); // 移动左右电击装置到各自的目标位置 var moveLeft = leftShockDevice.DOLocalMove(leftShockDeviceTargetPos, moveDuration); var moveRight = rightShockDevice.DOLocalMove(rightShockDeviceTargetPos, moveDuration); var movePanel = operationPanel.DOLocalMove(operationPanelTargetPos, moveDuration); yield return moveLeft.WaitForCompletion(); yield return moveRight.WaitForCompletion(); yield return movePanel.WaitForCompletion(); } public IEnumerator StopShock() { var moveLeft = leftShockDevice.DOLocalMove(leftDeviceOriginalPos, moveDuration); var moveRight = rightShockDevice.DOLocalMove(rightDeviceOriginalPos, moveDuration); var movePanel = operationPanel.DOLocalMove(operationPanelStartPos, moveDuration); yield return moveLeft.WaitForCompletion(); yield return moveRight.WaitForCompletion(); yield return movePanel.WaitForCompletion(); } private void ResetProgress() { // 停止充能音效 AibisDream.Kit.AudioManager.Instance.StopSfx(chargingAudioKey); // 开始进度条平滑下降 if (progressTweener != null) { progressTweener.Kill(); } float startProgress = currentProgress; progressTweener = DOTween.To( () => currentProgress, x => { currentProgress = x; progressBar.CurrentValue = Mathf.FloorToInt(x); }, 0f, progressDecreaseDuration ).SetEase(Ease.OutQuad); } private void UpdateCharging() { if (!isCharging) return; // 根据杆的角度计算进度增加速度 float progressRatio = currentLeverAngle / maxLeverAngle; float speedMultiplier = 1f + progressRatio; currentProgress += progressIncreaseSpeed * speedMultiplier * Time.deltaTime; // 更新进度条 int progressValue = Mathf.FloorToInt(currentProgress); progressBar.CurrentValue = progressValue; // 同步defibProgress参数到音频 float progressParam = Mathf.Clamp01(currentProgress / progressBar.MaxValue); AibisDream.Kit.AudioManager.Instance.SetSfxParam(chargingAudioKey, defibProgressParam, progressParam); // 计算震动强度 float currentVibrateStrength = Mathf.Lerp(minVibrateStrength, maxVibrateStrength, progressRatio); // 检查是否需要震动 if (Time.time - lastVibrateTime >= vibrateInterval) { // 电击器震动 if (shockDevice != null) { if (deviceShakeTweener != null) { deviceShakeTweener.Kill(); } // 计算电击器震动幅度(随进度增加) float currentShakeAmount = deviceShakeAmount * progressRatio; // 创建电击器震动动画 deviceShakeTweener = shockDevice.DOShakePosition( vibrateInterval, currentShakeAmount, vibrate, deviceShakeSpeed, false, false ).SetEase(Ease.Linear); } lastVibrateTime = Time.time; } // 检查是否达到最大值 if (currentProgress >= progressBar.MaxValue) { // 保持最大值 currentProgress = progressBar.MaxValue; progressBar.CurrentValue = Mathf.FloorToInt(currentProgress); // 触发释放效果 DialogController.Instance.StartDialogNode(shockEffectNode); // 停止充能 isCharging = false; // 强制杆回弹 targetLeverAngle = 0f; // 重置进度 ResetProgress(); } } private void StartCharging() { if (!isCharging) return; // 重置上次震动时间 lastVibrateTime = Time.time; } public IEnumerator PlayFlashEffect() { SyncFlashSpritesFromYarnState(); if (flashSequence != null) { flashSequence.Kill(); } // 先播放shock音效 AibisDream.Kit.AudioManager.Instance.PlaySfx(shockEvent, shockAudioKey); // 设置reverb参数 AibisDream.Kit.AudioManager.Instance.SetSfxParam(shockAudioKey, shockReverbParam, shockReverb); // 延迟shockFlashDelay秒后再闪烁 yield return new WaitForSeconds(shockFlashDelay); // 获取ECG波形组件 var cablePanel = FixPanelSystem.GetRepairPanel(); 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 } if (flashBackgroundSpriteRenderer != null) { flashBackgroundSpriteRenderer.gameObject.SetActive(true); flashBackgroundSpriteRenderer.color = new Color(0, 0, 0, 1f); // 确保初始alpha为0 } // 设置ECG为直线 if (cablePanel != null) { cablePanel.SetWaveType(RobotECGWave.WaveType.Flatline); } // 创建指定次数的闪烁 for (int i = 0; i < flashCount; i++) { flashSequence.AppendCallback(() => { // 设置背景颜色:第1、3张为黑,第2张为白 StartCoroutine(CameraKit.Instance.ShakeCamera(flashDuration, strength, vibrate)); if (currentFlashHeadIndex == 1) { flashBackgroundSpriteRenderer.color = Color.white; } else { flashBackgroundSpriteRenderer.color = Color.black; } // 切换头部图片 if (flashHeadSprites.Count > 0) { flashHeadSpriteRenderer.sprite = flashHeadSprites[currentFlashHeadIndex]; currentFlashHeadIndex = (currentFlashHeadIndex + 1) % flashHeadSprites.Count; } }); flashSequence.AppendInterval(flashDuration); if (i < flashCount - 1) { flashSequence.AppendInterval(flashInterval); } } // 最后整体淡出 if (flashHeadSpriteRenderer != null) { flashSequence.Append(flashHeadSpriteRenderer.DOFade(0f, flashDuration)); } if (flashBackgroundSpriteRenderer != null) { flashSequence.Join(flashBackgroundSpriteRenderer.DOFade(0f, flashDuration)); } // 等待序列完成 yield return flashSequence.WaitForCompletion(); // 恢复ECG波形 if (cablePanel != null && originalWaveType.HasValue) { cablePanel.SetWaveType(originalWaveType.Value); flashHeadSpriteRenderer.gameObject.SetActive(false); flashHeadSpriteRenderer.color = new Color(1, 1, 1, 0); flashHeadSpriteRenderer.sprite = flashHeadSprites[0]; } if (flashBackgroundSpriteRenderer != null) { flashBackgroundSpriteRenderer.gameObject.SetActive(false); flashBackgroundSpriteRenderer.color = new Color(0, 0, 0, 0); } } private void UpdateAbnormalState() { // 在异常状态下,拉杆会不受控制地震动 if (lever != null) { float randomAngle = Mathf.Sin(Time.time * abnormalLeverShakeSpeed) * abnormalLeverShakeAmount; lever.localRotation = Quaternion.Euler(0, 0, randomAngle); } // 更新充能状态 UpdateCharging(); } public void SetAbnormalState(bool isAbnormal) { isAbnormalState = isAbnormal; if (isAbnormal) { ForceClearLeverInteraction(); StartAbnormalEffects(); } else { StopAbnormalEffects(); } } private void StartAbnormalEffects() { // 设置进度条颜色为红色 if (progressBarFg != null) { progressBarFg.color = abnormalProgressBarColor; } // 启动面板震动,使用随机参数 if (operationPanel != null) { StartCoroutine(RandomPanelShake()); } // 激活火花特效并添加随机闪烁 if (sparkEffect1 != null) { sparkEffect1.SetActive(true); StartCoroutine(RandomSparkEffect(sparkEffect1)); } if (sparkEffect2 != null) { sparkEffect2.SetActive(true); StartCoroutine(RandomSparkEffect(sparkEffect2)); } } private IEnumerator RandomPanelShake() { while (isAbnormalState) { // 随机震动参数 float randomAmount = Random.Range(abnormalPanelShakeAmount * 0.5f, abnormalPanelShakeAmount * 1.5f); float randomSpeed = Random.Range(abnormalPanelShakeSpeed * 0.7f, abnormalPanelShakeSpeed * 1.3f); float randomDuration = Random.Range(0.2f, 0.5f); if (abnormalPanelShakeTweener != null) { abnormalPanelShakeTweener.Kill(); } abnormalPanelShakeTweener = operationPanel.DOShakePosition( randomDuration, randomAmount, vibrate, randomSpeed, false, false ).SetEase(Ease.Linear); yield return new WaitForSeconds(randomDuration); } } private IEnumerator RandomSparkEffect(GameObject sparkEffect) { while (isAbnormalState) { // 随机闪烁间隔 float randomInterval = Random.Range(0.1f, 0.3f); sparkEffect.SetActive(!sparkEffect.activeSelf); yield return new WaitForSeconds(randomInterval); } } private void StopAbnormalEffects() { // 恢复进度条颜色 if (progressBarFg != null) { progressBarFg.color = normalProgressBarColor; } // 停止面板震动 if (abnormalPanelShakeTweener != null) { abnormalPanelShakeTweener.Kill(); } // 停止拉杆震动 if (abnormalLeverShakeTweener != null) { abnormalLeverShakeTweener.Kill(); } // 关闭火花特效 if (sparkEffect1 != null) sparkEffect1.SetActive(false); if (sparkEffect2 != null) sparkEffect2.SetActive(false); } // 自动充能并释放 public IEnumerator AutoChargeAndRelease(float duration = 1f) { bool originalAbnormalState = isAbnormalState; isAbnormalState = false; _leverInputLocked = true; ForceClearLeverInteraction(); // 设置杆的角度 targetLeverAngle = maxLeverAngle; currentLeverAngle = maxLeverAngle; lever.localRotation = Quaternion.Euler(0, 0, -maxLeverAngle); // 开始充能 isCharging = true; StartCharging(); // 计算需要的充能速度 float targetProgress = progressBar.MaxValue; float chargeSpeed = targetProgress / duration; float originalProgressIncreaseSpeed = progressIncreaseSpeed; progressIncreaseSpeed = chargeSpeed; // 等待充能完成 float startTime = Time.time; while (Time.time - startTime < duration) { UpdateCharging(); yield return null; } // 恢复原始设置 progressIncreaseSpeed = originalProgressIncreaseSpeed; isCharging = false; _leverInputLocked = false; // 重置杆的角度 targetLeverAngle = 0f; ResetProgress(); // 恢复异常状态 isAbnormalState = originalAbnormalState; } // 使用默认参数的自动充能方法 public IEnumerator AutoChargeAndRelease() { yield return AutoChargeAndRelease(autoChargeDuration); } private void OnDestroy() { if (_eventTrigger != null) { _eventTrigger.UnRegister(EventTriggerType.PointerDown, OnEventPointerDown); _eventTrigger.UnRegister(EventTriggerType.PointerUp, OnEventPointerUp); _eventTrigger.UnRegister(EventTriggerType.Drag, OnEventDrag); } ForceClearLeverInteraction(); if (progressTweener != null) { progressTweener.Kill(); } if (flashSequence != null) { flashSequence.Kill(); } if (deviceShakeTweener != null) { deviceShakeTweener.Kill(); } if (abnormalLeverShakeTweener != null) { abnormalLeverShakeTweener.Kill(); } if (abnormalPanelShakeTweener != null) { abnormalPanelShakeTweener.Kill(); } } // 设置系统电源状态 public void SetSystemPower(bool isOn) { isSystemOn = isOn; // 更新灯光状态 if (isSystemOn) { if (flashHeadSpriteRenderer != null) { flashHeadSpriteRenderer.gameObject.SetActive(true); flashHeadSpriteRenderer.color = new Color(1, 1, 1, 1); } if (flashBackgroundSpriteRenderer != null) { flashBackgroundSpriteRenderer.gameObject.SetActive(true); flashBackgroundSpriteRenderer.color = new Color(0, 0, 0, 1); } } else { if (flashHeadSpriteRenderer != null) { flashHeadSpriteRenderer.gameObject.SetActive(false); flashHeadSpriteRenderer.color = new Color(1, 1, 1, 0); } if (flashBackgroundSpriteRenderer != null) { flashBackgroundSpriteRenderer.gameObject.SetActive(false); flashBackgroundSpriteRenderer.color = new Color(0, 0, 0, 0); } } } } /// /// 电击器拉杆交互桥接:挂在 Collider 所在子物体上,将 IInteraction 转交给父级 ShockSystem(对齐 CrankInteractionBridge)。 /// public class ShockLeverInteractionBridge : MonoBehaviour, IInteraction { private ShockSystem _shockSystem; private void Awake() { _shockSystem = GetComponentInParent(); } public bool IsActive => _shockSystem?.IsActive ?? true; public bool IsAvailable => _shockSystem?.IsAvailable ?? true; public GameObject GetGameObject() => gameObject; }