C#
Unity

gameObject.GetComponent<Transform>() と transform の違い(または Unity における省略記法について)

More than 1 year has passed since last update.

疑問

transform を取得するために以下のような様々な書き方ができるが、これらの違いは何なのだろうか?

  1. this.gameObject.GetComponent<Transform>()
  2. gameObject.GetComponent<Transform>()
  3. GetComponent<Transform>()
  4. transform

結論

  • 得られるオブジェクトはどれも同じ(当然)
  • スピードが違う
    • 4 >> 3 > 2 = 1

routing.png

前提:Unity におけるクラスの継承関係

  • Object > Component > Behaviour > MonoBehaviour
  • MonoBehaviour クラスは Component クラスを継承している

(1) GetComponent<>() のありか

  • GetComponent<>() は GameObject クラスで 定義されている
  • Component クラスは、自身の属する GameObject への参照をメンバーとして 持っている
  • つまり、それを継承した MonoBehaviour を継承したクラスでは、以下のように Transform を取得可能
1つ目の記法
this.gameObject.GetComponent<Transform>()

(2) this は省略可能

  • C# の仕様で、自身に属するメンバーを参照する場合 this は省略できる
2つ目の記法
gameObject.GetComponent<Transform>()

(3) もうひとつの GetComponent<>()

  • 実は GetComponent<>() は Component クラスにも 定義されている(単純に便利さのため)
  • つまり、それを継承した MonoBehaviour を継承したクラスでは、以下のように Transform を取得可能
    • gameObject を経由しなくて済む分、こちらの方が高速なもよう
3つ目の記法
GetComponent<Transform>()

(4) transform は特別

4つ目の記法
transform

補足:ほかのコンポーネントは「専用の内部関数」で取得できないの?

  • できない
  • Component クラスは tranform 以外にも様々なコンポーネントへのショートカットを持っている
    • camera
    • rigidbody
    • ...
  • しかしこれらは 内部で GetComponent<>() を呼び出している にすぎない
    • それどころか transform 以外のショートカットは最近のバージョンで非推奨になった
  • Transform は特によく使うコンポーネントなので、特別に高速なアクセス手段が用意されたのではないか?

検証

  • 以下のスクリプトを適当なオブジェクトにアタッチしてシーンを実行すれば、速度が検証できる
検証用スクリプト
    using UnityEngine;
    using System.Diagnostics;

    public class NewBehaviourScript : MonoBehaviour {

        // Use this for initialization
        void Start () {
            System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
            sw.Start();

            for (int i = 0; i < 10000000; ++i)
            {
                Transform t = this.gameObject.GetComponent<Transform>(); // => 約 0.73 秒
                // Transform t = gameObject.GetComponent<Transform>();   // => 約 0.73 秒
                // Transform t = GetComponent<Transform>();              // => 約 0.53 秒
                // Transform t = transform;                              // => 約 0.24 秒
            }

            sw.Stop();
            UnityEngine.Debug.Log(sw.Elapsed);
        }
    }

補足: 最速はキャッシュ

  • 一度取得した Transform をローカル変数に入れて使い回せるなら、それがもちろん最速

参考