Unity UGUI系列四 Pivot Anchor

Unity UGUI系列四 Pivot Anchor,第1张

参考

Unity进阶技巧 - RectTransform详解

Unity——RectTransform详解

屏幕适配实用技巧

揭秘!anchoredPosition的几何意义!

localPosition与anchoredPosition转化之瞎猫找死耗子

首先为了让大家更好的理解内容,我在Unity中创建了两个UI控件,一个Plane控件,作为父对象,一个Image控件,最为子对象,如下图:

Pivot我们可以暂且称它为中心轴(这个翻译不太准确,但为了便于理解,先这么叫着),它是一个X,Y值范围是0到1的点,这个点的会在Anchor(锚点)计算位置的时候会使用到,下面用一张图来解释Pivot点的位置

旋转、大小和缩放修改发生在主轴Pivot点周围,因此Pivot的位置会影响旋转、调整大小或缩放的结果。

关于Anchor锚点可能接触过UI的朋友都了解一些,但是Unity中Anchor应该称它为锚框更为合理,因为它是由两个锚点(Min,Max)组成的一个矩形,当然也可以组成一个点(两个点重合)

当然上图是两个锚点重合的情况,所以看上去是一个点,下面我们利用两个锚点不重合的情况来说明一下:

在了解了Pivot和Anchor分别是什么后,我们就来看看Unity是如何使用这个两个东西来控制UI的布局

我们先来看看两个锚点重合时的情况,这种情况是我们最常用也是最容易理解的方式

总结下第1种情况的特点就是:子物体的大小不会随着父物体的大小变化而变化,但是位置会根据Pivot点到Anchor点的距离一致的原则发生对应的变化

当两个锚点(AnchorMin和AnchorMax)不重合时,两点就会确定一个矩形,这个矩形就是我们的锚框,如下图中的绿框就是我们的锚框区域

同理,如上图所示,Unity以锚框的右上角为原点(0,0),然后红框的Right和Top两个数确定红框的右上角的在坐标系中的位置,原地和红框的右上角的点确定一段距离(即上图的绿色箭头),不管黑框如何边框,这段距离都保持不变

在黑框大小和位置变化的时候,Unity会保证红框的左下角到锚框的左下角距离不变,同时红框的右上角到锚框的右上角距离不变,来确定红框的相对位置和大小,看下图来感受一下变化:

注意上图中红框左下角到黑框左下角的距离,以及红框右上角到黑框右上角的距离,他们都是不变的

快速设置Anchor,加快捷键能同时设置pivot或position

unity中的ui元素是有严格的父子关系的,子物体的位置是根据父物体的变化而变化的,而子物体和父物体联系的桥梁就是Anchor。之所以anchorMax和anchorMin的值是小数,是因为其表征的是该点所在位置占父物体大小的比例。

所谓的绝对布局,就是出现锚点的情况,此时的recttransform面板中的属性变成PosX,PosY,PosZ,Width,Height,这五个属性,首先说说Width和Height,在绝对布局的情况下无论分辨率是多少,父物体多大,该UI元素的大小是恒定的,如下图所示

所谓相对布局,就是出现锚框的情况。在这种情况下UI元素的四个角,距离四个对应的锚点的距离是不变的,在这种情况下RectTransform的属性又变为了Left,Top,Right,Bottom,PosZ,其中的PosZ表征的是该元素到父物体在Z轴上的偏移,利用这个值可以调整UI元素的显示顺序,不过我用的不多,这里不作太多讨论。剩下的四个值应该很好理解了,就是UI元素的每一条边距离父物体的每一条边的距离。

anchoredPosition根据名字的含义,我们大概可以猜出他是根据anchor锚点得出来个一个位置属性,他本身是一个点,如果在AnchorMin和AnchorMax是重合的情况下,anchoredPosition就是表示锚点到Pivot的位置,如下图所示:

