Unity全面入门笔记13-Transform

Transform

GameObject和Transform

  • 获取Transform

Transform是每个GameObject都具有的属性,Transform是GameObject的一个特殊的Component。尝试删除Transform时会发现,Unity并没有提供可以删除Transform组件的选项,也就是说GameObject必须具有Transform组件。同样的,也没有任何方法添加Transform组件,也就是说GameObject只能具有一个Transform组件。

一个GameObject只对应一个Transform,一个Transform也只对应一个GameObject。在脚本中,我们可以直接通过gameObject获得对应Transform组件,也可以通过transform获得对应的GameObject,同时,用GetComponent方法也可以获得Transform组件:

public GameObject MonoBehaviour.gameObject{get;}
public Transform MonoBehaviour.transform{get;}
public Tranform GameObject.tranform{get;}
public GameObject Tranform.gameObject{get;}
gameObjcet.tranform == gameObject.GetComponent<Transform>();
tranform == gameObject.tranform.gameObject.GetComponent<Tranform>();
  • 修改位置

在Inspector中,每个GameObject的第一个组件都是Transform。Transform暴露出来的属性包括Position、Rotation和Scale,顾名思义,它们就是物体的位置、旋转、缩放信息。在Scene中移动、旋转、缩放物体,可以观察到Inspector中的Transform改变,而在Inspector中改变这三个属性,也可以在Scene和Game面板中看到修改的效果。

默认情况下,position、rotation均为零向量,scale为(1,1,1)。在Inspector面板中对Transform使用Reset即可使三个属性重置为默认值。注意,使本地座标归零的结果是使该物体与父物体座标系重合。

复习本地座标系与世界座标系:

本地座标系指物体的父节点的模型座标空间,如果物体没有父节点,则本地座标系等于世界座标空间。

本地座标是在本地座标系中的座标,而世界空间座标是在世界座标系中的座标。

Transform和座标信息

  • 移动
transform.position = new Vector3(1,2,3);
transform.localPosition = new Vector3(1,2,3);
transform.position += new Vector3(1,0,0);
transform.localPosition += new Vector3(-1,0,0);

通过position可以访问物体的世界座标,通过localPosition可以访问物体的本地座标。

由于Vector3重载了加减运算,故可以使用“+=”来修改position。

除了直接对position修改外,还可以调用Transform的函数:

public void Transform.Translate(float x, float y, float z, Space relativeTo = Space.Self);
public void Transform.Translate(Vector3 translation, Space relativeTo = Space.Self);

Space是一个枚举类型,具有两个枚举值:Space.Self和Space.World。前者使移动作用于本地座标,后者使移动作用于世界座标。

由于在Vector3类中,x、y、z属性是只读的,有时会造成麻烦,我们可以自己扩展方法,如下:

public static class Extensions
{
    public static void SetPositionX(this Transform t, float newX)
    {
        t.position = new Vector3(newX, t.position.y, t.position.z);
    }
}

扩展已有类时,我们需要一个静态类中的静态方法,这个方法的第一个参数增加this关键字,第一个参数的类型就是我们想要扩展的类型,这样我们就可以通过Transform对象直接调用这个方法了:

transform.SetPositionX(1);
  • 旋转
public Quaternion Transform.rotation;
public Quaternion Transform.localRotation;

通过Transform的属性获取轴:

public vector3 Transform.up{get; private set;}
public vector3 Transform.forward{get; private set;}
public vector3 Transform.right{get; private set;}

通过Transform的方法旋转物体:

public void Transform.Rotate(Vector3 eulers, Space relativeTo = Space.Self);
public void Transform.Rotate(float x, float y, float z, Space relativeTo = Space.Self);
public void Transform.Rotate(Vector3 axis, float angle, Space relativeTo = Space.Self);
public void Transform.RotateAround(Vector3 point, Vector3 axis, float angle);
public void Transform.LookAt(Vector3 worldPosition, Vector3 worldUp = Vector3.up);
public void Transform.LookAt(Transform target, Vector3 worldUp = Vector3.up);

Rotate函数具有两种完全不一致的效果,很容易使人产生困惑。在前两种重载中,物品以当前方向为基准重新进行欧拉变换,即沿z轴->y轴->x轴的顺序依次旋转指定角度,得到新的方向。而后一种重载中,物品绕自身的axis方向的轴,遵循左手螺旋定则的旋转angle角度。

RotateAround函数中,物体绕目标座标在axis方向的轴旋转angle度,旋转过程中座标和自身方向都会改变。

LookAt函数可以使物体的正面朝向某个点或Transform,所谓正面即z轴的正方向。在不使用第二个参数的情况下,物体只绕y轴旋转,而在使用第二个参数的情况下,物体的y轴正方向会指向第二个参数的方向。

Unity中没有使物体朝向某个方向的函数,但这个方法在移动时又十分常用,我们可以扩展一个LookTo方法来快捷的使用这个功能:

public static class Extensions
{
    public static void LookTo(this Transform t, Vector3 direction, Vector3 worldUp = Vector3.up)
    {
        t.LookAt(t.position + direction,worldUp);
    }
}

  • 缩放
public vector3 Transform.localScale;
public vector3 Transform.lossyScale{get; private set;}

注意,世界座标的大小是只读的。

推荐尽量少使用改变缩放的功能:一些缩放可以改用动画系统实现,还有更多情况下,模型或图片的大小应该由美术确定好后直接导入,GameObject的Scale应该尽量都保持(1,1,1)。

Transform和树型结构

让相关的GameObject尽量按照树型结构组织,可以有效的提高搜索物体的效率,也减少不必要的内存损耗。

  • 父节点
public Transform Transform.parent{get; private set;}
public Transform Transform.root{get; private set;}
public bool Transform.IsChildOf(Transform parent);
public void SetParent(Transform parent, bool worldPositionStays = true); 

注:当没有父节点时parent返回null,在SetParent中输入参数null也可以让物体不再有父节点,在IsChildOf中输入参数null可以判断物体是否没有父节点。

root代表最终根节点,可以返回自己。

SetParent函数的第二个参数为false时,物体会改变在世界座标系中的位置,在新的座标系中保持和在原本座标系中一致的本地座标,即和新父物体的相对位置等于和旧父物体的相对位置。

  • 子结点
public Transform Transform.Find(string n); 
public Transform Transform.GetChild(int index); 
public void Transform.DetachChildren(); 

使用Find可以根据物体名称搜索此节点派生出的所有后继节点,是GameObject.Find的范围缩小版本。

GetChild是速度最快的查找子物体的方法,所以让Prefabs或者GameObject以一个固定的顺序排列是一个很好的习惯。

DetachChildren可以一次性断开对所有子物体的连接,并使子物体移动到同一层级,即如果本物体有父物体,断开连接后子物体会成为原本父物体的子物体,成为本物体的兄弟节点。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章