曾几何时,我一直被Unity里的GUI跟坐标相关的一些问题困扰。比如在做UGUI的一些位移动画,控制UI的拖拽或者就是想在UI的某个位置显示一个实体时,总是会发生很多莫名奇妙的问题。究其原因,就是因为当时没把一些原理弄清楚。

所以今天决定写下这篇文章,来把这些问题捋一捋。

  • 首先提下Unity中的2D坐标系。

如图,在Unity中使用许多2D坐标空间,其中大多数将X定义为向右递增,而Y则向上递增。一个例外是在GUI和GUILayout类中,其中Y向下增加。

Rect坐标系和屏幕坐标系
在GUI和GUILayout是个例外,注意这里的GUI不是指UGUI

在运行时中,我们自然少不了和UGUI打交道,在UGUI中,RectTransform是一个很重要的概念。下面这篇文章有详细讲解:

Unity——RectTransform详解​www.jianshu.com

其中很重要的一点是,UI物体的anchorPosition的指的就是UI物体基于RectTransform来描述的相对于它的父物体的局部坐标。

这里着重讲讲曾经我总是有点迷糊的问题——做UGUI位移动画时的坐标问题。举个例子,现在我在场景中有一个这样的UI:

要求是:当鼠标左键按下时,Image物体跟随鼠标移动,但不能超过Panel的边界。

首先考虑到的是,要将屏幕坐标转换为UGUI相关的坐标。但是怎么转换呢?我们需要用到RectTransformUtility工具类:

//将屏幕空间点转换为位于矩形平面上的RectTransform的局部空间中的位置。
//cam参数应该是与屏幕点相关联的摄像机。
//对于画布中的RectTransform设置为Screen Space - Overlay模式,cam参数应该为null。
//当从提供PointerEventData对象的事件处理程序中使用ScreenPointToLocalPointInRectangle时,
//可以通过使用PointerEventData获得正确的摄像机。
//enterEventData(用于悬停功能)或PointerEventData。
//pressEventCamera(用于单击功能)。这将自动为给定的事件使用正确的相机(或null)。
RectTransformUtility.ScreenPointToLocalPointInRectangle (m_parent,Input.mousePosition,canvas.renderMode == RenderMode.ScreenSpaceOverlay?null : canvas.worldCamera,out _parentLocalPosWithScreenPos)
//可以理解为在屏幕坐标ScrrenPoint处发条Z方向的射线,摄像与rect的交点就是返回的世界坐标worldPoint。
//得到鼠标位置投射在Canvas平面上的世界坐标点。
if (canvas.renderMode != RenderMode.ScreenSpaceCamera && RectTransformUtility.ScreenPointToWorldPointInRectangle (canvas.transform as RectTransform,Input.mousePosition,canvas.worldCamera,out _hitWpos)) {cube.position = _hitWpos;}
//指定的RectTransform范围内是否包含对应的屏幕坐标
RectangleContainsScreenPoint(RectTransform rect, Vector2 screenPoint, Camera cam);

通过上面的注释可知,可以使用ScreenPointToLocalPointInRectangle这个方法。由名字就可以看出,它把一个屏幕空间上的点,转换成rect的内部坐标,但需要注意的是:Canvas 的RenderMode在Camera和World模式下,传入的camera为UI摄像机,在OverLay,camara参数应该传入null。

要使Image物体移动,需要改变Image的位置。由前面提供的文章可知,在UGUI中,我们不能去直接修改它的世界坐标,而是应该修改Image的anchorPosition(锚点位置)而anchorPosition就是Image相对于Plane的基于Rect的局部坐标(anchorPosition)。所以下面的代码中:通过ScreenPointToLocalPointInRectangle计算出的_parentLocalPosWithScreenPos即为Image的anchorPosition,然后通过rect.width来限制即可。

public class UGUITween : MonoBehaviour {public Canvas canvas;//image物体public RectTransform targetRectTransform;//image父物体RectTransform m_parent;void Start () {m_parent = targetRectTransform.parent as RectTransform;}void Update () {if (Input.GetMouseButton (0)) {Vector2 _parentLocalPosWithScreenPos = Vector2.zero;if (RectTransformUtility.ScreenPointToLocalPointInRectangle (m_parent,Input.mousePosition,canvas.renderMode == RenderMode.ScreenSpaceOverlay?null : canvas.worldCamera,out _parentLocalPosWithScreenPos)) {//_parentLocalPosWithScreenPos为targetRectTransform的局部坐标Rect _parentRect = m_parent.rect;_parentLocalPosWithScreenPos.x = Mathf.Clamp (_parentLocalPosWithScreenPos.x,//_parent的枢轴点在中心-_parentRect.width * 0.5f + targetRectTransform.rect.width * 0.5f,_parentRect.width * 0.5f - targetRectTransform.rect.width * 0.5f);_parentLocalPosWithScreenPos.y = Mathf.Clamp (_parentLocalPosWithScreenPos.y,-_parentRect.height * 0.5f + targetRectTransform.rect.height * 0.5f,_parentRect.height * 0.5f - targetRectTransform.rect.height * 0.5f);//运动targetRectTransform.anchoredPosition = Vector2.Lerp (targetRectTransform.anchoredPosition, _parentLocalPosWithScreenPos, .5f);}}}
}

