Unity UI的transform,recttransform,position的相互转换

Posted NerfmePlz

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Unity UI的transform,recttransform,position的相互转换相关的知识,希望对你有一定的参考价值。

学习中遇到一些坑,记录一下,因为RectTransform坐标转换第一次遇到真的头疼

1,首先要理解RectTransform是Transform的子类,而所有的UI组件,在代码中获取的transform.position实际上都是rectTransform.anchoredPosition,也就是说,新建一个空物体,加入Image、Text等组件后,这个物体只有在Canvas下,才能显示出来,它的Transform组件自动被替换为RectTransform。

2, rectTransform.anchoredPosition是该UI物体的Pivot对应它的锚点的坐标,如果锚点为一个点,就比较好理解,如果锚点是父物体Panel或者canvas的四个角,那还牵涉到unity内部的一些计算,具体这里不深入研究。

3, 那么如果我们需要一个一个UI的世界坐标,来进行一些操作,应该怎么做?

假设:(1) 目标ui在canvas下,canvas的模式为camera,camera为专门的UIcamera。此时UI和canvas画布是可以在scene中看到的,作为游戏物体的一部分出现。

(2)我们还有一个maincamera来拍摄渲染整个游戏场景

(3) 我们需要一个linerenderer来从ui指向场景中某个物体。

那么场景中的物体坐标很容易得到,我们需要的就是UI的坐标。

第一步:将UI的position转换为屏幕坐标

unity提供了一个方法RectTransformUtility.WorldToScreenPoint(Camera camera,Vector3 point),我们将UI的transform.position也就是实际上的rectTransform.anchoredPosition传进point中,将UIcamera传进camera中,就可以得到这个ui的屏幕坐标。

RectTransformUtility.WorldToScreenPoint(UIcamera,transform.position)

第二步,将屏幕坐标转换为世界坐标

这时我们所选用的摄像机就由UIcamera换成Camera.main,因为canvas在任何位置都不影响UIcamera渲染它,而我们游戏世界是由maincamera来渲染的,所以此时摄像机应该使用mainCamera。

unity同样提供了一个方法Camera.ScreenToWorldPoint(Vector3 point)来处理这个问题,需要注意的是,之前RectTransformUtility.WorldToScreenPoint方法的返回值是一个Vector2,而这个方法的入参是vector3,需要处理一下Z轴,否则返回值永远是一个(0,0,0)的三维向量。

 //主相机到2D界面的距离
            float distance = Mathf.Abs(GameObject.Find("BackGroundCanvas").GetComponent<Canvas>().planeDistance) ;
            // return GameObject.Find("UICamera").GetComponent<Camera>().ScreenToWorldPoint(new Vector3(mousPos.x, mousPos.y, distance));
            return camera.ScreenToWorldPoint(new Vector3(mousPos.x, mousPos.y, distance));

此处我的项目是一个2D项目,暂时的Z轴使用背景层canvas的planedistance,方法外部再进行-1,以保证生成的linerenderer在背景层上显示。

第二个坑: UI预制体创建时如果没有指定父物体为canvas,就会导致位置、大小出现问题

因为canvas的camera模式在渲染时是进行了缩放的:如果没有缩放,那么比如canvas的planedistance设定为100,那么在摄像机中看到的canvas就会非常小了。如果没有指定父物体为canvas或其子物体,就会导致创建出来的UI物体巨大,位置也因为LocalPosition等变换问题出现奇怪的偏移

总结:折腾了一天才处理明白,我的处理方法应该也不是最好的,因为感觉堆2D项目中Z轴、DEPTH的理解还不够清晰。

unity-------------UI的界面调节

Rect Transform

我们都知道,Unity3D中所有的GameObject都必须要携带一个Transform组件,且该组件无法移除,那么作为UI显示的GameObject则不是携带Transform而是使用Unity3D专门为UI组件设计的Rect Transform组件,如下:

