【unity游戏开发入门到精通——UGUI】屏幕坐标转UI本地坐标 —— RectTransformUtility类实现拖拽UI对象跟顺鼠标移动

发布于:2025-05-02 ⋅ 阅读:(211) ⋅ 点赞:(0)

注意:考虑到UGUI的内容比较多,我将UGUI的内容分开,并全部整合放在【unity游戏开发——UGUI】专栏里,感兴趣的小伙伴可以前往逐一查看学习。

前言

RectTransformUtility是UnityEngine.UI命名空间中的一个实用工具类,专门用于处理与RectTransform相关的各种计算和转换操作。它提供了一系列静态方法来简化UI元素的坐标转换、矩形测试等常见任务。

一、屏幕坐标转UI本地坐标

1、RectTransformUtility.ScreenPointToLocalPointInRectangle方法

这是最常用的方法之一,用于将屏幕空间坐标转换为UI元素在其父对象局部坐标系中的坐标。一般配合拖拽事件使用。

1.1 方法签名

public static bool ScreenPointToLocalPointInRectangle(
    RectTransform rect, 
    Vector2 screenPoint, 
    Camera cam, 
    out Vector2 localPoint)

1.2 参数说明

  1. rect:目标RectTransform,相对父对象,转换后的坐标将相对于这个矩形
  2. screenPoint:需要转换的屏幕空间坐标(像素坐标)
  3. cam:用于渲染UI的摄像机(通常是UI摄像机)
  4. localPoint:输出参数,转换后的局部坐标

1.3 返回值

  • 如果转换成功返回true(点在矩形内)
  • 如果转换失败返回false(点不在矩形内)

2、注意事项

Canvas渲染模式

  • Screen Space - Overlay模式:可以传递null作为摄像机参数
  • Screen Space - Camera/World Space模式:必须传递正确的摄像机

坐标系差异

  • 屏幕坐标系原点在左下角
  • UI局部坐标系原点取决于RectTransform的pivot设置

3、示例:实现拖拽UI

新增脚本

using UnityEngine;
using UnityEngine.EventSystems;

public class UIDragHandler : MonoBehaviour, IDragHandler
{
    RectTransform parentRect; // 相对父对象

    void Start()
    {
        parentRect = transform.parent.GetComponent<RectTransform>();
    }

    public void OnDrag(PointerEventData eventData)
    {
        Vector2 localPos;
        
        if (RectTransformUtility.ScreenPointToLocalPointInRectangle(
            parentRect,
            eventData.position,
            eventData.pressEventCamera,
            out localPos))
        {
            // 设置当前对象在父对象局部空间中的位置。让被拖拽的对象跟着鼠标移动
            transform.localPosition = localPos;
        }
    }
}

核心逻辑

  • 获取父对象的RectTransform作为参考坐标系
  • 在OnDrag事件中,将屏幕坐标(eventData.position)转换为父对象局部空间中的坐标
  • 将UI元素的位置设置为转换后的局部坐标

挂载脚本
在这里插入图片描述
效果
在这里插入图片描述

4、为什么不是直接使用eventData.delta实现拖拽UI?

比如

using UnityEngine;
using UnityEngine.EventSystems;

public class UIDragHandler : MonoBehaviour, IDragHandler
{
    public void OnDrag(PointerEventData eventData)
    {
        // 根据鼠标/触摸滑动的位移,调整当前对象的世界坐标位置
        transform.position += new Vector3(eventData.delta.x, eventData.delta.y, 0);
    }
}

效果貌似是一样的。
在这里插入图片描述
但是直接使用eventData.delta的旧方法:

  • 只考虑屏幕空间的增量移动
  • 不处理UI层级关系
  • 可能在不同分辨率或缩放情况下表现不一致
  • 不考虑父对象的变换属性

5、RectTransformUtility.ScreenPointToLocalPointInRectangle优势

  • 保持正确的父子层级关系
  • 自动处理所有变换矩阵计算
  • 在不同分辨率/设备上表现一致
  • 支持复杂的UI层级结构
  • 正确处理旋转/缩放的父对象

总结来说,这种方法更精确、更可靠,能正确处理UI系统中的各种复杂情况,是Unity UI推荐的拖拽实现方式

二、其他相关方法

  1. ScreenPointToWorldPointInRectangle:将屏幕点转换为世界空间中的点
  2. WorldToScreenPoint:将世界空间点转换为屏幕空间点
  3. PixelAdjustPoint:调整点坐标以适应像素完美的UI
  4. RectangleContainsScreenPoint:检查屏幕点是否在矩形内

专栏推荐

地址
【unity游戏开发入门到精通——C#篇】
【unity游戏开发入门到精通——unity通用篇】
【unity游戏开发入门到精通——unity3D篇】
【unity游戏开发入门到精通——unity2D篇】
【unity实战】
【制作100个Unity游戏】
【推荐100个unity插件】
【实现100个unity特效】
【unity框架/工具集开发】
【unity游戏开发——模型篇】
【unity游戏开发——InputSystem】
【unity游戏开发——Animator动画】
【unity游戏开发——UGUI】
【unity游戏开发——联网篇】
【unity游戏开发——优化篇】
【unity游戏开发——shader篇】

完结

好了,我是向宇,博客地址:https://xiangyu.blog.csdn.net,如果学习过程中遇到任何问题,也欢迎你评论私信找我。

赠人玫瑰,手有余香!如果文章内容对你有所帮助,请不要吝啬你的点赞评论和关注,你的每一次支持都是我不断创作的最大动力。当然如果你发现了文章中存在错误或者有更好的解决方法,也欢迎评论私信告诉我哦!
在这里插入图片描述


网站公告

今日签到

点亮在社区的每一天
去签到