还需要注意的是,进行位置限定时。需要使用.rect,而非.sizeDelta,网上有些资料有误导。具体原因参考前面提供的文章链接。

unity panel如何设置控件位置_Unity 关于GUI与UGUI坐标 的一点问题解惑相关推荐

  1. WPF中通过控件Margin属性设置控件位置

    WPF中通过控件Margin属性设置控件位置 一.Margin属性简介 二.Margin在cs文件中定义 三.Margin设置控件位置 四.参考文档 一.Margin属性简介 在使用WPF进行页面设计 ...

  2. html设置控件位置大小,下面那个代码段设置myButton控件显示在HTML页左上角100px的位置 - 问答库...

    问题: [多选] 下面那个代码段设置myButton控件显示在HTML页左上角100px的位置?() A . B . C . D . 调度例行会议形式有什么() 生产平衡会. 事故分析会. 调度专业会 ...

  3. qt 手动设置控件的位置

    QT中的Layout用着很不错,但有时候你想指定控件绝对位置.用以下红色代码就可以了. chanel1 = new QPushButton(tr("通道1:")); chanel1 ...

  4. qt 控件设置相对位置_qt设置控件相对位置

    QT关于控件的教程_计算机软件及应用_IT/计算机_专业资料.zl使用Linux... 此例程主要展示用代码方式创建控件并用 Layout 管理类对其进行布局; 例程来自 Qt5.2,如过是默认安装, ...

  5. qt 控件设置相对位置_qt 手动设置控件的位置

    QT中的Layout用着很不错,但有时候你想指定控件绝对位置.用以下红色代码就可以了. chanel1 = new QPushButton(tr("通道1:")); chanel1 ...

  6. html 控件坐标定位,利用JS改变html控件位置

    8种机械键盘轴体对比 本人程序员,要买一个写代码的键盘,请问红轴和茶轴怎么选? 利用JS改变html控件位置 我想写一个贪吃蛇小游戏,所以需要完成蛇的自动移动效果,这就需要改变html控件位置.本来我 ...

  7. js设置控件的隐藏与显示的两种方法

    js设置控件的隐藏与显示的两种方法: js设置控件的隐藏与显示,设置控件style的display和visibility属性就可以了. 用JavaScript隐藏控件的方法有两种,分别是通过设置控件的 ...

  8. Android Studio 线性布局Linearlayout的控件位置控制l属性Layout_margin失效问题解决

    Android Studio 线性布局Linearlayout的控件位置控制l属性Layout_margin失效问题解决 问题:如layout_marginRight ="50dp" ...

  9. 设置控件背景背景颜色为透明

    有时候,我们需要将控件的背景颜色设定为透明,比如说label(标签)控件.那么,如何将控件的背景颜色设定为透明?是不是只要将控件的BackColor属性设为Transparent(透明)就可以了呢?答 ...

最新文章

  1. mysql注入漏洞语句_mysql注入sleep语句引发的拒绝服务
  2. Hive自定义UDF的JAR包加入运行环境的方法
  3. liigo:爱可视70平板电脑使用感受,遗憾与满足并存
  4. SpringBoot 2.0参数校验Hibernate Validator
  5. zoj3829 Known Notation --- 2014 ACM-ICPC Asia Mudanjiang Regional Contest
  6. java执行update的方法_解决Hibernate4执行save()或update()无效问题的方法
  7. linux 安装fortran lapack 库
  8. linux卸载deb安装的软件,ubuntu常用软件包deb的安装与卸载
  9. 邮箱登陆时显示服务器连接失败,邮箱显示无法连接服务器
  10. .Net框架搭建之辅助模版代码生成工具
  11. 卡卡云模板(适配彩虹发卡系统)
  12. springboot 定时器使用方法之并行
  13. java 判断今天_java判断日期是否是今天
  14. Laravel 使用 seeder 使用要点
  15. 一键获取lazada商品评论
  16. Java中巧算年龄的代码,巧算年龄 - 寂寞暴走伤的个人空间 - OSCHINA - 中文开源技术交流社区...
  17. mysql数据库的连接
  18. split使用总结,被坑的正则特殊符号:*/+
  19. PT2262软件解码程序
  20. numpy中linspace用法

热门文章

  1. 超牛EXCEL操作技巧,用的好,会涨工资哦
  2. AI时代的领航者,智能电话机器人对市场的影响
  3. jira 配置自签SSL证书windowsAD域
  4. 11.3-全栈Java笔记:线程的生命周期
  5. iptables踩坑记
  6. http状态码302,303,307的区别
  7. 如何构造强度较高的密码
  8. 十佳自由Linux物理工具
  9. javax/management/DynamicMBean
  10. python隐藏部分代码_python隐藏类中属性的3种实现方法