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

タイトル: オブジェクトの取得とコンポーネントの取得
SEOタイトル: Unity GameObject/Component 取得完全ガイド(Find は重い/SerializeField 推奨)

この記事の要点
  • GameObject 取得: GameObject.Find は重く起動時のみ推奨/FindGameObjectWithTag はそれより速い/Inspector で参照アサインが最速
  • Component 取得: GetComponent() / GetComponentInChildren() / GetComponentInParent()
  • TryGetComponent(2019.2+)は存在しないとき null を投げずパフォーマンス・GC 共に有利
  • 結果はキャッシュする: AwakeStartGetComponent して private フィールドに保持
  • 頻繁に Find する設計は破綻 → [SerializeField] で Inspector アサインを基本にする

GameObject 取得の主要 API

API戻り値コスト用途
GameObject.Find("Name")GameObject★★★(重い、シーン全走査)起動時 1 回限定
GameObject.FindGameObjectWithTag("Tag")GameObject★★(Find より速い)タグ付け済オブジェクト取得
GameObject.FindGameObjectsWithTag("Tag")GameObject[]★★同タグ複数取得
FindObjectsOfType()T[]★★★(極重)シーン横断検索
FindFirstObjectByType()T★★Unity 2022.3+ 推奨
[SerializeField] T fieldT★(直接代入)推奨

サンプル: 各取得方法

using UnityEngine;

public class FindSample : MonoBehaviour
{
    // ★ 推奨: Inspector でアサイン
    [SerializeField] private GameObject player;
    [SerializeField] private Camera mainCam;

    void Start()
    {
        // 名前で検索(重い、起動時のみ)
        var enemy = GameObject.Find("Enemy");

        // タグで検索(マシだが it も重い)
        var goal  = GameObject.FindGameObjectWithTag("Goal");

        // 全タグ一致を配列取得
        var enemies = GameObject.FindGameObjectsWithTag("Enemy");

        // 型から検索(最も重い)
        // Unity 2022.3 以降は FindFirstObjectByType を使う
        var manager = FindFirstObjectByType();

        // ★ Camera.main は内部キャッシュ済(GameObject.Find より速いが過信注意)
        var cam = Camera.main;
    }
}

Component 取得の主要 API

API探索範囲備考
GetComponent()同じ GameObject基本
GetComponentInChildren()自身+子孫非アクティブ含めるオプションあり
GetComponentInParent()自身+祖先同上
GetComponents()同 GO の T 全部配列で返る
GetComponentsInChildren()自身+子孫の全 TUI のリスト取得に便利
TryGetComponent(out T x)同 GO未存在で null を返さず bool。GC ゼロ

キャッシュ推奨パターン

Update 内で毎フレーム GetComponent を呼ぶのは厳禁です。Awake / Start で取得して private フィールドに保持してください。

public class PlayerController : MonoBehaviour
{
    // ★ 1. SerializeField で Inspector からアサインが最速・最安全
    [SerializeField] private Rigidbody rb;
    [SerializeField] private Animator anim;

    // ★ 2. 同 GameObject 内ならコードで Awake キャッシュも可
    private AudioSource _audio;

    void Awake()
    {
        // null チェックは TryGetComponent が便利
        if (!TryGetComponent(out _audio)) {
            Debug.LogWarning("AudioSource not found, adding one.");
            _audio = gameObject.AddComponent();
        }
    }

    void Update()
    {
        // ✅ キャッシュ済を使う
        rb.AddForce(Vector3.up);
        anim.SetFloat("Speed", rb.velocity.magnitude);

        // ❌ NG: 毎フレーム取得
        // GetComponent().AddForce(Vector3.up);
    }
}

子孫からの取得

// 自分含む子の AudioSource を 1 つ取得
var aud = GetComponentInChildren(includeInactive: true);

// 子孫の Renderer を全部
var renderers = GetComponentsInChildren();
foreach (var r in renderers) r.enabled = false;

UnityEvent と デリゲートでイベント連携

毎回 Find で参照する代わりに、イベント駆動にすると依存が逆転し、テストも容易になります。

using UnityEngine;
using UnityEngine.Events;

public class Health : MonoBehaviour
{
    [SerializeField] private UnityEvent onDead;

    public void TakeDamage(int dmg)
    {
        // ...
        if (dmg >= 100) onDead.Invoke();
    }
}

// → 受け取り側を Inspector でアサインしておけば Find 不要

パフォーマンス比較(概略)

呼び方相対コスト毎フレーム呼んで良い?
直接 SerializeField 参照1はい
キャッシュ済の参照1はい
GetComponent~10避ける
GetComponentInChildren~30避ける
FindGameObjectWithTag~50NG
GameObject.Find~200NG
FindObjectsOfType~500+絶対 NG

Camera.main の注意

Camera.main は Unity 内部で "MainCamera" タグ付きカメラを返します。初回呼び出しはキャッシュ生成があるため、頻繁にアクセスするなら自分でキャッシュしてください。

private Camera _cam;
void Awake() { _cam = Camera.main; }
void Update() {
    var world = _cam.ScreenToWorldPoint(Input.mousePosition);
}

シングルトンと DI の検討

頻繁に「ゲーム全体で 1 つ」のオブジェクトにアクセスするなら、シングルトンや DI コンテナ(VContainer / Zenject)を使うほうが、Find より高速かつテストしやすくなります。

public class GameManager : MonoBehaviour
{
    public static GameManager Instance { get; private set; }
    void Awake()
    {
        if (Instance != null && Instance != this) { Destroy(gameObject); return; }
        Instance = this;
        DontDestroyOnLoad(gameObject);
    }
}

// 利用側
GameManager.Instance.AddScore(10);

FAQ

Q: GameObject.Find が動かない
A: 非アクティブなオブジェクトは Find できません。タグ検索(FindGameObjectWithTag)でも同様です。FindObjectsOfType(true) の引数で includeInactive を渡してください。

Q: SerializeField と public、どちらを使う?
A: [SerializeField] private が推奨。外部から書き換えられず、Inspector では編集可能というカプセル化が両立します。

Q: Find は何回までなら許容?
A: 1 シーンの起動時に数回程度なら問題なし。Update / FixedUpdate 内では絶対 NG です。