using UnityEngine; using UnityEngine.Events; /// /// 核心交互系统:射线检测 + 点击/拖拽处理。 /// 挂在主相机或专用 GameObject 上。 /// public class InteractionSystem : MonoBehaviour { [Header("射线配置")] [SerializeField] private Camera _mainCamera; [SerializeField] private LayerMask _interactableMask = ~0; [SerializeField] private float _maxRayDistance = 100f; [Header("事件 - 由 StepManager 绑定")] public UnityEvent OnObjectClicked; // 点击到 Tag 时触发,传 Tag public UnityEvent OnAnywhereClicked; // 点击空白处触发 [Header("拖拽配置")] [SerializeField] private float _dragPlaneDistance = 2f; [SerializeField] private float _snapDistance = 0.3f; private GameObject _draggedObject; private Vector3 _dragOffset; private float _dragZ; private bool _isDragging; // 考核模式序列点击 private int _sequenceClickCount; private string[] _expectedSequence; private void Awake() { if (_mainCamera == null) _mainCamera = Camera.main; } private void Update() { HandleClick(); HandleDrag(); } #region 点击处理 private void HandleClick() { if (!Input.GetMouseButtonDown(0)) return; if (UnityEngine.EventSystems.EventSystem.current != null && UnityEngine.EventSystems.EventSystem.current.IsPointerOverGameObject()) return; Ray ray = _mainCamera.ScreenPointToRay(Input.mousePosition); if (Physics.Raycast(ray, out RaycastHit hit, _maxRayDistance, _interactableMask)) { string tag = hit.collider.tag; if (!string.IsNullOrEmpty(tag)) { Debug.Log($"InteractionSystem: 点击到物体 Tag={tag}"); OnObjectClicked?.Invoke(tag); return; } } OnAnywhereClicked?.Invoke(); } #endregion #region 拖拽处理 private void HandleDrag() { if (Input.GetMouseButtonDown(0)) { if (UnityEngine.EventSystems.EventSystem.current != null && UnityEngine.EventSystems.EventSystem.current.IsPointerOverGameObject()) return; Ray ray = _mainCamera.ScreenPointToRay(Input.mousePosition); if (Physics.Raycast(ray, out RaycastHit hit, _maxRayDistance, _interactableMask)) { var draggable = hit.collider.GetComponent(); if (draggable != null && draggable.IsDraggable) { _draggedObject = hit.collider.gameObject; _dragZ = _mainCamera.WorldToScreenPoint(_draggedObject.transform.position).z; _isDragging = true; draggable.OnDragStart(); } } } if (Input.GetMouseButton(0) && _isDragging && _draggedObject != null) { Vector3 screenPos = new Vector3(Input.mousePosition.x, Input.mousePosition.y, _dragZ); Vector3 worldPos = _mainCamera.ScreenToWorldPoint(screenPos); _draggedObject.transform.position = worldPos; } if (Input.GetMouseButtonUp(0) && _isDragging && _draggedObject != null) { var draggable = _draggedObject.GetComponent(); if (draggable != null && draggable.SnapTarget != null) { float dist = Vector3.Distance(_draggedObject.transform.position, draggable.SnapTarget.position); if (dist <= _snapDistance) { _draggedObject.transform.position = draggable.SnapTarget.position; _draggedObject.transform.rotation = draggable.SnapTarget.rotation; draggable.OnSnapped(); } } draggable?.OnDragEnd(); _draggedObject = null; _isDragging = false; } } #endregion #region 考核序列点击 public void BeginSequenceCheck(string[] expectedTags) { _expectedSequence = expectedTags; _sequenceClickCount = 0; } public bool TrySequenceClick(string clickedTag, out bool isComplete) { isComplete = false; if (_expectedSequence == null || _sequenceClickCount >= _expectedSequence.Length) return false; if (clickedTag == _expectedSequence[_sequenceClickCount]) { _sequenceClickCount++; if (_sequenceClickCount >= _expectedSequence.Length) { isComplete = true; _expectedSequence = null; return true; } return true; } return false; } /// 获取当前序列已正确命中的步数(用于 proportion 计分) public int GetSequenceHitCount() { return _sequenceClickCount; } #endregion #region 公共方法 public void SetInteractionEnabled(bool enabled) { this.enabled = enabled; } #endregion }