Unityにおけるオブジェクト検索メソッドの徹底解説

Unityでは、シーン内のオブジェクトを検索するために複数のメソッドが用意されています。用途やパフォーマンス面、条件に合わせた検索など、さまざまなケースに応じて使い分ける必要があります。以下では、代表的な検索メソッドと、その応用例(タグや名前による条件抽出、スクリプトではなくGameObject自体を対象とする例)を詳細に解説します。


1. FindFirstObjectByType

概要

  • 動作内容
    指定された型の中で、最初に見つかったアクティブなロード済みオブジェクト(通常はインスタンスIDが最も低いもの)を返します。
  • 特性
    • 一貫性:常に同じ条件で検索されるため、結果が安定しています。
    • パフォーマンス負荷:シーン内の全オブジェクトを走査するため、毎フレームの利用は避けるべきです。
  • 利用シーン
    シングルトンパターンなど、特定の1つのインスタンスを確実に取得する必要がある場合に適しています。
  • 非アクティブオブジェクトの取り扱い
    引数に FindObjectsInactive.Include を指定することで、非アクティブなオブジェクトも対象に含められます。

サンプルコード

// アクティブなオブジェクトのみ検索(デフォルト)
OtherScript instance1 = FindFirstObjectByType<OtherScript>();

// 明示的に非アクティブなオブジェクトを除外して検索
OtherScript instance2 = FindFirstObjectByType<OtherScript>(FindObjectsInactive.Exclude);

// 非アクティブなオブジェクトも含めて検索
OtherScript instance3 = FindFirstObjectByType<OtherScript>(FindObjectsInactive.Include);

2. FindAnyObjectByType

概要

  • 動作内容
    指定された型のアクティブなロード済みオブジェクトのうち、任意の1つ(毎回異なる可能性がある)を返します。
  • 特性
    • 高速な処理:全体を走査する必要がなく、条件に合致した最初のオブジェクトを返すため効率的です。
    • 結果の一貫性が低い:返されるオブジェクトは毎回変わる可能性があるため、特定のインスタンスを必要とする場合には不向きです。
  • 利用シーン
    パフォーマンスを重視し、どのインスタンスでも問題ない場合に利用されます。
  • 非アクティブオブジェクトの取り扱い
    引数により制御が可能です。

サンプルコード

// アクティブなオブジェクトのみ検索(デフォルト)
OtherScript instance1 = FindAnyObjectByType<OtherScript>();

// 明示的に非アクティブなオブジェクトを除外して検索
OtherScript instance2 = FindAnyObjectByType<OtherScript>(FindObjectsInactive.Exclude);

// 非アクティブなオブジェクトも含めて検索
OtherScript instance3 = FindAnyObjectByType<OtherScript>(FindObjectsInactive.Include);

3. FindObjectsOfType:複数のオブジェクトを一括取得

概要

  • 動作内容
    シーン内の指定型のオブジェクトをすべて配列として取得します。
    デフォルトではアクティブなオブジェクトのみが対象ですが、オーバーロードにより非アクティブなオブジェクトも含めることが可能です。
  • 特性
    • 一括取得:複数のオブジェクトに対して一括で処理を行いたい場合に有効です。
  • パフォーマンスの注意点:シーン内のオブジェクト数が多い場合、全体を走査するため負荷が高くなる可能性があります。

基本サンプルコード

// アクティブなオブジェクトのみを取得(デフォルト)
OtherScript[] instances1 = FindObjectsOfType<OtherScript>();

// 非アクティブなオブジェクトも含めて取得(Unity2020以降のオーバーロード)
OtherScript[] instances2 = FindObjectsOfType<OtherScript>(true);

4. 条件によるフィルタリングの応用例

FindObjectsOfTypeで取得した配列に対し、LINQを利用してさらに条件を絞り込む方法を紹介します。

4.1. プロパティ値でフィルタリング

たとえば、コンポーネント OtherScript に score という数値プロパティがあり、score が50以上のものを抽出する場合:

using System.Linq; // LINQ利用のために必要

// シーン内の全 OtherScript コンポーネントを取得
OtherScript[] allInstances = FindObjectsOfType<OtherScript>();

// score プロパティが 50 以上のオブジェクトを抽出
OtherScript[] filteredInstances = allInstances.Where(instance => instance.score >= 50).ToArray();

