using UnityEngine; using UnityEngine.InputSystem; using System; using System.Collections.Generic; using Touch = UnityEngine.InputSystem.EnhancedTouch.Touch; using TouchPhase = UnityEngine.InputSystem.TouchPhase; /// /// 为节奏游戏设计的输入管理器,处理多点触控并分发三种主要事件。 /// 【重要】此版本内置了编辑器内的鼠标模拟功能,无需手机即可测试。 /// public class RhythmInputManager : MonoBehaviour { // ===================================================================== // 公共事件 (Public Events) // ===================================================================== public static event Action OnTap; public static event Action OnTouch; public static event Action OnSwipe; // ===================================================================== // 可配置参数 (Configurable Parameters) // ===================================================================== [Header("划动设置 (Swipe Settings)")] [Tooltip("识别为划动的最小移动距离(像素)")] [SerializeField] private float minSwipeDistance = 50.0f; // ===================================================================== // 内部状态 (Internal State) // ===================================================================== private class TouchState { public int TouchId; public Vector2 StartPosition; public float StartTime; public Vector2 LastSwipeDirection = Vector2.zero; public bool IsTapCandidate = true; } private readonly Dictionary _activeTouches = new Dictionary(); // 为鼠标模拟专门设置一个固定的Touch ID private const int MOUSE_TOUCH_ID = 999; // ===================================================================== // MonoBehaviour 生命周期方法 (Lifecycle Methods) // ===================================================================== private void Awake() { //OnTap += (id, pos)=> Debug.Log($"Tap Detected: Touch ID {id}, Position {pos}"); //OnTouch += (id, pos) => Debug.Log($"Touch Detected: Touch ID {id}, Position {pos}"); //OnSwipe += (id, pos, dir) => Debug.Log($"Swipe Detected: Touch ID {id}, Position {pos}, Direction {dir}"); } private void Update() { // 使用预处理指令区分平台 #if UNITY_EDITOR // --- 在Unity编辑器中,使用鼠标模拟触摸 --- ProcessMouseInput(); #else // --- 在真机设备上,使用真实的触摸输入 --- ProcessRealTouchInput(); #endif } // ===================================================================== // 核心处理逻辑 (Core Processing Logic) // ===================================================================== #if UNITY_EDITOR /// /// 【仅在编辑器中运行】处理鼠标输入并模拟触摸事件。 /// private void ProcessMouseInput() { if (Mouse.current == null) return; Vector2 position = Mouse.current.position.ReadValue(); if (Mouse.current.leftButton.wasPressedThisFrame) { ProcessInputEvent(MOUSE_TOUCH_ID, TouchPhase.Began, position); } else if (Mouse.current.leftButton.isPressed) { // 如果鼠标位置有变化,则为Moved,否则为Stationary if (Mouse.current.delta.ReadValue().sqrMagnitude > 0.1f) { ProcessInputEvent(MOUSE_TOUCH_ID, TouchPhase.Moved, position); } else { ProcessInputEvent(MOUSE_TOUCH_ID, TouchPhase.Stationary, position); } } else if (Mouse.current.leftButton.wasReleasedThisFrame) { ProcessInputEvent(MOUSE_TOUCH_ID, TouchPhase.Ended, position); } if (Mouse.current.rightButton.wasPressedThisFrame) { ProcessInputEvent(MOUSE_TOUCH_ID + 1, TouchPhase.Began, position); } else if (Mouse.current.rightButton.isPressed) { // 如果鼠标位置有变化,则为Moved,否则为Stationary if (Mouse.current.delta.ReadValue().sqrMagnitude > 0.1f) { ProcessInputEvent(MOUSE_TOUCH_ID + 1, TouchPhase.Moved, position); } else { ProcessInputEvent(MOUSE_TOUCH_ID + 1, TouchPhase.Stationary, position); } } else if (Mouse.current.rightButton.wasReleasedThisFrame) { ProcessInputEvent(MOUSE_TOUCH_ID + 1, TouchPhase.Ended, position); } } #endif /// /// 【仅在真机上运行】处理真实的触摸屏输入。 /// private void ProcessRealTouchInput() { if (Touchscreen.current == null) return; foreach (Touch touch in Touch.activeTouches) { ProcessInputEvent( touch.touchId, touch.phase, touch.screenPosition ); } } /// /// 所有输入事件的核心处理函数,无论是真实触摸还是鼠标模拟都会调用它。 /// private void ProcessInputEvent(int touchId, TouchPhase phase, Vector2 position) { switch (phase) { case TouchPhase.Began: var newState = new TouchState { TouchId = touchId, StartPosition = position, StartTime = Time.time, }; _activeTouches[touchId] = newState; OnTap?.Invoke(touchId, position); OnTouch?.Invoke(touchId, position); break; case TouchPhase.Moved: if (_activeTouches.TryGetValue(touchId, out TouchState movedState)) { OnTouch?.Invoke(touchId, position); DetectSwipe(movedState, position); } break; case TouchPhase.Stationary: if (_activeTouches.TryGetValue(touchId, out TouchState stationaryState)) { OnTouch?.Invoke(touchId, position); } break; case TouchPhase.Canceled: if (_activeTouches.ContainsKey(touchId)) { _activeTouches.Remove(touchId); } break; } } /// /// 检测划动逻辑 (无需修改) /// private void DetectSwipe(TouchState state, Vector2 currentPosition) { Vector2 swipeVector = currentPosition - state.StartPosition; if (swipeVector.magnitude < minSwipeDistance) return; Vector2 direction = swipeVector.normalized; // 检查是否是新的划动方向 if (Vector2.Dot(direction, state.LastSwipeDirection) < 0.5f) { OnSwipe?.Invoke(state.TouchId, state.StartPosition, direction); state.LastSwipeDirection = direction; state.StartPosition = currentPosition; state.StartTime = Time.time; } } }