基础知识:
Transform作为Unity中游戏对象最为重要的组件,“位置”作为Transfrom组件的一个属性,具有同等重要的地位。
Transform组件下有两个“位置”属性:
position:指的是游戏对象中心点在世界空间的位置(世界空间就是Unity最大的空间,可以创建一个无任何父节点的空对象,其position,rotation分量都是0,scale分量都是1,那么可以认为世界空间就是以此物体中心点为原点,物体的朝向为z轴,右方向为x轴,上方向为y轴,即物体的transform.forward为z轴,transform.right为x轴,transform.up为y轴,如图中的SuperParent物体)。
SuperParent1.jpg
localPosition:指的是游戏对象中心点在父类空间的位置(属性面板上显示的值就是这个值)。
父类空间的构建与其position,rotation,scale有关,但此处只讨论position,因此可以认为父类物体不旋转,没有缩放的情况。那么此时父类空间是以父类中心点为原点,x,y,z与世界空间x,y,z轴同方向。
如果游戏对象没有父类,那么此物体的父类空间就是世界空间,此时position和localPosition值是相同的。可以想象为,其父类就是文章上面的SuperParent物体。
UGUI下所有的UI空间都具有RectTransform组件,此组件继承自Transform组件,其内部的position和localPosition属性也继承自Transform。他多出来的位置属性是:
anchoredPosition3D:指的是物体中心点Pivot相对于锚点Anchor的位置(UI属性面板上显示的就是这个值,即PosX,PosY,PosZ)。
注意:
1、 这里指的是锚点,尽管锚点是附加在父类上的,但其并不是父类空间,父类空间指的是以其中心点为原点,而此处指的是以锚点为原点。
2、 RectTransform提供了我们足够的自由去更改UI的锚点位置和中心点的位置。但是万变不离其宗:anchoredPosition3D核心概念没变:中心点相对锚点的位置。
3、 anchoredPosition是anchoredPosition3D属性去除了z轴之后的值。
扩展知识:
尽管上述概念都是大家耳熟能详的东西,有关的博文一搜一大堆,我为什么要再总结一篇大家都知道的东西呢?因为看似简单的东西,可以做出复杂的系统,看似复杂的东西,都是由简单的东西堆砌出来的。
重点来了:位置脱离了空间系统毫无意义。人尽皆知啊。接下来请牢记:位置计算一定要统一空间。
Unity中,游戏物体除了有本地位置,世界空间位置,还有相对摄像机的位置(视角空间位置),屏幕空间位置。其中的转换详情计算机图形学,以后我也会总结有关图形学的知识。
实战:
最后用一个例子介绍一下这些位置的用途。
王者荣耀英雄展示界面。一边为英雄模型,一边为UI显示英雄技能等信息,是怎么样做到的模型跟正好显示在了规定的地方。如图:
Hero.jpg
两个接口(Camera组件下):
public Vector3 WorldToScreenPoint(Vector3 position);
//输入物体世界空间坐标得到物体当前摄像机下屏幕空间坐标位置
public Vector3 ScreenToWorldPoint(Vector3 position);
//输入物体当前摄像机下屏幕空间坐标得到物体世界空间坐标位置
注意:
1、屏幕空间坐标依赖于摄像机。同一物体,在不同摄像机下,其得到的屏幕坐标是不同的。不懂的话,可以了解一下图形学坐标转换。
2、屏幕空间坐标是三维的。其x,y轴是指显示在屏幕上的位置,z轴具有特殊意义——物体的深度值(与物体距离摄像机的远近有关)。
Camera组件下有很对关于空间位置的计算。有兴趣的话,可以研究研究。
首先我们需要两个摄像机:一个UI摄像机显示UI,一个模型摄像机显示模型。
具体思路:由UI位置计算其屏幕坐标位置,再由屏幕坐标位置计算模型世界空间位置。
场景:一个button,button下有一个位置标识,通过我点击button,会在该位置标识上生成一个小球(这个button同时充当了模型展台,小球就是宫本。太low了,哈哈),game场景如下:
Scene.png
代码如下:
public GameObject prefab; //小球预制件
public Camera uiCamera; //UI摄像机
public Camera modelCamera; //模型摄像机
public GameObject posTag; //需要把模型放置的位置
public int z = 5; //修改屏幕坐标的Z轴
public void ClickButton()
{
//初始化物体
GameObject go = GameObject.Instantiate(prefab);
Vector3 showPos = posTag.transform.position;
//获取展示位置的屏幕空间坐标
Vector3 screenPos = uiCamera.WorldToScreenPoint(showPos);
//设置屏幕坐标的z轴。z轴代表物体的深度值,与距离摄像机的远近有关。
//可以调一下大小感受一下
screenPos.z = z;
//获取模型摄像机下得到同一屏幕空间坐标的世界空间坐标
Vector3 modelPos = modelCamera.ScreenToWorldPoint(screenPos);
go.transform.position = modelPos;
}
效果展示:
position.gif
位置不对啊?其实是因为所有的坐标都是以中心点为基础的。小球的中心点在圆心,所以小球的中心点是与标志物重合的。在游戏中,美术提交的模型中心点基本都会设置在人物脚上,所以就不会出现这个情况。
小结:
知识点:位置概念不能脱离空间。位置计算一定要统一空间。
网友评论