menu
This commit is contained in:
@@ -2,6 +2,13 @@ using UnityEngine;
|
||||
using UnityEngine.InputSystem;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using DG.Tweening;
|
||||
using Ichni;
|
||||
using Lean.Common;
|
||||
using Lean.Pool;
|
||||
using Sirenix.OdinInspector;
|
||||
using UnityEngine.InputSystem.Controls;
|
||||
using UnityEngine.UI;
|
||||
using Touch = UnityEngine.InputSystem.EnhancedTouch.Touch;
|
||||
using TouchPhase = UnityEngine.InputSystem.TouchPhase;
|
||||
|
||||
@@ -9,14 +16,14 @@ using TouchPhase = UnityEngine.InputSystem.TouchPhase;
|
||||
/// 为节奏游戏设计的输入管理器,处理多点触控并分发三种主要事件。
|
||||
/// 【重要】此版本内置了编辑器内的鼠标模拟功能,无需手机即可测试。
|
||||
/// </summary>
|
||||
public class RhythmInputManager : MonoBehaviour
|
||||
public class RhythmInputManager : SerializedMonoBehaviour
|
||||
{
|
||||
// =====================================================================
|
||||
// 公共事件 (Public Events)
|
||||
// =====================================================================
|
||||
public static event Action<int, Vector2> OnTap;
|
||||
public static event Action<int, Vector2> OnTouch;
|
||||
public static event Action<int, Vector2, Vector2> OnSwipe;
|
||||
public static event Action<int, Vector2, bool, Vector2> OnSwipe;
|
||||
|
||||
// =====================================================================
|
||||
// 可配置参数 (Configurable Parameters)
|
||||
@@ -24,7 +31,8 @@ public class RhythmInputManager : MonoBehaviour
|
||||
|
||||
[Header("划动设置 (Swipe Settings)")]
|
||||
[Tooltip("识别为划动的最小移动距离(像素)")]
|
||||
[SerializeField] private float minSwipeDistance = 50.0f;
|
||||
[SerializeField] private float minSwipeDistance = 200.0f;
|
||||
[SerializeField] private float swipeAngleThreshold = 1f;
|
||||
|
||||
// =====================================================================
|
||||
// 内部状态 (Internal State)
|
||||
@@ -52,14 +60,19 @@ public class RhythmInputManager : MonoBehaviour
|
||||
//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}");
|
||||
|
||||
OnTap += GenerateTapMark;
|
||||
OnTouch += GenerateTouchMark;
|
||||
OnSwipe += GenerateSwipeMark;
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
// 使用预处理指令区分平台
|
||||
#if UNITY_EDITOR
|
||||
#if UNITY_EDITOR || UNITY_STANDALONE
|
||||
// --- 在Unity编辑器中,使用鼠标模拟触摸 ---
|
||||
ProcessMouseInput();
|
||||
//ProcessMouseInput();
|
||||
ProcessKeyboardInput();
|
||||
#else
|
||||
// --- 在真机设备上,使用真实的触摸输入 ---
|
||||
ProcessRealTouchInput();
|
||||
@@ -124,6 +137,48 @@ public class RhythmInputManager : MonoBehaviour
|
||||
}
|
||||
#endif
|
||||
|
||||
#if UNITY_EDITOR || UNITY_STANDALONE
|
||||
public static List<KeyControl> availableKeys = new List<KeyControl>()
|
||||
{
|
||||
Keyboard.current.dKey,
|
||||
Keyboard.current.fKey,
|
||||
Keyboard.current.jKey,
|
||||
Keyboard.current.kKey,
|
||||
};
|
||||
public static List<KeyControl> flickKeys = new List<KeyControl>()
|
||||
{
|
||||
Keyboard.current.sKey,
|
||||
Keyboard.current.lKey,
|
||||
};
|
||||
private void ProcessKeyboardInput()
|
||||
{
|
||||
for (int index = 0; index < availableKeys.Count; index++)
|
||||
{
|
||||
Vector2 inputPosition = new Vector2(index * 400 - 600 + Screen.width * 0.5f, 200f); // 假设每个按键的虚拟位置
|
||||
|
||||
if (availableKeys[index].wasPressedThisFrame)
|
||||
{
|
||||
OnTap?.Invoke(index, inputPosition);
|
||||
}
|
||||
|
||||
if (availableKeys[index].isPressed)
|
||||
{
|
||||
OnTouch?.Invoke(index, inputPosition);
|
||||
}
|
||||
}
|
||||
|
||||
for (int index = 0; index < flickKeys.Count; index++)
|
||||
{
|
||||
Vector2 inputPosition = new Vector2(index * 1600 - 800 + Screen.width * 0.5f, 200f); // 假设每个划动按键的虚拟位置
|
||||
|
||||
if (flickKeys[index].wasPressedThisFrame)
|
||||
{
|
||||
OnSwipe?.Invoke(index, inputPosition, true, Vector2.zero);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// 【仅在真机上运行】处理真实的触摸屏输入。
|
||||
/// </summary>
|
||||
@@ -198,12 +253,86 @@ public class RhythmInputManager : MonoBehaviour
|
||||
Vector2 direction = swipeVector.normalized;
|
||||
|
||||
// 检查是否是新的划动方向
|
||||
if (Vector2.Dot(direction, state.LastSwipeDirection) < 0.5f)
|
||||
if (Vector2.Dot(direction, state.LastSwipeDirection) <= swipeAngleThreshold)
|
||||
{
|
||||
OnSwipe?.Invoke(state.TouchId, state.StartPosition, direction);
|
||||
OnSwipe?.Invoke(state.TouchId, state.StartPosition, false, direction);
|
||||
state.LastSwipeDirection = direction;
|
||||
state.StartPosition = currentPosition;
|
||||
state.StartTime = Time.time;
|
||||
}
|
||||
}
|
||||
|
||||
private void GenerateTapMark(int id, Vector2 pos)
|
||||
{
|
||||
RectTransform mark = LeanPool.Spawn(GameManager.instance.basePrefabs.tapInputMark,
|
||||
GameManager.instance.judgeHintCanvas.transform). GetComponent<RectTransform>();
|
||||
|
||||
RectTransform canvasRect = GameManager.instance.judgeHintCanvas.GetComponent<RectTransform>();
|
||||
if (RectTransformUtility.ScreenPointToLocalPointInRectangle(canvasRect, pos, null, out Vector2 uiPosition))
|
||||
{
|
||||
mark.anchoredPosition = uiPosition;
|
||||
}
|
||||
|
||||
Sequence ss = DOTween.Sequence();
|
||||
ss.OnStart(() =>
|
||||
{
|
||||
mark.GetComponent<Image>().color = Color.white;
|
||||
mark.localScale = Vector3.zero;
|
||||
});
|
||||
ss.Join(mark.GetComponent<Image>().DOFade(0, 0.5f));
|
||||
ss.Join(mark.DOScale(5, 0.5f));
|
||||
ss.OnComplete(() => LeanPool.Despawn(mark.gameObject));
|
||||
ss.SetUpdate(true);
|
||||
ss.Play();
|
||||
}
|
||||
|
||||
private void GenerateTouchMark(int id, Vector2 pos)
|
||||
{
|
||||
RectTransform mark = LeanPool.Spawn(GameManager.instance.basePrefabs.touchInputMark,
|
||||
GameManager.instance.judgeHintCanvas.transform). GetComponent<RectTransform>();
|
||||
|
||||
RectTransform canvasRect = GameManager.instance.judgeHintCanvas.GetComponent<RectTransform>();
|
||||
if (RectTransformUtility.ScreenPointToLocalPointInRectangle(canvasRect, pos, null, out Vector2 uiPosition))
|
||||
{
|
||||
mark.anchoredPosition = uiPosition;
|
||||
}
|
||||
|
||||
Sequence ss = DOTween.Sequence();
|
||||
ss.OnStart(() =>
|
||||
{
|
||||
mark.GetComponent<Image>().color = Color.white;
|
||||
});
|
||||
ss.Join(mark.GetComponent<Image>().DOFade(0, 0.1f));
|
||||
ss.OnComplete(() => LeanPool.Despawn(mark.gameObject));
|
||||
ss.SetUpdate(true);
|
||||
ss.Play();
|
||||
}
|
||||
|
||||
private void GenerateSwipeMark(int id, Vector2 pos, bool isGeneric, Vector2 direction)
|
||||
{
|
||||
GameObject markPrefab = isGeneric
|
||||
? GameManager.instance.basePrefabs.genericSwipeInputMark
|
||||
: GameManager.instance.basePrefabs.directionalSwipeInputMark;
|
||||
|
||||
RectTransform mark = LeanPool.Spawn(markPrefab, GameManager.instance.judgeHintCanvas.transform). GetComponent<RectTransform>();
|
||||
|
||||
RectTransform canvasRect = GameManager.instance.judgeHintCanvas.GetComponent<RectTransform>();
|
||||
if (RectTransformUtility.ScreenPointToLocalPointInRectangle(canvasRect, pos, null, out Vector2 uiPosition))
|
||||
{
|
||||
mark.anchoredPosition = uiPosition;
|
||||
}
|
||||
mark.localEulerAngles = new Vector3(0, 0, Mathf.Atan2(direction.y, direction.x) * Mathf.Rad2Deg - 90f);
|
||||
|
||||
Sequence ss = DOTween.Sequence();
|
||||
ss.OnStart(() =>
|
||||
{
|
||||
mark.GetComponent<Image>().color = Color.white;
|
||||
mark.localScale = Vector3.zero;
|
||||
});
|
||||
ss.Join(mark.GetComponent<Image>().DOFade(0, 0.5f));
|
||||
ss.Join(mark.DOScale(5, 0.5f));
|
||||
ss.OnComplete(() => LeanPool.Despawn(mark.gameObject));
|
||||
ss.SetUpdate(true);
|
||||
ss.Play();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user