修了不少东西

This commit is contained in:
2026-07-16 23:04:59 +08:00
parent 29972d0705
commit 73fe474cc6
134 changed files with 7673 additions and 741 deletions
@@ -1,15 +1,25 @@
using System.Collections.Generic;
using UnityEngine;
#if ENABLE_INPUT_SYSTEM
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.EnhancedTouch;
using ETouch = UnityEngine.InputSystem.EnhancedTouch.Touch;
#endif
/// <summary>
/// 手游触屏输入分发器:每帧遍历所有触摸点(及编辑器鼠标),用 Physics2D.OverlapPoint
/// 命中带 TrackTouchZone 的透明 Collider2D,把按下/抬起转发给 InputManager。
///
/// 为什么用这种方式而不是 UI 的 IPointerDownHandler
/// 【多点触控根因】项目 activeInputHandler = Both(同时启用新旧输入系统)。
/// 在这种配置下,旧版 UnityEngine.Input.touches 走的是兼容 shim,同时按多指时
/// 常常只上报一个触点 → 只能触发一个轨道。所以这里优先用新输入系统的
/// EnhancedTouchTouch.activeTouches),它能可靠上报所有并发手指;
/// 仅在没有新输入系统时回退到旧版 Input.touches。判定逻辑完全不变。
///
/// 为什么用物理命中而不是 UI 的 IPointerDownHandler
/// - 轨道会平移+旋转晃动,点击区必须跟随晃动的 ColliderOverlapPoint 支持旋转过的碰撞体)。
/// - 需要多点触控:每根手指独立按住各自的轨道(靠 fingerId 配对按下/抬起)。
/// - 需要多点触控:每根手指独立按住各自的轨道(靠 touchId 配对按下/抬起)。
///
/// 判定逻辑完全不变:这里只调用现成的 PressTrack/ReleaseTrack
/// 判定时间戳仍由 Note.HandlePress 读取 GameplayClock.NowSongTimedspTime)。
///
/// 用法:场景里放一个空物体挂本脚本,把主相机拖到 gameplayCamera(留空则自动取 Camera.main)。
@@ -35,10 +45,8 @@ public class TrackTouchInput : MonoBehaviour
"留空自动按相机 orthographic 判断;一般不用手动改。")]
[SerializeField] private bool forceOrthographicMode = false;
// fingerId -> 当前按住的轨道索引。用于在抬起/取消时精确释放对应轨道。
// 触点 id -> 当前按住的轨道索引。用于在抬起/取消时精确释放对应轨道。
private readonly Dictionary<int, int> _activeTouches = new Dictionary<int, int>();
// 鼠标模拟用的"手指 id",取一个不会和真实 fingerId 冲突的值。
private const int MouseFingerId = -100;
private int _mouseHeldTrack = -1;
private Camera Cam
@@ -50,14 +58,13 @@ public class TrackTouchInput : MonoBehaviour
}
}
private void Awake()
#if ENABLE_INPUT_SYSTEM
private void OnEnable()
{
// 【多点触控根因修复】若 multiTouchEnabled 为 falseInput.touchCount 永远 ≤1
// 同时按多条轨道时只会报告一个触点 → 只能触发一个轨道。强制开启多点触控。
// simulateMouseWithTouches 关掉:避免触摸被合成成鼠标事件,与真实多指冲突。
Input.multiTouchEnabled = true;
Input.simulateMouseWithTouches = false;
// 开启增强触摸,Touch.activeTouches 才会被填充。
EnhancedTouchSupport.Enable();
}
#endif
private void Update()
{
@@ -67,50 +74,101 @@ public class TrackTouchInput : MonoBehaviour
Camera cam = Cam;
if (cam == null) return;
ProcessTouches(im, cam);
int touchCount = ProcessTouches(im, cam);
if (enableMouseFallback && Input.touchCount == 0)
if (enableMouseFallback && touchCount == 0)
{
ProcessMouse(im, cam);
}
}
private void ProcessTouches(InputManager im, Camera cam)
/// <summary>处理所有并发触点,返回本帧触点数量。</summary>
private int ProcessTouches(InputManager im, Camera cam)
{
for (int i = 0; i < Input.touchCount; i++)
#if ENABLE_INPUT_SYSTEM
// 优先走新输入系统的增强触摸:可靠上报所有并发手指。
var touches = ETouch.activeTouches;
int count = touches.Count;
for (int i = 0; i < count; i++)
{
ETouch t = touches[i];
switch (t.phase)
{
case UnityEngine.InputSystem.TouchPhase.Began:
HandleTouchBegan(im, cam, t.touchId, t.screenPosition);
break;
case UnityEngine.InputSystem.TouchPhase.Ended:
case UnityEngine.InputSystem.TouchPhase.Canceled:
HandleTouchEnded(im, t.touchId);
break;
// Moved / Stationary:手指在轨道内保持按住即可,不重新判定归属。
}
}
return count;
#else
// 回退:旧版 Input.touches(仅在未启用新输入系统时使用)。
int count = Input.touchCount;
for (int i = 0; i < count; i++)
{
Touch t = Input.GetTouch(i);
switch (t.phase)
{
case TouchPhase.Began:
{
int track = ResolveTrack(cam, t.position);
if (track >= 0)
{
_activeTouches[t.fingerId] = track;
im.PressTrack(track);
}
HandleTouchBegan(im, cam, t.fingerId, t.position);
break;
}
case TouchPhase.Ended:
case TouchPhase.Canceled:
{
if (_activeTouches.TryGetValue(t.fingerId, out int track))
{
_activeTouches.Remove(t.fingerId);
im.ReleaseTrack(track);
}
HandleTouchEnded(im, t.fingerId);
break;
}
// Moved / Stationary:手指在轨道内保持按住即可,不重新判定归属,
// 避免手指轻微滑动跨到相邻轨道时反复 Press/Release 造成误判。
}
}
return count;
#endif
}
private void HandleTouchBegan(InputManager im, Camera cam, int touchId, Vector2 screenPos)
{
int track = ResolveTrack(cam, screenPos);
if (track >= 0)
{
_activeTouches[touchId] = track;
im.PressTrack(track);
}
}
private void HandleTouchEnded(InputManager im, int touchId)
{
if (_activeTouches.TryGetValue(touchId, out int track))
{
_activeTouches.Remove(touchId);
im.ReleaseTrack(track);
}
}
private void ProcessMouse(InputManager im, Camera cam)
{
#if ENABLE_INPUT_SYSTEM
var mouse = Mouse.current;
if (mouse == null) return;
if (mouse.leftButton.wasPressedThisFrame)
{
int track = ResolveTrack(cam, mouse.position.ReadValue());
if (track >= 0)
{
_mouseHeldTrack = track;
im.PressTrack(track);
}
}
else if (mouse.leftButton.wasReleasedThisFrame)
{
if (_mouseHeldTrack >= 0)
{
im.ReleaseTrack(_mouseHeldTrack);
_mouseHeldTrack = -1;
}
}
#else
if (Input.GetMouseButtonDown(0))
{
int track = ResolveTrack(cam, Input.mousePosition);
@@ -128,6 +186,7 @@ public class TrackTouchInput : MonoBehaviour
_mouseHeldTrack = -1;
}
}
#endif
}
/// <summary>
@@ -135,8 +194,7 @@ public class TrackTouchInput : MonoBehaviour
///
/// 相机移动/晃动/推拉时,每帧都用当前相机状态转换,所以命中自动跟随相机。
/// - 正交相机:ScreenToWorldPoint 忽略深度,直接取 x/y。
/// - 透视相机:从相机发射线,求与轨道平面(Z = trackPlaneWorldZ)的交点
/// 避免因相机 Z 变化(如 cameraDash)导致命中点偏移。
/// - 透视相机:从相机发射线,求与轨道平面(Z = trackPlaneWorldZ)的交点
/// </summary>
private int ResolveTrack(Camera cam, Vector2 screenPos)
{
@@ -149,7 +207,6 @@ public class TrackTouchInput : MonoBehaviour
}
else
{
// 透视:射线与轨道平面(法线 +Z,过 z = trackPlaneWorldZ)求交。
Ray ray = cam.ScreenPointToRay(screenPos);
float denom = ray.direction.z;
if (Mathf.Abs(denom) < 1e-6f)
@@ -187,5 +244,9 @@ public class TrackTouchInput : MonoBehaviour
}
_activeTouches.Clear();
_mouseHeldTrack = -1;
#if ENABLE_INPUT_SYSTEM
EnhancedTouchSupport.Disable();
#endif
}
}