但是如果AnchorMin和AnchorMax不重合的时候,anchoredPosition就比较复杂了,在这种情况下,Unity会根据Pivot、AnchorMin和AnchorMax计算出一个锚点,然后在通过Pivot和锚点来得出anchoredPosition的位置

offsetMin和offsetMax这两个属性比较好理解,其中offsetMin表示物体(本文中的红框)左下角相对AnchorMin的偏移,offsetMax表示物体右上角相对AnchorMax的偏移

sizeDelta就是offsetMax - offsetMin的值,即物体左下角到右上角的变量,如下图所示:

自学备用,如有问题欢迎及时指正,我会尽快改正。

(版本unity 201829f1)

本篇记录 Unity UGUI canvas 中的各项参数设置和效果,还是那句话自学备用,如有问题欢迎指正,我会尽快改正。

新建的Canvas拥有Rect Transform,Canvas,Canvas Scaler 以及 Graphic Raycaster 这几个组件。Rect Transform此时为灰色,在Scene视图中不能对Canvas进行 *** 作。Rect Transform 下一行英文“Some values driven by Canvas” ——Canvas驱动一些值。

此设置时,Canvas会填满整个屏幕,并将Canvas下面所有的UI元素置于屏幕的最上层,Canvas将一直覆盖场景中普通的3D GameObject。

启用pixelPerfect可以使元素看起来更清晰并防止模糊。勾选不启用抗锯齿(还在实验中,暂无截图)。

Canvas深度,数值越大,显示的优先级就越高,也就是数值大的Canvas会遮挡住数值小的Canvas。

此设置使Canvas渲染到指定的显示中。支持的辅助显示器(例如监视器)的最大数量为8。

最新几个版本中拥有的特性,提供给Shader使用的参数。此处不太了解。

启用pixelPerfect可以使元素看起来更清晰并防止模糊。勾选不启用抗锯齿(还在实验中,暂无截图)。

指定Canvas渲染在哪一个摄像机上

当Camera的Projection为Orthograhic时,此值得改变仅仅会改变Canvas的Pos Z;

当Camera的Projection为Perspective时,此值得不仅会改变Canvas的Pos Z,还会影响Scale。

当Plane Distance等于Camera的Clipping Planes的Near时 ,相当于Render Mode 是 Screen Space-Overlay 的效果,当Plane Distance等于Camera的Clipping Planes的Far时,Canvas在所有物体的后面。

Sorting Layer,可为UGUI设置画布深度,在下拉菜单中点击“Add Sorting Layer”按钮进入标签和层的设置界面,或者点击导航菜单->edit->Project Settings->Tags and Layers进入该页面。可以点击“+”添加Layer,或者点击“-”删除Layer。画布所使用的Sorting Layer越排在下面,显示的优先级也就越高。

在相同的Layer中区别显示层级关系的设定,相同的Layer中Order in Layer 越高,显示的优先级也就越高。

World Space即世界控件模式。在此模式下,Canvas被视为与场景中其他普通游戏对象性质相同的类似于一张面片(Plane)的游戏物体。在此模式下我们可以手动设置RectTransform数值,来改变Canvas在世界中的位置选择大小等。当所用UI为场景中的一部分时,我们可以使用这种模式。

此处在我使用时World Space模式下,Event Camera为空也可以执行按钮点击事件,摸索中~~~~~

不断学习中。整理出来忘记时看看,有错误的地方感谢指出。

现有的自适应方法,通常都是基于屏幕的分辨率。分辨率越高的设备上,UI显示的越小。这就造成了一些5寸左右的手机分辨率比ipad等平板设备还要高。UI在平板上显示太大。但是在高分辨率手机上显示太小。

以上脚本为基于屏幕物理尺寸自适应UI的一种方法。通过计算屏幕的DPI获取到屏幕的实际尺寸。然后根据一个标准的尺寸对UI的分辨率进行相对应的缩放。

可以改进的地方就是对于大屏幕或者小屏幕进行缩放的限制。避免类似ipad pro这类的设备上,UI有小的离谱。

