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

Unity安卓平台相机捏合缩放/变换异常问题求助

问题根源

你的捏合缩放逻辑依赖历史帧的距离差累加,且未在捏合结束时重置历史数据。松开捏合后,_pinchDistances数组仍保留上一次捏合的旧数据,新的小幅度捏合触发时,旧数据的平均差会导致_distance被错误跳变到最大值。

修复方案

改用比例缩放逻辑:每次捏合开始时记录当前手指间距和相机距离,后续通过当前间距与初始间距的比例计算相机距离;同时在捏合结束时重置状态,确保每次捏合都从当前相机状态开始。

修改后的完整代码
// 新增变量记录捏合初始状态
private float _initialPinchDistance;
private float _initialCameraDistance;
private bool _isPinching = false;

void LateUpdate()
{
    if (_target)
    {
        if (Input.touchCount == 1 && Input.GetTouch(0).phase == TouchPhase.Moved)
        {
            // 单指旋转逻辑保留
            _velocityX += _xSpeed * Input.GetTouch(0).deltaPosition.x * 0.02f;
            _velocityY += _ySpeed * Input.GetTouch(0).deltaPosition.y * 0.02f;
        }
        else if (Input.touchCount == 2)
        {
            Touch touchZero = Input.GetTouch(0);
            Touch touchOne = Input.GetTouch(1);

            // 触发捏合初始化:手指刚接触或首次进入双指状态
            if (touchZero.phase == TouchPhase.Began || touchOne.phase == TouchPhase.Began || !_isPinching)
            {
                _initialPinchDistance = Vector2.Distance(touchZero.position, touchOne.position);
                _initialCameraDistance = _distance;
                _isPinching = true;
                // 清空历史距离数组,避免旧数据干扰
                System.Array.Clear(_pinchDistances, 0, _pinchFramesCount);
                _pinchFramesIndex = 0;
            }

            // 计算当前捏合比例,转换为相机距离
            float currentPinchDistance = Vector2.Distance(touchZero.position, touchOne.position);
            float pinchScale = currentPinchDistance / _initialPinchDistance;
            // 用初始相机距离除以比例,实现捏合放大/缩小
            _distance = Mathf.Clamp(_initialCameraDistance / pinchScale, _distanceMin, _distanceMax);
        }
        else if (Input.GetMouseButton(0))
        {
            // 鼠标旋转逻辑保留
            _velocityX += _xSpeed * Input.GetAxis("Mouse X") * _distance * 0.02f;
            _velocityY += _ySpeed * Input.GetAxis("Mouse Y") * 0.02f;
        }
        else
        {
            // 无触摸时重置捏合状态
            _isPinching = false;
        }

        // 旋转与相机位置更新逻辑保留
        _rotationYAxis += _velocityX;
        _rotationXAxis -= _velocityY;
        _rotationXAxis = ClampAngle(_rotationXAxis, _yMinLimit, _yMaxLimit);
        Quaternion rotation = Quaternion.Euler(_cameraAngle, _rotationYAxis, 0);

        // 鼠标滚轮缩放逻辑保留
        _distance = Mathf.Clamp(_distance - Input.GetAxis("Mouse ScrollWheel") * _pinchZoomSensitivity, _distanceMin, _distanceMax);

        Vector3 negDistance = new Vector3(0.0f, 0.0f, -_distance);
        Vector3 position = rotation * negDistance + _target.position;
        transform.rotation = rotation;
        transform.position = position;
        _velocityX = Mathf.Lerp(_velocityX, 0, Time.deltaTime * _smoothTime);
        _velocityY = Mathf.Lerp(_velocityY, 0, Time.deltaTime * _smoothTime);
    }
}
核心修改说明
  1. 初始状态记录:每次捏合开始时,记录当前手指间距和相机的_distance值,确保缩放基于当前相机位置
  2. 比例计算替代帧差累加:用当前手指间距与初始间距的比例计算相机距离,避免帧差累加导致的跳变和误差
  3. 状态重置:无触摸输入时重置_isPinching并清空历史距离数组,确保下一次捏合不受上一次数据影响

修改后,无论小幅度还是大幅度捏合,相机都会从当前位置平滑缩放,不会出现跳转到最大范围的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 06:22:53