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可以一次性斷開對所有子物體的連接,並使子物體移動到同一層級,即如果本物體有父物體,斷開連接後子物體會成爲原本父物體的子物體,成爲本物體的兄弟節點。

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