配合这个脚本使用的同时。UI也需要用到锚点,进行初步的自适应,不然会造成UI的错乱。

效果图,素材是网上随便拉的

这是运行后的Hierarchy的界面,其中最下面的Item是放在摄像机不能拍到的位置,当做预设体,每个Item都有Toggle组件,在Grid上有Toggle Group 组件,并且将Itme上的Toggle组件中Group设置为Grid,这实现了点了一个之后,其他不会高亮。Grid上有组件 Grid Layout Group,该组件实现了当创建Item,并且将父物体设置为Grid后能够自动排版

这里我们需要写三个类,一个是自己捏造的数据类,放在Item上获取各种UI的类,还有能够创建Item并且能够对Item进行管理的类

public class ItemData//这个类存放的是数据

{

public int _starNum;//星星的数量(本来是想找星星的,现在就随便将就一下)

public string _icon;//这是名字

public string _itemName;//关卡的名字

public string _itemNum;//第几关

}

item上的类,用来获取item上的UI控件

public class Item : MonoBehaviour

{    

public Image _star1;    

public Image _star2;    

public Image _star3;    

public Image _icon;    

public Text _levelNum;    

public Text _levelName;    

void initializeItem()    

{        

_star1 = transformFind("StarGroup/star1")GetComponent<Image>();       

 _star2 = transformFind("StarGroup/star2")GetComponent<Image>();        

_star3 = transformFind("StarGroup/star3")GetComponent<Image>();

 _icon = transformFind("Icon")GetComponent<Image>();        

_levelName = transformFind("Levelname/name")GetComponent<Text>();        

_levelNum = transformFind("Levelname/Lv")GetComponent<Text>();

}

void Awake()

{

initializeItem();

}

}

这是个管理Item创建的类

public class MainMgr : MonoBehaviour 

