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

Unity第三人称移动端相机首次拖拽旋转跳变问题求助

问题解决:移动端第三人称相机首次拖拽跳变旋转

问题根源
你遇到的首次拖拽跳变,是因为坐标坐标系不匹配:

  • OnPointerDown中存储的是屏幕全局坐标eventData.position
  • 但OnDrag里计算拖拽增量时,用的是触摸区域的本地坐标localPointerPosition
    两者坐标系完全不同,首次计算的delta值会异常大,直接导致相机跳变旋转。每次抬起指针后再次按下,都会重复这个错误。

修复方案
在OnPointerDown时,就将触摸点转换为触摸区域的本地坐标,存储到lastDragPosition中,确保后续计算增量时坐标系统一。另外,初始化xAxis和yAxis时,读取相机当前的欧拉角,避免初始值与实际相机旋转不一致的问题。

修改后的完整代码

using UnityEngine;
using UnityEngine.EventSystems;

public class CameraMobile2 : MonoBehaviour, IDragHandler, IPointerDownHandler, IPointerUpHandler
{
    public float rotationSpeed;
    private float xAxis;
    private float yAxis;

    private float minRotation = 10f;
    private float maxRotation = 60f;

    public Transform playerHead;
    public Transform cameraTransform;
    public RectTransform touchpadRect;

    private bool isDragging = false;
    private Vector2 lastDragPosition;

    private void Start()
    {
        // 初始化时读取相机当前的旋转值,避免初始偏差
        xAxis = cameraTransform.eulerAngles.x;
        yAxis = cameraTransform.eulerAngles.y;
        // 处理x轴欧拉角可能的360度循环问题(比如相机初始旋转是350度,实际是-10度)
        if (xAxis > 180f)
        {
            xAxis -= 360f;
        }
        xAxis = Mathf.Clamp(xAxis, minRotation, maxRotation);
    }

    public void OnPointerDown(PointerEventData eventData)
    {
        isDragging = true;
        // 将屏幕坐标转换为触摸区域的本地坐标后存储
        RectTransformUtility.ScreenPointToLocalPointInRectangle(touchpadRect, eventData.position, null, out lastDragPosition);
        Debug.Log("pointer Down");
    }

    public void OnDrag(PointerEventData eventData)
    {
        Debug.Log("pointer drag");

        if (!isDragging)
        {
            return;
        }

        Vector2 localPointerPosition;
        if (RectTransformUtility.ScreenPointToLocalPointInRectangle(touchpadRect, eventData.position, null, out localPointerPosition))
        {
            Vector2 delta = localPointerPosition - lastDragPosition;
            lastDragPosition = localPointerPosition;

            yAxis += delta.x * rotationSpeed * Time.deltaTime;
            xAxis -= delta.y * rotationSpeed * Time.deltaTime;
            xAxis = Mathf.Clamp(xAxis, minRotation, maxRotation);

            Vector3 targetRotation = new Vector3(xAxis, yAxis);
            cameraTransform.eulerAngles = targetRotation;
        }
    }

    public void OnPointerUp(PointerEventData eventData)
    {
        Debug.Log("pointer Up");
        isDragging = false;
    }

    private void Update() 
    {
        cameraTransform.position = playerHead.position - cameraTransform.forward * 2f;
    }
}

额外说明

  • Start方法中初始化xAxis和yAxis,是为了让相机的初始旋转和代码中的累积变量保持一致,避免首次运行时相机突然跳到(0,0)旋转。
  • 处理x轴欧拉角的360度循环问题,是因为Unity中欧拉角会以0-360度循环,而我们需要的是min到max范围内的数值,避免出现异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 08:05:17