Unity C#开发安卓游戏能否检测两个独立的同时滑动手势?
Unity 安卓双半区独立滑动检测实现方案
问题根源
原有脚本采用单触摸串行逻辑,仅维护全局单一滑动状态,识别到第一根手指的触摸后就阻塞后续触摸检测,直到当前触摸周期结束,本质是没有利用Unity多点触控的唯一标识做并行追踪,无法同时处理两个独立触摸流。
核心实现思路
- 废弃全局单状态锁,按fingerId做逐指独立追踪
Unity所有触摸事件从按下到抬起全程携带唯一的Touch.fingerId标识,不要用单个变量存储全局滑动状态,而是为左、右半区分别维护独立的滑动状态实例,两个状态完全解耦、互不干扰。 - 提前划定分区边界,触摸起始阶段判定归属
以屏幕中线Screen.width / 2f为界,仅在TouchPhase.Began阶段判定触摸点所属半区,滑动过程中即使手指越界也不更改归属,避免逻辑跳变。每个半区同一时间仅跟踪一个有效触摸,同半区新增的多余触摸直接忽略,防止误触。 - 逐帧全量遍历触摸点,禁止中途跳出循环
每帧遍历Input.touches下的所有触摸点,不要在识别到第一个有效触摸后用break或return提前终止遍历,按触摸的fingerId匹配对应半区的跟踪状态,分别处理移动、抬起、取消逻辑。 - 滑动阈值适配设备参数
直接使用EventSystem.current.pixelDragThreshold作为滑动触发阈值,该值由Unity根据当前设备的DPI、触控灵敏度自动适配,无需手动写死像素值。
核心实现代码
using UnityEngine; using UnityEngine.EventSystems; // 单区域滑动状态存储类 public class ZoneSlideState { public int TrackingFingerId = -1; // -1表示当前区域无正在跟踪的触摸 public Vector2 StartPos; public bool IsSliding; /// <summary> /// 滑动中回调:参数1为归一化滑动方向,参数2为滑动总距离 /// </summary> public System.Action<Vector2, float> OnSliding; /// <summary> /// 滑动结束回调:参数为最终归一化滑动方向 /// </summary> public System.Action<Vector2> OnSlideEnd; } public class DualZoneSlideDetector : MonoBehaviour { private float _splitLineX; private ZoneSlideState _leftZone = new ZoneSlideState(); private ZoneSlideState _rightZone = new ZoneSlideState(); private float _slideTriggerThreshold; void Start() { _splitLineX = Screen.width / 2f; _slideTriggerThreshold = EventSystem.current.pixelDragThreshold; // 此处绑定左右半区对应的游戏对象操控逻辑即可 _leftZone.OnSliding = (dir, distance) => { // 左半区操控对象的滑动响应逻辑 }; _rightZone.OnSliding = (dir, distance) => { // 右半区操控对象的滑动响应逻辑 }; } void Update() { int touchCount = Input.touchCount; for (int i = 0; i < touchCount; i++) { Touch currentTouch = Input.GetTouch(i); ZoneSlideState targetZone = null; // 触摸开始阶段判定区域归属 if (currentTouch.phase == TouchPhase.Began) { targetZone = currentTouch.position.x < _splitLineX ? _leftZone : _rightZone; // 仅当对应区域无跟踪触摸时才绑定本次触摸 if (targetZone.TrackingFingerId == -1) { targetZone.TrackingFingerId = currentTouch.fingerId; targetZone.StartPos = currentTouch.position; targetZone.IsSliding = false; } continue; } // 非开始阶段,匹配当前触摸所属的跟踪区域 if (currentTouch.fingerId == _leftZone.TrackingFingerId) { targetZone = _leftZone; } else if (currentTouch.fingerId == _rightZone.TrackingFingerId) { targetZone = _rightZone; } // 不属于任何正在跟踪的区域直接跳过 if (targetZone == null) continue; // 分阶段处理触摸事件 switch (currentTouch.phase) { case TouchPhase.Moved: Vector2 slideDelta = currentTouch.position - targetZone.StartPos; // 超过阈值才判定为有效滑动 if (!targetZone.IsSliding && slideDelta.magnitude >= _slideTriggerThreshold) { targetZone.IsSliding = true; } if (targetZone.IsSliding) { targetZone.OnSliding?.Invoke(slideDelta.normalized, slideDelta.magnitude); } break; case TouchPhase.Ended: case TouchPhase.Canceled: if (targetZone.IsSliding) { Vector2 finalDelta = currentTouch.position - targetZone.StartPos; targetZone.OnSlideEnd?.Invoke(finalDelta.normalized); } // 重置区域状态,接收下一次触摸 targetZone.TrackingFingerId = -1; targetZone.IsSliding = false; break; } } } }
避坑说明
- 不要在滑动过程中重新判定触摸所属区域,否则会出现左右操控对象跳变的问题
- 若使用Unity新Input System,核心逻辑不变,仅需替换旧Input的Touch API为新系统的触控读取接口即可
- 真机测试前确认设备多点触控功能已开启,部分安卓机型默认限制多点触控点数为1,需在设置中调整为至少2点
内容的提问来源于stack exchange,提问作者Сергей Хрящёв
相关产品推荐
相关产品推荐

