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

Unity 2D拖拽图像鼠标大幅移动仅微小位移问题排查

Scroll View中2D图像拖拽位移极小的问题排查与解决

我编写了以下代码用于在Scroll View中移动2D图像,代码可正常运行,但图像仅会产生微小位移。即使鼠标在整个屏幕范围内拖拽,图像的移动距离也很小,请问这是什么原因?

using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

public class DraggableObject : MonoBehaviour, IPointerDownHandler, IPointerUpHandler
{
    private bool isDragging = false;
    private Vector3 offset;
    private SceneController sceneController;
    [SerializeField] GameObject ObjectToDrag;
    [SerializeField] private BoxCollider boxCollider;
    [SerializeField] private Image image;

    void Start()
    {
        sceneController = GameObject.Find("Controller").GetComponent<SceneController>();
    }

    void Update()
    {
        if (isDragging)
        {
            ObjectToDrag.transform.position = Camera.main.ScreenToWorldPoint(Input.mousePosition) + offset;
        }
    }

    public void SetSizeOfBoxCollider()
    {
        RectTransform rectTransform = image.rectTransform;
        float width = rectTransform.rect.width;
        float height = rectTransform.rect.height;
        Vector3 sizeAsVector3 = new Vector3(width, height, 0);

        boxCollider.size = sizeAsVector3;

    }

    public void OnPointerDown(PointerEventData eventData)
    {
        isDragging = true;
        offset = ObjectToDrag.transform.position - Camera.main.ScreenToWorldPoint(Input.mousePosition);
        sceneController.DeactivateScrollView();
    }

    public void OnPointerUp(PointerEventData eventData)
    {
        isDragging = false;
        sceneController.ActivateScrollView();
    }
}

问题根源

  1. 坐标转换逻辑错误:UI元素(如Image)属于Canvas系统,依赖RectTransform的锚点坐标而非3D世界坐标。你用Camera.main.ScreenToWorldPoint将屏幕坐标转为3D世界坐标,当相机与UI的Z轴位置不匹配时,会导致坐标被异常缩放,最终拖拽位移被大幅压缩。
  2. 位置控制方式错误:直接修改UI元素的transform.position会违背Canvas的布局规则,UI元素的标准位置控制属性是anchoredPosition。

修复方案

改用Unity官方推荐的UI坐标处理方式,替换拖拽逻辑为UI专用的事件接口:

using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

public class DraggableObject : MonoBehaviour, IPointerDownHandler, IPointerUpHandler, IDragHandler
{
    private bool isDragging = false;
    private Vector2 offset;
    private SceneController sceneController;
    [SerializeField] private RectTransform objectToDrag; // 直接引用RectTransform
    [SerializeField] private BoxCollider boxCollider;
    [SerializeField] private Image image;

    void Start()
    {
        sceneController = GameObject.Find("Controller").GetComponent<SceneController>();
        SetSizeOfBoxCollider();
    }

    // 用IDragHandler的OnDrag替代Update判断,更符合UI事件生命周期
    public void OnDrag(PointerEventData eventData)
    {
        if (isDragging)
        {
            // 将屏幕坐标转为父容器的本地坐标
            RectTransformUtility.ScreenPointToLocalPointInRectangle(
                objectToDrag.parent.GetComponent<RectTransform>(),
                eventData.position,
                eventData.pressEventCamera,
                out Vector2 localPoint);
            
            objectToDrag.anchoredPosition = localPoint + offset;
        }
    }

    public void SetSizeOfBoxCollider()
    {
        RectTransform rectTransform = image.rectTransform;
        float width = rectTransform.rect.width;
        float height = rectTransform.rect.height;
        Vector3 sizeAsVector3 = new Vector3(width, height, 0);

        boxCollider.size = sizeAsVector3;
    }

    public void OnPointerDown(PointerEventData eventData)
    {
        isDragging = true;
        // 计算鼠标点击点与UI锚点的偏移量
        RectTransformUtility.ScreenPointToLocalPointInRectangle(
            objectToDrag.parent.GetComponent<RectTransform>(),
            eventData.position,
            eventData.pressEventCamera,
            out Vector2 localPoint);
        
        offset = objectToDrag.anchoredPosition - localPoint;
        sceneController.DeactivateScrollView();
    }

    public void OnPointerUp(PointerEventData eventData)
    {
        isDragging = false;
        sceneController.ActivateScrollView();
    }
}

关键修改点

  • 将GameObject ObjectToDrag改为RectTransform objectToDrag,直接操作UI的核心布局组件
  • 使用RectTransformUtility.ScreenPointToLocalPointInRectangle处理UI坐标转换,避免3D世界坐标的缩放问题
  • 实现IDragHandler接口,用OnDrag方法处理拖拽逻辑,性能和事件响应更可靠
  • 所有位置控制改用anchoredPosition,符合UI系统的布局规则

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 08:57:26