diff --git a/Assets/Scripts/FixSystemNew/Open/ShockSystem.cs b/Assets/Scripts/FixSystemNew/Open/ShockSystem.cs index 0f6de8d8b..d425c27bd 100644 --- a/Assets/Scripts/FixSystemNew/Open/ShockSystem.cs +++ b/Assets/Scripts/FixSystemNew/Open/ShockSystem.cs @@ -1,16 +1,20 @@ -using UnityEngine; -using UnityEngine.UI; -using DG.Tweening; -using TMPro; -using RainbowArt.CleanFlatUI; +using System.Collections; using System.Collections.Generic; -using AibisDream.Framework; -using UnityEngine.EventSystems; +using System.Linq; +using AibisDream; using AibisDream.FixSystem; -using System.Collections; -using AibisDream; // 添加 SpriteFlashSystem 的命名空间 +using AibisDream.Framework; +using DG.Tweening; +using RainbowArt.CleanFlatUI; +using UnityEngine; +using UnityEngine.EventSystems; +using UnityEngine.UI; -public class ShockSystem : MonoBehaviour +/// +/// 电击器系统。拉杆交互通过 EventTriggerEx 统一管理,支持 EventSystemEx.isLocked 与 IInteraction, +/// 光标由 EventTriggerEx → EventSystemEx → CursorManager 自动驱动。 +/// +public class ShockSystem : MonoBehaviour, IInteraction { [Header("References")] [SerializeField] private Transform shockDevice; // 电击器 @@ -98,18 +102,74 @@ public class ShockSystem : MonoBehaviour 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) { - // 注册 - FixSystemCenter.SystemDic.Register(this); +#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() { @@ -152,77 +212,183 @@ public class ShockSystem : MonoBehaviour } else { - HandleLeverInput(); + if (_useEventTrigger) + UpdateLeverReturn(); + else + HandleLeverInputFallback(); + UpdateLeverRotation(); UpdateCharging(); } } - private void HandleLeverInput() + 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)) { - // 检查是否点击到杆 - Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); - RaycastHit2D hit = Physics2D.Raycast(ray.origin, ray.direction); - - if (hit.collider != null && hit.collider.transform == lever) + var cam = Camera.main; + if (cam != null && lever != null) { - isDraggingLever = true; - lastMousePosition = Input.mousePosition; + 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)) { - isDraggingLever = false; - // 停止充能 - if (isCharging) - { - isCharging = false; - if (currentProgress >= progressBar.MaxValue) - { - DialogController.Instance.StartDialogNode(shockEffectNode); - } - ResetProgress(); - } + EndLeverDrag(); } if (isDraggingLever) - { - Vector3 mouseDelta = Input.mousePosition - lastMousePosition; - float angleDelta = mouseDelta.x * 0.5f; // 调整灵敏度 - - targetLeverAngle = Mathf.Clamp(targetLeverAngle + angleDelta, 0f, maxLeverAngle); - lastMousePosition = Input.mousePosition; - - // 根据杆的角度计算进度 - float progressRatio = targetLeverAngle / maxLeverAngle; - if (progressRatio > 0 && !isCharging) - { - isCharging = true; - StartCharging(); - // 开始播放充能音效 - AibisDream.Kit.AudioManager.Instance.PlaySfx(chargingEvent, chargingAudioKey); - } - } + 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 > 0 && !isCharging) { - // 杆自动回弹 - targetLeverAngle = Mathf.MoveTowards(targetLeverAngle, 0f, leverReturnSpeed * Time.deltaTime); - - // 如果杆已经回弹到接近0度,确保停止充能 - if (targetLeverAngle < 0.1f && isCharging) - { - isCharging = false; - if (currentProgress >= progressBar.MaxValue) - { - DialogController.Instance.StartDialogNode(shockEffectNode); - } - ResetProgress(); - } + 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) @@ -486,12 +652,11 @@ public class ShockSystem : MonoBehaviour if (isAbnormal) { - // 启动异常状态效果 + ForceClearLeverInteraction(); StartAbnormalEffects(); } else { - // 停止异常状态效果 StopAbnormalEffects(); } } @@ -589,15 +754,10 @@ public class ShockSystem : MonoBehaviour // 自动充能并释放 public IEnumerator AutoChargeAndRelease(float duration = 1f) { - // 保存当前异常状态 bool originalAbnormalState = isAbnormalState; - - // 临时禁用异常状态 isAbnormalState = false; - - // 禁用玩家输入 - bool originalIsDraggingLever = isDraggingLever; - isDraggingLever = false; + _leverInputLocked = true; + ForceClearLeverInteraction(); // 设置杆的角度 targetLeverAngle = maxLeverAngle; @@ -625,7 +785,7 @@ public class ShockSystem : MonoBehaviour // 恢复原始设置 progressIncreaseSpeed = originalProgressIncreaseSpeed; isCharging = false; - isDraggingLever = originalIsDraggingLever; + _leverInputLocked = false; // 重置杆的角度 targetLeverAngle = 0f; @@ -643,6 +803,15 @@ public class ShockSystem : MonoBehaviour 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(); @@ -698,4 +867,21 @@ public class ShockSystem : MonoBehaviour } } } +} + +/// +/// 电击器拉杆交互桥接:挂在 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; } \ No newline at end of file