{    

GameObject item;    

Transform Parent;    //这里需要得到Gird的Transform

List<ItemData> dataGroup = new List<ItemData>();   

void Awake()    

{        

CreateData();        

item = transformFind("Item")gameObject;        //获得一开始放在摄像机外的游戏对象,当做预设体

Parent = transformFind("Grid");    //保存Gird的Transform

}    

void CreateData()    //创建自己捏造的数据

{       

 dataGroupClear();//确保这个List没有其他数据        

ItemData itemdata = new ItemData();        

itemdata_icon = "1 (5)";       

itemdata_itemName = "小树林";        

itemdata_itemNum = "第一关";        

itemdata_starNum = 3;        

dataGroupAdd(itemdata);        

ItemData itemdata1 = new ItemData();        

itemdata1_icon = "1 (7)";        

itemdata1_itemName = "沼泽";       

 itemdata1_itemNum = "第二关";        

itemdata1_starNum = 1;        

dataGroupAdd(itemdata1);        

ItemData itemdata2 = new ItemData();        

itemdata2_icon = "1 (15)";        

itemdata2_itemName = "山海关";        

itemdata2_itemNum = "第三关";       

itemdata2_starNum = 1;        

dataGroupAdd(itemdata2);        

ItemData itemdata3 = new ItemData();        

itemdata3_icon = "1 (12)";        

itemdata3_itemName = "墓地";        

itemdata3_itemNum = "第四关";        

itemdata3_starNum = 2;        

dataGroupAdd(itemdata3);       

 ItemData itemdata4 = new ItemData();        

itemdata4_icon = "1 (32)";        

itemdata4_itemName = "神殿";       

 itemdata4_itemNum = "第五关";       

 itemdata4_starNum = 3;        

dataGroupAdd(itemdata4);        

ItemData itemdata5 = new ItemData();        

itemdata5_icon = "1 (25)";        

itemdata5_itemName = "天庭";        

itemdata5_itemNum = "第六关";        

itemdata5_starNum = 2;        

dataGroupAdd(itemdata5);        

ItemData itemdata6 = new ItemData();        

itemdata6_icon = "1 (30)";        

itemdata6_itemName = "心魔";        

itemdata6_itemNum = "第七关";        

itemdata6_starNum = 3;        

dataGroupAdd(itemdata6);   

 }    

GameObject tempItem; //创建临时的游戏对象   

void CreateTempItem()    //创建Item

{        

if (dataGroup != null)       //当这个List不为空时

{            

for (int i = 0; i < dataGroupCount; i++)            //循环创建Item

{                

tempItem = Instantiate(item) as GameObject;          //创建Item并且获取到这个游戏对象     

 tempItemtransformlocalPosition = Vector3zero;                //将其位置,缩放大小,旋转角度初始化

tempItemtransformlocalRotation = new Quaternion();                

tempItemtransformlocalScale = Vector3one;                

tempItemtransformSetParent(Parent);                //设置其父物体为Grid

Item itemSprite = tempItemAddComponent();  //为每一个创建的Item添加脚本

itemSprite_levelNametext = dataGroup[i]_itemName;//获取每一个关卡的名字获取,一下类似

itemSprite_levelNumtext = dataGroup[i]_itemNum;

string path = stringFormat("Icon/{0}", dataGroup[i]_icon);//字符串拼接

itemSprite_iconsprite = ResourcesLoad(path, typeof(Sprite)) as Sprite;

ShowStar(dataGroup[i]_starNum, itemSprite);//调用这个方法获得星星的显示

}

}

}

void ShowStar(int num,Item tempitem)//这个方法是用来显示星星

{

if (num == 1)

{

tempitem_star1gameObjectSetActive(true);

tempitem_star2gameObjectSetActive(false);

tempitem_star3gameObjectSetActive(false);

}

if (num == 2)

{

tempitem_star1gameObjectSetActive(true);

tempitem_star2gameObjectSetActive(true);

tempitem_star3gameObjectSetActive(false);

}

if (num == 3)

{

tempitem_star1gameObjectSetActive(true);

tempitem_star2gameObjectSetActive(true);

tempitem_star3gameObjectSetActive(true);

}

}

void Start () {

CreateTempItem();

}

}

以上就是简单的游戏关卡的选择界面的实现,如果有错误,或者更好的方法,望指正,万分感谢!

因项目的需求,在制作中需要让UGUI中的组件,追随鼠标的运动轨迹。由于个人在以前使用中对于UGUI的坐标系了解不深,在使用中产生了一些问题,在此对UGUI的坐标系做一个简单的记录,以备后面查询。

Unity3D 采用InputmousePosition来获取当前鼠标的位置,获取的位置是相对于屏幕坐标系的,而UGUI使用的坐标系和屏幕坐标系不是同一个坐标系,

在UGUI中组件使用的坐标都是2D在Rect中的一个相对坐标,所以在实际使用中需要进行转换。

<pre>

public class test : MonoBehaviour

{

public RectTransform myRectTransform; // 目标组件

public Canvas myCanvas; // 当前画布

// Update is called once per frame

void Update ()

{

Vector2 vT = Vector2zero;

// 通过此函数,将鼠标坐标,从屏幕坐标,转换到UGUI坐标

RectTransformUtilityScreenPointToLocalPointInRectangle(myCanvastransform as RectTransform, InputmousePosition, myCanvasworldCamera, out vT);

myRectTransformlocalPosition = vT;

}

}

</pre>

#######附带一说,在Unity3D中可以使用函数ScreenshowCursor(老版本)、UnityEngineCursorvisible来显示和隐藏鼠标

以上就是关于Unity UGUI系列四 Pivot Anchor全部的内容,包括:Unity UGUI系列四 Pivot Anchor、Unity UGUI Canvas简谈、Unity3d UGUI基于屏幕尺寸的自适应等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/web/9435888.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-04-28
下一篇 2023-04-28

发表评论

登录后才能评论

评论列表(0条)

保存