GameObject.Find() / GetComponent<T>()
| 対応: | C# 1.0(2002) |
|---|
シーン内のゲームオブジェクトを名前で検索する『GameObject.Find()』と、アタッチされているコンポーネントを取得する『GetComponent<T>()』の使い方です。
構文
using UnityEngine; // シーン内から名前でゲームオブジェクトを検索します(見つからない場合は null)。 GameObject obj = GameObject.Find(string name); // タグでゲームオブジェクトを検索します。 GameObject obj = GameObject.FindWithTag(string tag); // タグで一致するすべてのゲームオブジェクトを取得します。 GameObject[] objs = GameObject.FindGameObjectsWithTag(string tag); // このゲームオブジェクトにアタッチされているコンポーネントを取得します。 T comp = GetComponent<T>(); // 子オブジェクトも含めて検索します。 T comp = GetComponentInChildren<T>(); // 親オブジェクトも含めて検索します。 T comp = GetComponentInParent<T>(); // コンポーネントを追加します。 T comp = gameObject.AddComponent<T>();
メソッド一覧
| メソッド | 概要 |
|---|---|
| GameObject.Find(name) | シーン内のすべてのアクティブなゲームオブジェクトを名前で検索します。非アクティブなオブジェクトは対象外です。 |
| GameObject.FindWithTag(tag) | 指定したタグを持つゲームオブジェクトを 1 つ返します。複数ある場合はどれかが返されます。 |
| GameObject.FindGameObjectsWithTag(tag) | 指定したタグを持つすべてのゲームオブジェクトを配列で返します。 |
| GetComponent<T>() | このゲームオブジェクトにアタッチされているコンポーネント T を返します。なければ null を返します。 |
| TryGetComponent<T>(out T component) | コンポーネントの取得を試みます。見つかれば true、なければ false を返します(Unity 2019.2 以降)。 |
| GetComponentInChildren<T>() | 子オブジェクト(自身を含む)を深さ優先で検索してコンポーネント T を返します。 |
| gameObject.AddComponent<T>() | コンポーネント T をゲームオブジェクトに追加して返します。 |
サンプルコード
Inspector からの参照・タグ検索・GetComponent の組み合わせを使ったサンプルです。
FindSample.cs
using UnityEngine;
public class FindSample : MonoBehaviour
{
// Inspector から直接アサインする方法が最も効率的です。
[SerializeField] private GameObject player;
[SerializeField] private Rigidbody2D myRigidbody;
void Start()
{
// GameObject.Find() でシーン内から名前で検索します(Start での使用を推奨)。
GameObject enemy = GameObject.Find("Enemy");
if (enemy != null)
{
Debug.Log($"エネミー発見: {enemy.transform.position}");
}
// FindWithTag() でタグで検索します(Find() より高速です)。
GameObject mainCamera = GameObject.FindWithTag("MainCamera");
if (mainCamera != null)
{
Debug.Log($"メインカメラ: {mainCamera.name}");
}
// GetComponent<>() でコンポーネントを取得します。
Rigidbody rb = GetComponent<Rigidbody>();
if (rb != null)
{
rb.AddForce(Vector3.up * 10f);
}
// TryGetComponent でコンポーネント取得と null チェックを同時に行います。
if (TryGetComponent<Animator>(out Animator anim))
{
anim.SetTrigger("Jump");
}
// GetComponentInChildren で子オブジェクトから検索します。
AudioSource sfx = GetComponentInChildren<AudioSource>();
if (sfx != null)
{
sfx.Play();
}
// タグで複数オブジェクトを取得します。
GameObject[] coins = GameObject.FindGameObjectsWithTag("Coin");
Debug.Log($"コインの数: {coins.Length}");
}
}
実践パターン: 参照のキャッシュ
Find 系メソッドはシーン全体を走査するため負荷が高いです。Awake() か Start() で一度だけ取得してフィールドに保存するパターンが推奨されます。
CachedReference.cs
using UnityEngine;
public class CachedReference : MonoBehaviour
{
// キャッシュ用のフィールドです。
private Rigidbody _rb;
private Animator _anim;
private AudioSource _audio;
private GameObject _uiRoot;
void Awake()
{
// コンポーネントは Awake() で一度だけ取得してキャッシュします。
_rb = GetComponent<Rigidbody>();
_anim = GetComponent<Animator>();
_audio = GetComponentInChildren<AudioSource>();
_uiRoot = GameObject.FindWithTag("UIRoot"); // Find 系も Awake/Start のみ
}
void Update()
{
// NG: Update() 内で GetComponent は毎フレーム検索が走るため低速です。
// GetComponent<Rigidbody>().AddForce(Vector3.up);
// OK: キャッシュしたフィールドを使います。
if (_rb != null)
_rb.AddForce(Vector3.up * 0.1f);
if (Input.GetKeyDown(KeyCode.Space) && _anim != null)
_anim.SetTrigger("Jump");
}
}
実践パターン: 動的コンポーネント追加
AddComponent でランタイムにコンポーネントを追加するパターンです。エフェクトや一時的な処理の付与に使います。
DynamicComponent.cs
using UnityEngine;
public class DynamicComponent : MonoBehaviour
{
void Start()
{
// Rigidbody をコードで追加します。
if (!TryGetComponent<Rigidbody>(out _))
{
Rigidbody rb = gameObject.AddComponent<Rigidbody>();
rb.mass = 2f;
rb.useGravity = true;
Debug.Log("Rigidbody を追加しました。");
}
// AudioSource を追加して設定します。
AudioSource audio = gameObject.AddComponent<AudioSource>();
audio.playOnAwake = false;
audio.volume = 0.8f;
// コンポーネントの有無を確認します。
bool hasRenderer = TryGetComponent<Renderer>(out Renderer rend);
Debug.Log($"Renderer 存在: {hasRenderer}");
if (hasRenderer)
Debug.Log($"マテリアル: {rend.material.name}");
}
}
よくあるミス
よくあるミス1: Update() 内で GameObject.Find() を使う
GameObject.Find() はシーン全体を走査するため重い処理です。Update() 内で使うとパフォーマンスが大幅に低下します。
using UnityEngine;
public class FindInUpdateNG : MonoBehaviour
{
void Update()
{
// NG: 毎フレームシーン全体を検索します。
GameObject enemy = GameObject.Find("Enemy");
if (enemy != null)
transform.LookAt(enemy.transform);
}
}
修正後は次の通りです。
using UnityEngine;
public class FindInUpdateOK : MonoBehaviour
{
private Transform _enemyTransform; // キャッシュ用
void Start()
{
// OK: 初期化時に一度だけ検索してキャッシュします。
GameObject enemy = GameObject.Find("Enemy");
if (enemy != null)
_enemyTransform = enemy.transform;
}
void Update()
{
// キャッシュを使います。
if (_enemyTransform != null)
transform.LookAt(_enemyTransform);
}
}
よくあるミス2: GetComponent の戻り値を null チェックしない
コンポーネントが付いていない場合 GetComponent は null を返します。null チェックなしにアクセスすると NullReferenceException が発生します。
using UnityEngine;
public class NullCheckNG : MonoBehaviour
{
void Start()
{
// NG: Rigidbody が付いていない場合 NullReferenceException が発生します。
GetComponent<Rigidbody>().AddForce(Vector3.up * 10f);
}
}
修正後は次の通りです。
using UnityEngine;
public class NullCheckOK : MonoBehaviour
{
void Start()
{
// OK: TryGetComponent を使うと null チェックを省略できます。
if (TryGetComponent<Rigidbody>(out Rigidbody rb))
{
rb.AddForce(Vector3.up * 10f);
}
else
{
Debug.LogWarning("Rigidbody がアタッチされていません。");
}
}
}
概要
『GameObject.Find()』はシーン全体を走査するため、毎フレーム呼ばれる Update() で使用するとパフォーマンスが大幅に低下します。Start() や Awake() で一度だけ呼び出して変数にキャッシュしてください。可能な限り Inspector で直接アサインする方法を優先してください。
GetComponent<T>() で取得したコンポーネントが null の場合にアクセスすると NullReferenceException が発生します。必ず null チェックを行うか、TryGetComponent<T>() を使用してください。デバッグ出力についてはDebug.Log()を、Unity の数学関数についてはMathfをご確認ください。
記事の間違いや著作権の侵害等ございましたらお手数ですがこちらまでご連絡頂ければ幸いです。