この内容は古いバージョンです。最新バージョンを表示するには、戻るボタンを押してください。
バージョン:3
ページ更新者:guest
更新日時:2026-06-11 07:07:02

タイトル: コンポーネントの取得
SEOタイトル: Unity Component 取得とキャッシュの完全ガイド(GetComponent/RequireComponent/TryGetComponent)

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

GetComponent の基本

using UnityEngine;

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

        // 型引数なし(古い書き方、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();
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();
        _anim = GetComponent();
    }

    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 が必ず居るので null チェック不要
}

子・親からの取得

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

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

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

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

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

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

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

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

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

パフォーマンス指針

呼び方速度使い所
キャッシュ済フィールド★★★★★Update / FixedUpdate
TryGetComponent★★★★初回 / 条件分岐
GetComponent★★★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() でインターフェイスを実装した MonoBehaviour が返ります。

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