foreach (var instance in filteredInstances)
{
    Debug.Log($"Scoreが50以上のインスタンス: {instance.name}");
}

4.2. タグを条件にフィルタリング

例2-1: LINQでタグフィルタリング

using System.Linq; // LINQ利用のために必要

// シーン内の全 OtherScript コンポーネントを取得
OtherScript[] allInstances = FindObjectsOfType<OtherScript>();

// タグが "Enemy" のオブジェクトを抽出
OtherScript[] enemyInstances = allInstances.Where(instance => instance.CompareTag("Enemy")).ToArray();

foreach (var enemy in enemyInstances)
{
    Debug.Log($"Enemyタグが付いたインスタンス: {enemy.name}");
}

例2-2: GameObject.FindGameObjectsWithTag を利用する方法

タグ “Enemy" を持つ GameObject を直接取得し、そこから必要なコンポーネントを参照する方法です。

// タグ "Enemy" を持つ全 GameObject を取得
GameObject[] enemyObjects = GameObject.FindGameObjectsWithTag("Enemy");

foreach (GameObject enemyObj in enemyObjects)
{
    // 例として、Enemyオブジェクトに OtherScript コンポーネントが付いている場合
    OtherScript script = enemyObj.GetComponent<OtherScript>();
    if (script != null)
    {
        Debug.Log($"Enemyタグが付いたオブジェクトからOtherScriptを取得: {enemyObj.name}");
    }
}

4.3. 名前を条件にフィルタリング

4.3.1. コンポーネントの名前でフィルタリング

(対象がスクリプトコンポーネントの場合)

using System.Linq; // LINQ利用のために必要

// シーン内の全 OtherScript コンポーネントを取得
OtherScript[] allInstances = FindObjectsOfType<OtherScript>();

// 名前が "TargetObject" のコンポーネントを抽出
OtherScript[] targetInstances = allInstances.Where(instance => instance.name == "TargetObject").ToArray();

foreach (var instance in targetInstances)
{
    Debug.Log($"名前が 'TargetObject' のインスタンス: {instance.name}");
}

4.3.2. GameObject自体の名前でフィルタリング

スクリプトに依存せず、GameObjectの名前を条件に複数のオブジェクトを取得する場合の例です。

using System.Linq; // LINQ利用のために必要
using UnityEngine;

public class FindByNameExample : MonoBehaviour
{
    void Start()
    {
        // シーン内の全アクティブなGameObjectを取得
        GameObject[] allObjects = GameObject.FindObjectsOfType<GameObject>();

        // 名前が "TargetObject" と一致するGameObjectを抽出
        GameObject[] targetObjects = allObjects.Where(obj => obj.name == "TargetObject").ToArray();

        foreach (var obj in targetObjects)
        {
            Debug.Log($"名前が 'TargetObject' のGameObject: {obj.name}");
        }
    }
}

5. (旧バージョン)FindObjectOfType

概要

  • 動作内容
    従来使用されていたメソッドで、シーン内のアクティブなオブジェクトから指定型の最初のインスタンスを返していました。
  • 注意点
    シーン内のオブジェクト数が多い場合に全体走査を行うため、パフォーマンスに影響が出ることがあり、現在は上記の新しいメソッド(FindFirstObjectByTypeやFindObjectsOfType)の使用が推奨されます。

6. まとめ

  • 特定の1つのインスタンスを確実に取得したい場合
    FindFirstObjectByType を利用。常に同じ条件で検索されるため、一貫性があります。
  • 任意のインスタンスで十分で、パフォーマンス重視の場合
    FindAnyObjectByType を利用。高速に検索が行えますが、結果は毎回変わる可能性があります。
  • 複数のオブジェクトを一括取得したい場合
    FindObjectsOfType を利用し、必要に応じて LINQ 等でさらにフィルタリングします。
    ・プロパティ、タグ、名前といった条件でのフィルタリング例も用意されています。
    ・GameObject自体を条件とする場合は、GameObject.FindObjectsOfType や GameObject.FindGameObjectsWithTag を活用できます。

各メソッドは、シーンの規模や実行時のパフォーマンス、また検索対象の条件に応じた使い分けが重要です。用途に合わせた適切な検索方法を選択することで、効率的な開発が実現できます。

Unity

Posted by hidepon