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

Unity触摸输入:如何检测手指Pinch In(捏合)与Pinch Out(张开)

解决Unity触摸捏合的Pinch In/Out判断问题

你的核心问题在于帧间比例对比的逻辑容易受初始值干扰,且未正确处理触摸状态的持续与切换,下面是具体的修正方案:

关键问题分析

  • 原代码中prevtouchCount从未更新,导致prevtouchCount != 2的判断只会触发一次,后续手指持续触摸时无法正确维护状态
  • 用ratio(当前距离/初始距离)和previousRatio对比,容易因初始距离的基准值导致判断波动,我们需要的是相邻两帧的距离变化来直接判断捏合方向
  • 未处理手指从2指切换到其他数量时的变量重置,会影响下一次捏合判断

修正后的代码

using UnityEngine;
using UnityEngine.InputSystem.EnhancedTouch;
using Touch = UnityEngine.InputSystem.EnhancedTouch.Touch;

public class DetectTouch : MonoBehaviour
{
    // 上一帧的触摸数量
    private int _prevTouchCount;
    // 初始两指距离(用于缩放计算)
    private float _initialPinchDistance;
    // 上一帧的两指距离(用于判断捏合方向)
    private float _lastPinchDistance;
    // 初始相机FOV
    private float _originalCameraFOV;

    private void OnEnable()
    {
        // 启用EnhancedTouch输入
        EnhancedTouchSupport.Enable();
    }

    private void OnDisable()
    {
        // 禁用EnhancedTouch,避免内存泄漏
        EnhancedTouchSupport.Disable();
    }

    void Update()
    {
        int currentTouchCount = Touch.activeFingers.Count;

        if (currentTouchCount == 2)
        {
            Touch touch1 = Touch.activeFingers[0].currentTouch;
            Touch touch2 = Touch.activeFingers[1].currentTouch;
            float currentDistance = Vector2.Distance(touch1.screenPosition, touch2.screenPosition);

            // 刚进入两指触摸状态,初始化基准值
            if (_prevTouchCount != 2)
            {
                _initialPinchDistance = currentDistance;
                _lastPinchDistance = currentDistance;
                _originalCameraFOV = Camera.main.fieldOfView;
            }
            else
            {
                // 通过帧间距离变化判断捏合方向
                if (currentDistance < _lastPinchDistance)
                {
                    Debug.Log("Pinch In(手指靠近)");
                }
                else if (currentDistance > _lastPinchDistance)
                {
                    Debug.Log("Pinch Out(手指远离)");
                }
                // 相等时不做处理,避免抖动

                // 更新缩放逻辑(保留原有缩放功能)
                float ratio = currentDistance / _initialPinchDistance;
                Camera.main.fieldOfView = _originalCameraFOV / ratio;
            }

            // 更新上一帧的距离
            _lastPinchDistance = currentDistance;
        }
        else
        {
            // 当触摸数量从2变为其他时,重置变量,避免影响下一次捏合
            if (_prevTouchCount == 2)
            {
                _initialPinchDistance = 0;
                _lastPinchDistance = 0;
            }
        }

        // 必须更新上一帧的触摸数量,否则无法检测状态切换
        _prevTouchCount = currentTouchCount;
    }
}

核心改动说明

  • 帧间距离对比:用currentDistance和_lastPinchDistance直接对比,精准判断每帧的手指移动方向,避免比例带来的波动
  • 状态切换处理:在触摸数量从2变为其他时重置变量,确保下次捏合的初始值正确;同时在刚进入2指状态时初始化所有基准值
  • 输入系统生命周期管理:添加OnEnable/OnDisable来管理EnhancedTouch的启用/禁用,符合Unity最佳实践
  • 避免无效判断:当两帧距离相等时不输出日志,过滤微小抖动导致的误判

关于手指持续触摸的处理

只要保持_prevTouchCount的更新,以及在每帧维护_lastPinchDistance,即使用户始终不抬起手指,代码也能持续、稳定地判断捏合方向,同时正确执行缩放逻辑。

内容的提问来源于stack exchange,提问作者Saif

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 21:45:28