GetComponentメソッド
UnityEngineには、GetComponentというメソッドがあります。
主にGameObjectにアタッチされているコンポーネントを取得するのに使用します。
GameObjectクラス、及びComponentクラス内に実装されているので、
MonoBehaviourを継承したコンポーネントクラス内からも呼ぶことが出来ます。
基本的な使い方
以下の例では、スクリプトがアタッチされているのと同じGameObjectにアタッチされているコンポーネントを取得できます。
private void Awake()
{
Rigidbody body = GetComponent<Rigidbody>();
}
特定のGameObject,Transformを指定してコンポーネントを取得する事も出来ます。
当たり判定用のイベント内ではこのような使い方をすることが多いのではないでしょうか。
private void OnCollisionEnter(Collision other)
{
var collider1 = other.gameObject.GetComponent<Collider>();
var collider2 = other.transform.GetComponent<Collider>();
}
GetComponentという名前ですが、インターフェイスを取得することも出来ます。
IVisibleという適当なインターフェイスを用意しましたが、
以下の例では、GameObjectにアタッチされているコンポーネントのうちIVisibleというインターフェースを継承しているコンポーネントの
インターフェイスを取得します。
public interface IVisible
{
bool IsVisible { get; }
}
private IVisible GetVisible()
{
return GetComponent<IVisible>();
}
関連するメソッド
GetComponentに関連するメソッドがいくつかあります。
これらを使うと、コンポーネントをまとめて取得したり、子のGameObjectから取得できたりします。
GetComponents
GameObjectにアタッチされている同種のコンポーネントをまとめて取得することが出来ます。
var components = GetComponents<Collider>();
GetComponentInChildren
GameObject自身とヒエラルキー上の全ての子GameObjectにアタッチされているコンポーネントを取得することが出来ます。
引数にtrueを渡すことで、非アクティブなGameObjectも対象になります。
falseを渡すか省略した場合、非アクティブなGameObjectからはコンポーネントを取得できません。
var component = GetComponentInChildren<Collider>(true);
GetComponentsInChildren
GameObject自身とヒエラルキー上の全ての子GameObjectにアタッチされているコンポーネントをまとめて取得することが出来ます。
引数にtrueを渡すことで、非アクティブなGameObjectも対象になります。
falseを渡すか省略した場合、非アクティブなGameObjectからはコンポーネントを取得できません。
var components = GetComponentsInChildren<Collider>(true);
GetComponentInParent
直接の親GameObjectにアタッチされているコンポーネントを取得します。
var component = GetComponentInParent<Collider>();
GetComponentsInParent
直接の親GameObjectにアタッチされているコンポーネントをまとめて取得します。
引数で非アクティブなオブジェクトも検索対象にするか選べます。
var components = GetComponentsInParent<Collider>(true);
TryGetComponent
TryGetComponentは、Unity2019.2から追加されたメソッドです。
コンポーネントが存在するかをチェックし、存在する場合はコンポーネントを返します。
if (TryGetComponent(out Collider collider))
{
// Colliderを取得できた
}
コンポーネントの存在をチェックするコードが読みやすくなり、より安全で効率的にコードを書くことが出来ます。
また、TryGetComponentはビルド後のアプリ上ではGC Allocが発生しません。
気をつける点
GetComponent系メソッドは便利ですが、パフォーマンスの面で気をつける必要があります。
開発の序盤は、GetComponentsで問題なかったとします。
開発が進むにつれGameObjectが沢山の子オブジェクトとコンポーネントを持つようになっていた場合、
検索する対象が増えるため負荷も増えていきます。
Updateメソッドなど頻繁に呼ばれるタイミングで使用するのは避けた方がいいでしょう。
必要であれば、Awake,Startメソッドのタイミングで事前にキャッシュしておくのがよいでしょう。
代替方法
一番いいのは、事前にSerializeFieldに設定しておくことです。
// 1.必要な時にGetComponentで取得する
public class Stage : MonoBehaviour
{
private void Update()
{
var player = GetComponent<Player>();
}
}
// 2.事前にGetComponentnで取得する
public class Stage : MonoBehaviour
{
private Player _player;
private void Start()
{
_player = GetComponent<Player>();
}
}
// 3.事前にSerializeFieldに設定しておく
public class Stage : MonoBehaviour
{
[SerializeField] private Player _player;
}
事前に設定しておけば、取得するためのコードを書く必要もなくなり、
子オブジェクトやコンポーネントが増えてもパフォーマンスに影響も出ません。
まとめ
今回はGetComponent関係について説明しました。
GetComponentはUnityでゲーム開発を行う上で重要なメソッドですが、
パフォーマンスに影響を与える可能性もあるため、その使い方には注意が必要です。
特に、頻繁に呼び出されるメソッド内での使用や、大量の子オブジェクトやコンポーネントを持つGameObjectでの使用は避けた方が良いでしょう。
また、可能であればAwakeやStartメソッドでコンポーネントをキャッシュするか、SerializeFieldを利用して事前に設定しておくとベストです。
衝突時のイベントなどどうしても使用する場合には、TryGetComponentを使うことも考えてみてください。