いろいろガンガンいこうぜ。体も大事に

普段はJavaでAndroidアプリ開発しているプログラマーのブログです。

GetComponentメソッドについて

GetComponentメソッドについて調べたり,まとめてみたりしました。 (Unity4.3.2f1で試しています。)

この記事はUnity4.3.2f1での記事です。ドキュメント化されていない仕様・挙動について他のバージョン・最新のバージョンでのUnityの動作を保証するものではありません。

3個のオーバーロード

Componentクラスのインスタンスメソッド,GetComponent。

GetComponentのスクリプトリファレンス

このGetComponentメソッドは3個のオーバーロードを持っています。

Component GetComponent(Type type);
T GetComponent<T>();
Component GetComponent(string type);

スクリプトリファレンスによるとパフォーマンスの観点から見て,文字列型を引数にとるオーバーロードより他の物を使った方がいいようです。

またGeneric Functionsにはジェネリクスを用いると,キャストをする手間とタイプする文字数が減るよねという記述があります。

基本的には,ジェネリクス版を使えばいいと思います。が,しかしジェネリクスオーバーロードではできず,Type型を引数にとるオーバーロードではできるものがありました。

型パラメータにスーパークラスを与えてGetComponent

MonoBehaviourクラスを継承したBaseクラス。そのBaseクラスを継承したDerived0クラスを用意します。

using UnityEngine;

public class Base : MonoBehaviour { }
public class Derived0 : Base { }

そして,Baseクラスを型パラメータに指定してGetComponentします。 そのGetComponentしたコンポーネントのクラス名を表示するクラスを作ります。

using UnityEngine;

public class GetComponentSample : MonoBehaviour
{
    void Start ()
    {
        Base component = GetComponent<Base> ();
        Debug.Log (component.GetType ().Name); 
    }
}

次のようにシーン上のGameObjectにDerived0とGetComponentSampleコンポーネントをつけます。

画像1

これを実行すると,Derived0とデバックログが出力されます。 サブクラスのコンポーネントが付与されているGameObjectに対して,スーパークラスの型を指定して,GetCompoenentでコンポーネントを取得することができました。

次のように,スーパークラスを抽象クラスにすることも可能なようです。

using UnityEngine;

public abstract class Base : MonoBehaviour { }

また,次のようにDerive0とは違うサブクラスを作って,

public class Derived1 : Base { }

それを次のようにGetComponentSampleと一緒にGameObjectに付与して,

画像2

実行した場合,こちらはDerived1と出力されました。

型パラメータにスーパークラスを指定したGetComponentメソッドの呼び出しで,サブクラスのコンポーネントを取得することができることがわかりました。

複数のコンポーネントが付与されてる場合のGetComponent

using UnityEngine;

public class StringContainer : MonoBehaviour
{
    public string value;
}
using UnityEngine;

public class GetComponentSample : MonoBehaviour
{
    void Start ()
    {
        StringContainer component = GetComponent<StringContainer> ();
        Debug.Log (component.value);
    }
}

次の画像のように一つのGameObjectにStringContainerクラスを3個,GetComponentSampleを1個付与します。

画像3

これを実行すると, デバックログにはvalue0と表示されました。 インスペクターのMoveUpなどを用いて,コンポーネントの順番を変えます。

画像4

上の画像のような状態で実行するとデバックログにはvalue1と表示されました。 また順番を変えて以下のようにします。

画像5

この状態で実行するとデバックログにはvalue2と表示されました。

同じクラスのコンポーネントが複数付与されている場合,インスペクターにおける一番上のインスタンス(という言い方でいいのでしょうか?)が取得できるようです。

前の節で作ったBaseクラス,Derived0クラスそしてDerived1クラスを使ってみます。ふたたびBaseクラスでGetComponentして,クラス名を表示します。

using UnityEngine;

public class GetComponentSample : MonoBehaviour
{
    void Start ()
    {
        Base component = GetComponent<Base> ();
        Debug.Log (component.GetType ().Name); 
    }
}

画像6

上の画像のように, GetComponentSampleクラス, Derived0クラス, Derived1クラス の順番でコンポーネントを付与します。

これを実行するとデバックログに,Derived0と表示されました。

順番を変えます。

画像7

上の画像の用に GetComponentSampleクラス, Derived1クラス, Derived0クラス の順番でコンポーネントを付与したら

これを実行するとデバックログに,Derived1と表示されました。

GetComponentでコンポーネントを取得する際,もし指定した型パラメータのクラスで取得出来るコンポーネントが複数ある場合は,インスペクター上で一番上の物が取得できるようです。

GetComponentsについて

複数のコンポーネントを取得するGetComponentsというメソッドがあります。

取得しようとするコンポーネントがGameObjectについていない場合,GetComponentではnullが帰ってきますが,GetComponentsでは空の配列が帰ってくるようです。

前節のStringContainerクラスとGetComponentsメソッドを用いたサンプルを作りました。

using UnityEngine;

public class GetComponentSample : MonoBehaviour
{
    void Start ()
    {
        StringContainer[] stringContainers = GetComponents<StringContainer> ();
        foreach (var stringContainer in stringContainers) {
            Debug.Log (stringContainer.value);
        }
    }
}

画像8

上の画像ようにGetComponentSampleを1個とStringContainerクラスのコンポーネントを複数付けて文字列valueを画像の用に設定し,実行すると

value0
value1
value2
value3

という順番で表示されました。

順番を変えます。

画像9

上の画像のように,順番を変えると実行結果は

value3
value2
value1
value0

となりました。

GetComponentsで取得した配列の要素の順番は,インスペクターで表示される順番と同じ順番のようです。

インタフェースでGetComponent


2019/03/17(日) 追記ここから

Unity 5.0からインターフェース型Tでも T GetComponent<T>()が利用できるようになりました。

Unity 4系では、T GetComponent<T>()TはComponent型の型引数制約が設定されていたため、インターフェースでのT GetComponent<T>()はできませんでした。

もとの記事では、「インターフェースではできない」という旨の記述がありましたがUnity5からはできるので、その部分を削除しました。

追記ここまで


まとめとか

よく使うGetComponentメソッド。(あとGetComponentsメソッド) 型パラメータにスーパークラスや抽象クラスを指定するのは,いくつか使い方がありそうですね。インターフェースはどうでしょう。もしかした。

本当は全コンポーネントや,一つのGameObjectについている,全ての自作コンポーネントを取得する方法を調べていたら,細かいところが気になって書いたポスト。 次は,GetComponents<Component>GetComponents<MonoBehavoiour>コンポーネント全取得します。

関連リンク

http://docs.unity3d.com/Documentation/ScriptReference/Component.GetComponent.html

http://docs.unity3d.com/Documentation/Manual/GenericFunctions.html

  • 暗黙の参照変換

http://msdn.microsoft.com/ja-jp/library/aa691284(v=vs.71).aspx

  • 型パラメータ制約

http://msdn.microsoft.com/ja-jp/library/d5x73970(v=vs.90).aspx