另外说一下,Canvas Renderer也是UI组件必须携带的组件。

我们来看一下其为我们提供的功能:

位置

位置是以像素为单位,其具体的值则以锚点为准,表示和锚点距离,其中x轴从左到右的数值越来越大,y轴从下到上的数值越来越大,其中的Pos Z和Transform中的position.z效果一致,但不是使用该值来表示UI的深度。保留该值估计是为了在3D UI的一些效果实现上的考虑。

尺寸

不同于缩放,这两个值设置了UI的尺寸,为负并不会翻转UI而是直接不显示。

上面的两个按钮,上方的按钮是设置width为320,下方则是将width为160的按钮的scale x设置为2。

旋转

效果同Transform,一般配合Tween使用。

缩放

效果同Transform,一般配合Tween使用。

深度

不通过NGUI的深度,在UGUI中的深度完全使用树形结构来表示,同一层级里位于下方的节点会覆盖掉位于上方的节点,如下:

修改一下树形显示列表后如下:

Anchor

Rect Transform除了上面提到的功能外,还提供了描点功能,该功能主要实现相对布局的功能。

同时我们还可以非常直观的配置描点:

锚点描述的是当前UI的父对象的位置信息。而锚点则表示当前对象坐标的(0, 0)点。

非stretch

我们可以发现有Left、Center、Right、Top、Middle及Bottom六个设置项,这6个项目可以组合出9种形式的锚点,分别对应了当前UI父对象的9个方向的位置,这样方便我们的UI做相对位置的调整,比如当UI的坐标为(0, 0),选择CenterMiddle则当前UI为居中状态,而选择TopLeft则UI会位于父对象的左上角。

CenterMiddle:

TopLeft:

stretch

除了上面说到的还有一种stretch状态,该状态则表示当前UI距离父级UI边缘的距离,当设定了之后则是使用一种类似相对位置的方式来定义UI的位置及尺寸,我们看下:

当我们选择水平和垂直都为stretch时,Pos X、Pos Y、Width和Height都改变为Left、Top、Right及Bottom,即使用了相对位置来排列,我们调整一下看看。

我们发现按钮始终和父级保持10个像素的距离,调整父级的尺寸会修改子级的尺寸,如下:

我们发现按钮始终为一种相对的位置呈现。

自定义Anchor

我们之前定义锚点都是直接在下拉菜单中选择,那么锚点是否可以自定义,答案是肯定的,比如当我们需要下面的效果时就需要自定义Anchor了。

我们希望子UI的尺寸始终和父UI的尺寸保持一定的比例,比如无论父UI多大,子UI都占其10%的空间。

我们只需要将子UI的锚点设置为一个合适的值即可,比如设置为子UI的尺寸,如下:

我们复制几个改变大小看看效果:

Pivot

注册点或者叫做中心点,如果说Anchor表示的是UI的父级的位置,那么Pivot则表示UI本身的(0, 0)点的位置。

我们首先开启Pivot:

然后就可以在场景中修改UI的Pivot了,如下:

这个小蓝圈就是Button组件的中心点,表示Button组件的(0, 0)点。

下面我们看一个实例:

我希望在屏幕的右上方显示一个按钮且按钮和屏幕的间距为10,只需要将按钮的中心点也设置到右上方即可,如下:

补充

蓝图模式

表示是否忽略掉物体的旋转。点开不能对物体进行旋转。

RawEdit模式

表示当修改Anchor时UI的位置及尺寸是否会根据Anchor进行匹配,点开可以进行匹配。

以上是关于Unity UI的transform,recttransform,position的相互转换的主要内容,如果未能解决你的问题,请参考以下文章

Unity3D之UGUI:Rect Transform与Anchor

unity-------------UI的界面调节

unity怎么实现UI缓慢移动

unity UGUI怎么让 被拖拽的UI最后渲染

Unity——RectTransform详解

2019.9.30 Unity 3D之UI设置父子关系setParent坑