2025-07-21 05:42:20 -04:00
|
|
|
|
using UnityEngine;
|
|
|
|
|
|
using UnityEngine.InputSystem;
|
|
|
|
|
|
using System;
|
|
|
|
|
|
using System.Collections.Generic;
|
2025-07-26 04:20:25 -04:00
|
|
|
|
using DG.Tweening;
|
|
|
|
|
|
using Ichni;
|
|
|
|
|
|
using Lean.Common;
|
|
|
|
|
|
using Lean.Pool;
|
|
|
|
|
|
using Sirenix.OdinInspector;
|
2025-08-11 14:04:06 -04:00
|
|
|
|
using TMPro;
|
2025-07-26 04:20:25 -04:00
|
|
|
|
using UnityEngine.InputSystem.Controls;
|
2025-09-05 10:14:45 -04:00
|
|
|
|
using UnityEngine.InputSystem.EnhancedTouch;
|
2025-07-26 04:20:25 -04:00
|
|
|
|
using UnityEngine.UI;
|
2025-07-21 05:42:20 -04:00
|
|
|
|
using Touch = UnityEngine.InputSystem.EnhancedTouch.Touch;
|
|
|
|
|
|
using TouchPhase = UnityEngine.InputSystem.TouchPhase;
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 为节奏游戏设计的输入管理器,处理多点触控并分发三种主要事件。
|
|
|
|
|
|
/// 【重要】此版本内置了编辑器内的鼠标模拟功能,无需手机即可测试。
|
|
|
|
|
|
/// </summary>
|
2025-09-05 10:14:45 -04:00
|
|
|
|
public class GameInputManager : MonoBehaviour
|
2025-07-21 05:42:20 -04:00
|
|
|
|
{
|
|
|
|
|
|
// =====================================================================
|
|
|
|
|
|
// 可配置参数 (Configurable Parameters)
|
|
|
|
|
|
// =====================================================================
|
|
|
|
|
|
|
|
|
|
|
|
[Header("划动设置 (Swipe Settings)")]
|
|
|
|
|
|
[Tooltip("识别为划动的最小移动距离(像素)")]
|
2025-08-11 14:04:06 -04:00
|
|
|
|
[SerializeField] private float minSwipeDistance = 100f;
|
2025-07-26 04:20:25 -04:00
|
|
|
|
[SerializeField] private float swipeAngleThreshold = 1f;
|
2025-07-21 05:42:20 -04:00
|
|
|
|
|
2025-08-11 14:04:06 -04:00
|
|
|
|
public GameInput gameInput;
|
|
|
|
|
|
public PlayerInput playerInput;
|
|
|
|
|
|
private string rebindsFilePath => Application.persistentDataPath + "/GameData/Rebindings.json";
|
|
|
|
|
|
|
2025-07-21 05:42:20 -04:00
|
|
|
|
// =====================================================================
|
|
|
|
|
|
// 内部状态 (Internal State)
|
|
|
|
|
|
// =====================================================================
|
|
|
|
|
|
private class TouchState
|
|
|
|
|
|
{
|
|
|
|
|
|
public int TouchId;
|
|
|
|
|
|
public Vector2 StartPosition;
|
|
|
|
|
|
public float StartTime;
|
|
|
|
|
|
public Vector2 LastSwipeDirection = Vector2.zero;
|
2025-09-05 10:14:45 -04:00
|
|
|
|
public bool isFirstSwipe = true;
|
2025-07-21 05:42:20 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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()
|
|
|
|
|
|
{
|
2025-09-05 10:14:45 -04:00
|
|
|
|
#if UNITY_STANDALONE
|
2025-08-11 14:04:06 -04:00
|
|
|
|
DOTween.SetTweensCapacity(200, 200);
|
|
|
|
|
|
gameInput = new GameInput();
|
|
|
|
|
|
gameInput.Game.Enable();
|
|
|
|
|
|
if (ES3.FileExists(rebindsFilePath) && ES3.KeyExists("Rebinds", rebindsFilePath))
|
|
|
|
|
|
{
|
|
|
|
|
|
gameInput.LoadBindingOverridesFromJson(ES3.Load<string>("Rebinds", rebindsFilePath));
|
|
|
|
|
|
Debug.Log("已加载自定义按键绑定");
|
|
|
|
|
|
}
|
|
|
|
|
|
RegisterActionsInputs();
|
2025-09-05 10:14:45 -04:00
|
|
|
|
#else
|
|
|
|
|
|
Debug.Log("已启用真实触摸输入");
|
2025-08-11 14:04:06 -04:00
|
|
|
|
#endif
|
2025-07-21 05:42:20 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void Update()
|
|
|
|
|
|
{
|
2025-08-22 14:54:40 -04:00
|
|
|
|
if (!GameManager.instance.audioManager.isUpdating)
|
|
|
|
|
|
{
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-21 05:42:20 -04:00
|
|
|
|
// 使用预处理指令区分平台
|
2025-09-05 10:14:45 -04:00
|
|
|
|
#if UNITY_STANDALONE
|
2025-08-11 14:04:06 -04:00
|
|
|
|
HandleHolding();
|
2025-07-21 05:42:20 -04:00
|
|
|
|
#else
|
|
|
|
|
|
ProcessRealTouchInput();
|
2025-09-05 10:14:45 -04:00
|
|
|
|
#endif
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void OnDisable()
|
|
|
|
|
|
{
|
|
|
|
|
|
#if UNITY_STANDALONE
|
|
|
|
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
2025-07-21 05:42:20 -04:00
|
|
|
|
#endif
|
|
|
|
|
|
}
|
2025-08-11 14:04:06 -04:00
|
|
|
|
|
|
|
|
|
|
private void OnTap(int id, Vector2 position)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (SettingsManager.instance.gameSettings.debugMode)
|
|
|
|
|
|
{
|
|
|
|
|
|
GenerateTapMark(id, position);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
GameManager.instance.noteJudgeManager.SetNewInputUnitTap(id, position);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void OnTouch(int id, Vector2 position)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (SettingsManager.instance.gameSettings.debugMode)
|
|
|
|
|
|
{
|
|
|
|
|
|
GenerateTouchMark(id, position);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
GameManager.instance.noteJudgeManager.SetNewInputUnitTouch(id, position);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-05 10:14:45 -04:00
|
|
|
|
private void OnSwipe(int id, Vector2 position, bool isGeneric, bool isFirst, Vector2 direction)
|
2025-08-11 14:04:06 -04:00
|
|
|
|
{
|
|
|
|
|
|
if (SettingsManager.instance.gameSettings.debugMode)
|
|
|
|
|
|
{
|
2025-09-05 10:14:45 -04:00
|
|
|
|
GenerateSwipeMark(id, position, isGeneric, isFirst, direction);
|
|
|
|
|
|
|
|
|
|
|
|
if(isFirst) Debug.Log($"划动开始 - ID: {id}, 位置: {position}, 方向: {direction}");
|
|
|
|
|
|
else Debug.Log($"划动更新 - ID: {id}, 位置: {position}, 方向: {direction}");
|
2025-08-11 14:04:06 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-05 10:14:45 -04:00
|
|
|
|
GameManager.instance.noteJudgeManager.SetNewInputUnitSwipe(id, position, isGeneric, isFirst, direction);
|
2025-08-11 14:04:06 -04:00
|
|
|
|
}
|
2025-07-21 05:42:20 -04:00
|
|
|
|
|
|
|
|
|
|
// =====================================================================
|
|
|
|
|
|
// 核心处理逻辑 (Core Processing Logic)
|
|
|
|
|
|
// =====================================================================
|
|
|
|
|
|
|
2025-09-05 10:14:45 -04:00
|
|
|
|
#if UNITY_STANDALONE
|
2025-07-21 05:42:20 -04:00
|
|
|
|
/// <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
|
|
|
|
|
|
|
2025-09-05 10:14:45 -04:00
|
|
|
|
#if UNITY_STANDALONE
|
2025-08-11 14:04:06 -04:00
|
|
|
|
|
|
|
|
|
|
public bool holdingTouch0;
|
|
|
|
|
|
public bool holdingTouch1;
|
|
|
|
|
|
public bool holdingTouch2;
|
|
|
|
|
|
public bool holdingTouch3;
|
|
|
|
|
|
public bool holdingSwipe0;
|
|
|
|
|
|
public bool holdingSwipe1;
|
|
|
|
|
|
|
|
|
|
|
|
private void RegisterActionsInputs()
|
2025-07-26 04:20:25 -04:00
|
|
|
|
{
|
2025-08-11 14:04:06 -04:00
|
|
|
|
gameInput.Game.Tap0.performed += ctx =>
|
2025-07-26 04:20:25 -04:00
|
|
|
|
{
|
2025-08-11 14:04:06 -04:00
|
|
|
|
if (ctx.performed)
|
2025-07-26 04:20:25 -04:00
|
|
|
|
{
|
2025-08-11 14:04:06 -04:00
|
|
|
|
Vector2 inputPosition = new Vector2(-600 + Screen.width * 0.5f, 200f);
|
|
|
|
|
|
OnTap(0, inputPosition);
|
|
|
|
|
|
holdingTouch0 = true;
|
2025-07-26 04:20:25 -04:00
|
|
|
|
}
|
2025-08-11 14:04:06 -04:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
gameInput.Game.Tap1.performed += ctx =>
|
|
|
|
|
|
{
|
|
|
|
|
|
if (ctx.performed)
|
2025-07-26 04:20:25 -04:00
|
|
|
|
{
|
2025-08-11 14:04:06 -04:00
|
|
|
|
Vector2 inputPosition = new Vector2(-200 + Screen.width * 0.5f, 200f);
|
|
|
|
|
|
OnTap(1, inputPosition);
|
|
|
|
|
|
holdingTouch1 = true;
|
2025-07-26 04:20:25 -04:00
|
|
|
|
}
|
2025-08-11 14:04:06 -04:00
|
|
|
|
};
|
2025-07-26 04:20:25 -04:00
|
|
|
|
|
2025-08-11 14:04:06 -04:00
|
|
|
|
gameInput.Game.Tap2.performed += ctx =>
|
2025-07-26 04:20:25 -04:00
|
|
|
|
{
|
2025-08-11 14:04:06 -04:00
|
|
|
|
if (ctx.performed)
|
2025-07-26 04:20:25 -04:00
|
|
|
|
{
|
2025-08-11 14:04:06 -04:00
|
|
|
|
Vector2 inputPosition = new Vector2(200 + Screen.width * 0.5f, 200f);
|
|
|
|
|
|
OnTap(2, inputPosition);
|
|
|
|
|
|
holdingTouch2 = true;
|
2025-07-26 04:20:25 -04:00
|
|
|
|
}
|
2025-08-11 14:04:06 -04:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
gameInput.Game.Tap3.performed += ctx =>
|
|
|
|
|
|
{
|
|
|
|
|
|
if (ctx.performed)
|
|
|
|
|
|
{
|
|
|
|
|
|
Vector2 inputPosition = new Vector2(600 + Screen.width * 0.5f, 200f);
|
|
|
|
|
|
OnTap(3, inputPosition);
|
|
|
|
|
|
holdingTouch3 = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
gameInput.Game.Tap0.canceled += ctx =>
|
|
|
|
|
|
{
|
|
|
|
|
|
if (ctx.canceled)
|
|
|
|
|
|
{
|
|
|
|
|
|
holdingTouch0 = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
gameInput.Game.Tap1.canceled += ctx =>
|
|
|
|
|
|
{
|
|
|
|
|
|
if (ctx.canceled)
|
|
|
|
|
|
{
|
|
|
|
|
|
holdingTouch1 = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
gameInput.Game.Tap2.canceled += ctx =>
|
|
|
|
|
|
{
|
|
|
|
|
|
if (ctx.canceled)
|
|
|
|
|
|
{
|
|
|
|
|
|
holdingTouch2 = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
gameInput.Game.Tap3.canceled += ctx =>
|
|
|
|
|
|
{
|
|
|
|
|
|
if (ctx.canceled)
|
|
|
|
|
|
{
|
|
|
|
|
|
holdingTouch3 = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
gameInput.Game.Swipe0.performed += ctx =>
|
|
|
|
|
|
{
|
|
|
|
|
|
if (ctx.performed)
|
|
|
|
|
|
{
|
|
|
|
|
|
holdingSwipe0 = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
gameInput.Game.Swipe0.canceled += ctx =>
|
|
|
|
|
|
{
|
|
|
|
|
|
if (ctx.canceled)
|
|
|
|
|
|
{
|
|
|
|
|
|
holdingSwipe0 = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void HandleHolding()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (holdingTouch0)
|
|
|
|
|
|
{
|
|
|
|
|
|
Vector2 inputPosition = new Vector2(-600 + Screen.width * 0.5f, 200f);
|
|
|
|
|
|
OnTouch(0, inputPosition);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (holdingTouch1)
|
|
|
|
|
|
{
|
|
|
|
|
|
Vector2 inputPosition = new Vector2(-200 + Screen.width * 0.5f, 200f);
|
|
|
|
|
|
OnTouch(1, inputPosition);
|
2025-07-26 04:20:25 -04:00
|
|
|
|
}
|
2025-08-11 14:04:06 -04:00
|
|
|
|
|
|
|
|
|
|
if (holdingTouch2)
|
|
|
|
|
|
{
|
|
|
|
|
|
Vector2 inputPosition = new Vector2(200 + Screen.width * 0.5f, 200f);
|
|
|
|
|
|
OnTouch(2, inputPosition);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (holdingTouch3)
|
|
|
|
|
|
{
|
|
|
|
|
|
Vector2 inputPosition = new Vector2(600 + Screen.width * 0.5f, 200f);
|
|
|
|
|
|
OnTouch(3, inputPosition);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (holdingSwipe0)
|
|
|
|
|
|
{
|
|
|
|
|
|
Vector2 inputPosition = new Vector2(Screen.width * 0.5f, 200f);
|
|
|
|
|
|
OnSwipe(0, inputPosition, true, Vector2.zero);
|
|
|
|
|
|
}
|
2025-07-26 04:20:25 -04:00
|
|
|
|
}
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
2025-07-21 05:42:20 -04:00
|
|
|
|
/// <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,
|
2025-09-05 10:14:45 -04:00
|
|
|
|
LastSwipeDirection = Vector2.zero,
|
|
|
|
|
|
isFirstSwipe = true
|
2025-07-21 05:42:20 -04:00
|
|
|
|
};
|
|
|
|
|
|
_activeTouches[touchId] = newState;
|
2025-08-11 14:04:06 -04:00
|
|
|
|
OnTap(touchId, position);
|
|
|
|
|
|
OnTouch(touchId, position);
|
2025-07-21 05:42:20 -04:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case TouchPhase.Moved:
|
|
|
|
|
|
if (_activeTouches.TryGetValue(touchId, out TouchState movedState))
|
|
|
|
|
|
{
|
2025-08-11 14:04:06 -04:00
|
|
|
|
OnTouch(touchId, position);
|
2025-09-05 10:14:45 -04:00
|
|
|
|
DetectSwipe(movedState, _activeTouches[touchId].isFirstSwipe, position);
|
|
|
|
|
|
//_activeTouches[touchId].isFirstSwipe = false;
|
2025-07-21 05:42:20 -04:00
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case TouchPhase.Stationary:
|
|
|
|
|
|
if (_activeTouches.TryGetValue(touchId, out TouchState stationaryState))
|
|
|
|
|
|
{
|
2025-08-11 14:04:06 -04:00
|
|
|
|
OnTouch(touchId, position);
|
2025-07-21 05:42:20 -04:00
|
|
|
|
}
|
|
|
|
|
|
break;
|
2025-08-11 14:04:06 -04:00
|
|
|
|
|
|
|
|
|
|
case TouchPhase.Ended:
|
|
|
|
|
|
if (_activeTouches.ContainsKey(touchId))
|
|
|
|
|
|
{
|
|
|
|
|
|
_activeTouches.Remove(touchId);
|
2025-09-05 10:14:45 -04:00
|
|
|
|
if (SettingsManager.instance.gameSettings.debugMode)
|
|
|
|
|
|
{
|
|
|
|
|
|
GenerateEndMark(position);
|
|
|
|
|
|
}
|
2025-08-11 14:04:06 -04:00
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
2025-07-21 05:42:20 -04:00
|
|
|
|
case TouchPhase.Canceled:
|
|
|
|
|
|
if (_activeTouches.ContainsKey(touchId))
|
|
|
|
|
|
{
|
|
|
|
|
|
_activeTouches.Remove(touchId);
|
2025-09-05 10:14:45 -04:00
|
|
|
|
if (SettingsManager.instance.gameSettings.debugMode)
|
|
|
|
|
|
{
|
|
|
|
|
|
GenerateCanceledMark(position);
|
|
|
|
|
|
}
|
2025-07-21 05:42:20 -04:00
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 检测划动逻辑 (无需修改)
|
|
|
|
|
|
/// </summary>
|
2025-09-05 10:14:45 -04:00
|
|
|
|
private void DetectSwipe(TouchState state, bool isFirst, Vector2 currentPosition)
|
2025-07-21 05:42:20 -04:00
|
|
|
|
{
|
|
|
|
|
|
Vector2 swipeVector = currentPosition - state.StartPosition;
|
|
|
|
|
|
if (swipeVector.magnitude < minSwipeDistance) return;
|
|
|
|
|
|
|
|
|
|
|
|
Vector2 direction = swipeVector.normalized;
|
|
|
|
|
|
|
|
|
|
|
|
// 检查是否是新的划动方向
|
2025-07-26 04:20:25 -04:00
|
|
|
|
if (Vector2.Dot(direction, state.LastSwipeDirection) <= swipeAngleThreshold)
|
2025-07-21 05:42:20 -04:00
|
|
|
|
{
|
2025-09-05 10:14:45 -04:00
|
|
|
|
OnSwipe(state.TouchId, state.StartPosition, false, isFirst, direction);
|
2025-07-21 05:42:20 -04:00
|
|
|
|
state.LastSwipeDirection = direction;
|
|
|
|
|
|
state.StartPosition = currentPosition;
|
|
|
|
|
|
state.StartTime = Time.time;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-07-26 04:20:25 -04:00
|
|
|
|
|
|
|
|
|
|
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;
|
2025-08-11 14:04:06 -04:00
|
|
|
|
mark.GetComponentInChildren<TMP_Text>().text = GameManager.instance.noteJudgeManager.checkingTapList.Count.ToString();
|
2025-07-26 04:20:25 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Sequence ss = DOTween.Sequence();
|
|
|
|
|
|
ss.OnStart(() =>
|
|
|
|
|
|
{
|
|
|
|
|
|
mark.GetComponent<Image>().color = Color.white;
|
|
|
|
|
|
mark.localScale = Vector3.zero;
|
|
|
|
|
|
});
|
2025-08-11 14:04:06 -04:00
|
|
|
|
ss.Join(mark.GetComponent<Image>().DOFade(0, 0.25f));
|
|
|
|
|
|
ss.Join(mark.DOScale(5, 0.25f));
|
2025-07-26 04:20:25 -04:00
|
|
|
|
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();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-05 10:14:45 -04:00
|
|
|
|
private void GenerateSwipeMark(int id, Vector2 pos, bool isGeneric, bool isFirst, Vector2 direction)
|
2025-07-26 04:20:25 -04:00
|
|
|
|
{
|
|
|
|
|
|
GameObject markPrefab = isGeneric
|
|
|
|
|
|
? GameManager.instance.basePrefabs.genericSwipeInputMark
|
|
|
|
|
|
: GameManager.instance.basePrefabs.directionalSwipeInputMark;
|
|
|
|
|
|
|
2025-09-05 10:14:45 -04:00
|
|
|
|
RectTransform mark = LeanPool.Spawn(markPrefab, GameManager.instance.judgeHintCanvas.transform).GetComponent<RectTransform>();
|
2025-07-26 04:20:25 -04:00
|
|
|
|
|
|
|
|
|
|
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(() =>
|
|
|
|
|
|
{
|
2025-09-05 10:14:45 -04:00
|
|
|
|
mark.GetComponent<Image>().color = isFirst ? Color.red : Color.white;
|
2025-07-26 04:20:25 -04:00
|
|
|
|
mark.localScale = Vector3.zero;
|
|
|
|
|
|
});
|
2025-08-11 14:04:06 -04:00
|
|
|
|
ss.Join(mark.GetComponent<Image>().DOFade(0, 0.25f));
|
|
|
|
|
|
ss.Join(mark.DOScale(5, 0.25f));
|
2025-07-26 04:20:25 -04:00
|
|
|
|
ss.OnComplete(() => LeanPool.Despawn(mark.gameObject));
|
|
|
|
|
|
ss.SetUpdate(true);
|
|
|
|
|
|
ss.Play();
|
|
|
|
|
|
}
|
2025-09-05 10:14:45 -04:00
|
|
|
|
|
|
|
|
|
|
private void GenerateEndMark(Vector2 pos)
|
|
|
|
|
|
{
|
|
|
|
|
|
RectTransform canvasRect = GameManager.instance.judgeHintCanvas.GetComponent<RectTransform>();
|
|
|
|
|
|
RectTransform mark = LeanPool.Spawn(GameManager.instance.basePrefabs.inputEndMark, canvasRect).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.one * 5f;
|
|
|
|
|
|
});
|
|
|
|
|
|
ss.Join(mark.GetComponent<Image>().DOFade(0, 0.25f));
|
|
|
|
|
|
ss.Join(mark.DOScale(0, 0.25f));
|
|
|
|
|
|
ss.OnComplete(() => LeanPool.Despawn(mark.gameObject));
|
|
|
|
|
|
ss.SetUpdate(true);
|
|
|
|
|
|
ss.Play();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void GenerateCanceledMark(Vector2 pos)
|
|
|
|
|
|
{
|
|
|
|
|
|
RectTransform canvasRect = GameManager.instance.judgeHintCanvas.GetComponent<RectTransform>();
|
|
|
|
|
|
RectTransform mark = LeanPool.Spawn(GameManager.instance.basePrefabs.inputCanceledMark, canvasRect).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.one * 5f;
|
|
|
|
|
|
});
|
|
|
|
|
|
ss.Join(mark.GetComponent<Image>().DOFade(0, 0.25f));
|
|
|
|
|
|
ss.Join(mark.DOScale(0, 0.25f));
|
|
|
|
|
|
ss.OnComplete(() => LeanPool.Despawn(mark.gameObject));
|
|
|
|
|
|
ss.SetUpdate(true);
|
|
|
|
|
|
ss.Play();
|
|
|
|
|
|
}
|
2025-07-21 05:42:20 -04:00
|
|
|
|
}
|