Files
ichni_Official/Assets/Scripts/Manager/RhythmInputManager.cs
SoulliesOfficial bae0bfbc20 perf
2025-07-21 05:42:20 -04:00

210 lines
7.2 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using UnityEngine;
using UnityEngine.InputSystem;
using System;
using System.Collections.Generic;
using Touch = UnityEngine.InputSystem.EnhancedTouch.Touch;
using TouchPhase = UnityEngine.InputSystem.TouchPhase;
/// <summary>
/// 为节奏游戏设计的输入管理器,处理多点触控并分发三种主要事件。
/// 【重要】此版本内置了编辑器内的鼠标模拟功能,无需手机即可测试。
/// </summary>
public class RhythmInputManager : MonoBehaviour
{
// =====================================================================
// 公共事件 (Public Events)
// =====================================================================
public static event Action<int, Vector2> OnTap;
public static event Action<int, Vector2> OnTouch;
public static event Action<int, Vector2, Vector2> 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<int, TouchState> _activeTouches = new Dictionary<int, TouchState>();
// 为鼠标模拟专门设置一个固定的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
/// <summary>
/// 【仅在编辑器中运行】处理鼠标输入并模拟触摸事件。
/// </summary>
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
/// <summary>
/// 【仅在真机上运行】处理真实的触摸屏输入。
/// </summary>
private void ProcessRealTouchInput()
{
if (Touchscreen.current == null) return;
foreach (Touch touch in Touch.activeTouches)
{
ProcessInputEvent(
touch.touchId,
touch.phase,
touch.screenPosition
);
}
}
/// <summary>
/// 所有输入事件的核心处理函数,无论是真实触摸还是鼠标模拟都会调用它。
/// </summary>
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;
}
}
/// <summary>
/// 检测划动逻辑 (无需修改)
/// </summary>
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;
}
}
}