9.

UnityのGetComponent取得とキャッシュ|TryGetComponent・RequireComponent

編集
この記事の要点
  • GetComponent<Rigidbody>() が基本。文字列指定の GetComponent("Rigidbody")リフレクションで遅い
  • Awake / Start で取得してキャッシュ。Update での GetComponent は禁忌
  • [RequireComponent(typeof(Rigidbody))] でコンポーネント自動付与&削除防止
  • TryGetComponent(2019.2+)は未存在でも GC ゴミが出ない
  • コンポーネント追加 AddComponent<T>()/削除 Destroy(component)GameObject ではなく Component を Destroy

GetComponent の基本

using UnityEngine;

public class Sample : MonoBehaviour
{
    void Start()
    {
        // ジェネリック版(推奨)
        Rigidbody rb1 = GetComponent<Rigidbody>();

        // 型引数なし(古い書き方、Cast 必要)
        Rigidbody rb2 = (Rigidbody)GetComponent(typeof(Rigidbody));

        // 文字列版(遅い、補完効かない、リフレクション)
        Rigidbody rb3 = (Rigidbody)GetComponent("Rigidbody");

        // 取得できなかったときは null
        if (rb1 == null) Debug.LogWarning("Rigidbody missing");
    }
}

3 つの書き方の中で、ジェネリック版が最速かつ最も保守的です。文字列版はリフレクションを使うため数倍遅く、リネーム時にコンパイラがミスを検知できません。

TryGetComponent(GC 回避)

Unity 2019.2 以降では TryGetComponent が利用できます。コンポーネント未存在時に null を返す代わりに false を返し、UnityEngine.Object との比較で発生する GC ゴミを回避します。

// ❌ 旧来: null 比較が偽 null 経由で GC を発生させる
var rb = GetComponent<Rigidbody>();
if (rb != null) rb.AddForce(Vector3.up);

// ✅ 推奨: TryGetComponent
if (TryGetComponent(out Rigidbody rb)) {
    rb.AddForce(Vector3.up);
}

キャッシュは必須

GetComponent毎呼び出しで内部リスト走査します。Update で呼ぶと毎フレームのコストが積み重なります。Awake / Start で取得して private フィールドに保持してください。

public class Mover : MonoBehaviour
{
    private Rigidbody _rb;
    private Animator  _anim;

    void Awake()
    {
        _rb = GetComponent<Rigidbody>();
        _anim = GetComponent<Animator>();
    }

    void FixedUpdate()
    {
        _rb.AddForce(transform.forward * 10f);
        _anim.SetFloat("Speed", _rb.velocity.magnitude);
    }
}

RequireComponent 属性

「このスクリプトには必ず Rigidbody が必要」と表現したい場合、[RequireComponent] 属性を使います。

  • アタッチ時に未存在ならば自動追加
  • 該当コンポーネントを Inspector から削除しようとすると警告が出る
  • 依存関係を宣言的に表現でき、ドキュメントとしても機能
[RequireComponent(typeof(Rigidbody))]
[RequireComponent(typeof(Collider))]
public class Bullet : MonoBehaviour
{
    private Rigidbody _rb;
    void Awake() { _rb = GetComponent<Rigidbody>(); }
    // Rigidbody が必ず居るので null チェック不要
}

子・親からの取得

// 自身+子孫
var aud = GetComponentInChildren<AudioSource>();

// 自身+祖先
var canvas = GetComponentInParent<Canvas>();

// 配列で複数取得
var rends = GetComponentsInChildren<Renderer>();

// 非アクティブも含む
var hiddenAud = GetComponentInChildren<AudioSource>(includeInactive: true);

コンポーネント追加と削除

// 追加
var rb = gameObject.AddComponent<Rigidbody>();
rb.mass = 2f;

// 削除(GameObject ではなく Component を渡す!)
Destroy(rb);

// すぐ削除(Editor 用)
DestroyImmediate(rb);

// 同型を複数つけられないコンポーネント(Rigidbody 等)に重複 AddComponent するとエラー
// 重複は AudioSource など限られた型のみ可

パフォーマンス指針

呼び方速度使い所
キャッシュ済フィールド★★★★★Update / FixedUpdate
TryGetComponent<T>★★★★初回 / 条件分岐
GetComponent<T>★★★Awake / Start
GetComponentInChildren★★必要時のみ
GetComponent("StringName")使わない

ECS(DOTS)との比較

Unity DOTS の ECS(Entity Component System)では、コンポーネントは IComponentData 構造体としてエンティティに付与されます。MonoBehaviour とは設計思想が大きく異なり、キャッシュフレンドリで CPU SIMD 最適化がしやすい代わりに、API がまったく別物になります。大量オブジェクト(数千〜数万)を扱うときに検討してください。

// ECS の例(IJobEntity)
[BurstCompile]
partial struct MoveJob : IJobEntity
{
    public float dt;
    void Execute(ref LocalTransform t, in MoveSpeed s)
    {
        t.Position += new float3(0, 0, s.Value * dt);
    }
}

よくあるトラブル

症状原因対処
NullReferenceExceptionGetComponent が null を返したRequireComponent / TryGetComponent
FixedUpdate が遅い毎回 GetComponentAwake でキャッシュ
同じ Rigidbody が 2 個ついたAddComponent を 2 回呼んだ事前に TryGetComponent で確認
Destroy(gameObject) しちゃったComponent 削除のつもりが GO ごと消失Component 変数を Destroy に渡す

FAQ

Q: 同じ GameObject に同じコンポーネントを複数付けたい
A: AudioSource は複数可。Rigidbody や Collider 系は不可(特定の Collider のみ可)。複数アタッチが許容されるかは型ごとに違います。

Q: インターフェイス型で取得できる?
A: できます。GetComponent<IDamageable>() でインターフェイスを実装した MonoBehaviour が返ります。

Q: コンポーネント削除のタイミングは?
A: Destroy はフレーム終了時に実行されます。即時必要なら DestroyImmediate(ただしランタイムでは使わない)。

編集
Post Share
子ページ

子ページはありません

同階層のページ
  1. スクリプトの作成と実行
  2. C# のクラス一覧
  3. シーンの移動方法
  4. オブジェクトの移動・回転
  5. キーボードの入力値を受け取る
  6. オブジェクトの取得とコンポーネントの取得
  7. 衝突時の処理
  8. Webページを開く
  9. コンポーネントの取得
  10. 処理を一定時間待つ
  11. コンソールへのログ出力方法
  12. 飛行機の加速と減速
  13. ジェットエンジンのエフェクトとオーディオ

最近更新/作成されたページ