【Unity】 タグを使って複数のゲームオブジェクトをスクリプトから効率的に取得する方法!非アクティブなオブジェクトを取得するには?

はじめに

Unityゲーム開発において、ゲームオブジェクトの操作は非常に重要です。しかし、特定のシーンで複数のゲームオブジェクトを取得し、それらに対してスクリプトを適用する必要がある場合、どのようにすれば最も効率的に処理できるか疑問に思うことがあるかもしれません。

本記事では、基本的なゲームオブジェクトの取得方法から、まとめて取得する方法まで解説します。

本記事で学べること

  • スクリプトからゲームオブジェクトを取得する方法
  • タグを使ってまとめて取得する方法
  • 非アクティブなゲームオブジェクトを取得する方法
  • ゲームオブジェクトを取得する際の注意点について

基本的なゲームオブジェクトの取得方法

Unityでゲームオブジェクトを取得する方法はいくつかありますが、最も基本的な方法は次の2つです。

1. 名前による取得 (GameObject.Find):

ゲームオブジェクトの名前を知っている場合、GameObject.Find() メソッドを使用して取得できます。以下は基本的な使い方です。

   GameObject myObject = GameObject.Find("ObjectName");

“ObjectName”には、ゲームオブジェクトの名前を入れます。

これにより、指定した名前のゲームオブジェクトが取得されます。ただし、この方法は名前に依存するため、名前が変更されると取得できなくなってしまうので注意が必要です。

実際のコード例

using UnityEngine;

public class GameObjectFinder : MonoBehaviour
{
    private void Start()
    {
        // ゲームオブジェクトの名前を指定して取得
        GameObject myObject = GameObject.Find("ObjectName");

        // 取得したゲームオブジェクトが存在するか確認
        if (myObject != null)
        {
            // 取得したゲームオブジェクトに対する操作をここで行う
            Debug.Log("オブジェクト名が見つかりました:" + myObject.name);
        }
        else
        {
            Debug.LogWarning("オブジェクト名: 'ObjectName'が見つかりません");
        }
    }
}

コード例のように、Findで設定した名前が存在しなかった場合も考慮してコードを書くといいでしょう。

後で名前を変えてしまっても、すぐに気づけるから安心!

コード例を実行してみると

ゲームオブジェクトを以下のように用意してコードを実行してみました。

もちろん、’ObjectName’という名前は見つからないので、警告が出ます。

Findのオブジェクト名を変えると取得ができます。

2. タグによる取得 (GameObject.FindWithTag):

ゲームオブジェクトにタグを割り当てている場合、GameObject.FindWithTag() メソッドを使用してまとめて取得できます。

以下の例では、”Enemy”と名付けられたタグがついたゲームオブジェクトを全て取得します。

   GameObject[] myObjects = GameObject.FindGameObjectsWithTag("Enemy");

この場合、指定したタグを持つすべてのゲームオブジェクトが取得され、配列に格納されます。タグはゲームオブジェクトのカテゴリを指定するのに役立ちます。

タグの設定方法

ゲームオブジェクトにどんなタグが設定されているかは、インスペクターの上部に記載されています。

タグのところをクリックして、Add Tag…から、新たにタグを追加することが可能です。

実際のコード例

using UnityEngine;

public class GameObjectFinder : MonoBehaviour
{
    private void Start()
    {
        // タグを指定してゲームオブジェクトを取得
        GameObject[] enemyObjects = GameObject.FindGameObjectsWithTag("Enemy");

        // 取得したゲームオブジェクトに対する操作をループで行う
        foreach (GameObject enemy in enemyObjects)
        {
            Debug.Log("Enemyタグを持ったオブジェクト名:" + enemy.name);
        }
    }
}

タグで取得したオブジェクト全てに何か処理を行いたいときは、foreachを使います。

コード例を実行してみると

ゲームオブジェクトには、Enemyタグをあらかじめ設定しておきます。

取得したすべてのオブジェクトに対して処理が行われました。

非アクティブなオブジェクトを取得するには

紹介した2つの取得方法(FindFindWithTag)について、非アクティブなオブジェクトを見つけることができません。

以下の例だと、Enemy1は取得ができなくなります。

非アクティブなオブジェクトを含む場合は、Transform.Find()メソッドを使用することで解決できます。

Transform child = parentTransform.Find("ChildObjectName");

実際のコード例

using UnityEngine;

public class GameObjectFinder : MonoBehaviour
{
    public GameObject parent = default;

    private void Start()
    {
        // ゲームオブジェクトの名前を指定して取得
        GameObject myObject = parent.transform.Find("Enemy1").gameObject;
    }
}

オブジェクト取得の注意点

Findや、FindWithTagは非常に便利ですが、処理が重たいため、できるだけ多用は避けましょう。2つの対策方法を紹介します。

対策1:Awake、またはStart関数内で取得を行う

マイフレーム実行するUpdate関数ではなく、起動時に一度だけ行うAwakeやStart関数の中で行うのが良いでしょう。

また、一度取得したゲームオブジェクトはキャッシュ(一時保存)しておくことで、ゲームオブジェクトの取得を最小限に止めることができます。

private GameObject cachedObject;

private void Start()
{
    // 初回のみ取得し、以降はキャッシュを使用
    if (cachedObject == null)
    {
        cachedObject = GameObject.Find("ObjectName");
    }
}

データの保存に便利な方法はこちら。

対策2:あらかじめインスペクターに設定しておく

スクリプトからPublicやSerializefieldでゲームオブジェクトの宣言を行っておき、インスペクターにあらかじめ設定しておくことで、Findを使わなくても取得ができます。

参考

おわりに

スクリプトからゲームオブジェクトを取得する方法の解説でした。

私は、ゲームオブジェクトの取得をスクリプトで行うのは重い処理だと知らず、Unityを始めたばかりの頃はFindを多用してしまっていました。今回紹介した対策方法を活用することをおすすめします。

コンパイルを高速化して、ストレスのない開発ができる必須級アセットはこちら

Hot Reload | Edit Code Without Compiling

タイトルとURLをコピーしました