You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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,提问作者Сергей Хрящёв

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 18:42:25