特定の型のインスタンスをすべて取得して操作

FindObjectsByType<T>()メソッドを使って、高速に複数のオブジェクトを操作する方法をみていきましょう

FindObjectsByType<T>()メソッドとは

FindObjectsByType<T>()メソッドは、FindObjectsOfType<T>()メソッドの実装を効率化により高速化したバージョンです

FindObjectsOfType<T>()メソッド

FindObjectsOfType()メソッドは、Unityのゲームオブジェクトの中から、指定されたコンポーネントの型(T)を持つものを全て取得するための静的メソッドです。

引数のTには、取得したいコンポーネントの型を指定します。例えば、FindObjectsOfType()とすると、全てのTransformコンポーネントを持つゲームオブジェクトを取得できます。

このメソッドは、複数のゲームオブジェクトから特定のコンポーネントを取得するために使用されます。例えば、特定のコンポーネントを持つゲームオブジェクトを取得して、それらに対して一括で操作を行うことができます。

ただし、このメソッドはパフォーマンスに影響するため、使用には注意が必要です。ゲームオブジェクトの数が多い場合や、頻繁に呼び出される場合には、適切な最適化が必要です。また、このメソッドは他のコンポーネントを探すためにも使えますが、探す対象になるコンポーネントが多い場合にもパフォーマンスに悪影響を与えることがあるため、使用する場合には注意が必要です。

Helthが特定の値以下になったものはDestroyしたい

各オブジェクト(Cube)に設定されているHealthの値をチェックして、20より小さければ、0を再代入するサンプルを作ってみましょう
なお、Cubeは自分のHealthを常に確認していて0以下になったら削除されるようにしてあります

実行結果

シーンのゲームオブジェクト構成

Cubeを4つとGameManagerのゲームオブジェクトを配置しておきます

Cube1

Cube2

Cube1と同じオブジェクトとしますが、Helthだけ20にしておきます

Cube3

Cube1と同じオブジェクトとしますが、Helthだけ20にしておきます

Cube4

Cube1と同じオブジェクトとしますが、Helthだけ20にしておきます

GameManager

各Cubeを操作するためのスクリプトがアタッチされています

スクリプト

Statusスクリプト

各Cubeにアタッチされています

using UnityEngine;

public class Status : MonoBehaviour
{
    public int Health;

    void Update()
    {
        if (Health <= 0)
        {
            Destroy(gameObject);
        }
    }
}

このコードは、Unityゲームエンジンで動作するスクリプトで、オブジェクトの状態を管理するためのものです。

using UnityEngine;は、Unityのクラスを使用するための名前空間の宣言です。

public class Status : MonoBehaviourは、Statusという名前のクラスを定義し、MonoBehaviourクラスを継承することを示しています。MonoBehaviourクラスは、Unityのゲームオブジェクトにアタッチされるスクリプトの基本クラスです。

public int Helth;は、Helthという名前の公開された(外部からアクセス可能な)整数型の変数を宣言しています。

void Update()は、Unityが毎フレーム呼び出す特別なメソッドで、このスクリプトがアタッチされたオブジェクトの状態を更新するために使用されます。

if (Helth <= 0)は、Helth変数が0以下になった場合に、以下のブロックを実行する条件文です。

Destroy(gameObject);は、このスクリプトがアタッチされたオブジェクト自体を削除するためのUnity関数です。gameObjectは、このスクリプトがアタッチされているオブジェクト自体を表す特別な変数です。

つまり、このスクリプトは、Helth変数が0以下になった場合に、このスクリプトがアタッチされたオブジェクトを破棄するという動作をします。これにより、ゲームオブジェクトの状態を管理することができます。

HealthCheckerスクリプト

using System.Linq;
using UnityEngine;

public class HealthChecker : MonoBehaviour
{
    void Start()
    {
        var enemiesWithStatus = FindObjectsByType<Status>(FindObjectsSortMode.None);

        var enemiesOver20helth = enemiesWithStatus.Where(enemy => enemy.Health > 20);

        foreach (var enemy in enemiesOver20helth)
        {
            enemy.Health = 0;
        }
    }
}

このコードは、UnityのゲームオブジェクトにアタッチされたHealthCheckerというコンポーネントを定義しています。このコンポーネントは、ゲームオブジェクトのStart関数が実行されると、敵キャラクターのStatusコンポーネントを持つオブジェクトを見つけ、その中でヘルスが20以上の敵キャラクターのヘルスを0に設定するものです。

具体的には、以下のように機能します。

  • using System.Linq;UnityEngine;をインポートしています。
  • HealthCheckerクラスは、MonoBehaviourを継承しています。
  • Start()関数は、ゲームオブジェクトがアクティブになったときに呼び出されます。
  • FindObjectsByType関数は、指定されたコンポーネントタイプを持つすべてのオブジェクトを取得します。引数にはFindObjectsSortModeがあり、オブジェクトの並び順を制御します。この例では、Noneを指定しているため、オブジェクトの並び順は変更されません。
  • enemiesWithStatusは、Statusコンポーネントを持つすべてのオブジェクトのリストです。
  • Where関数は、条件を満たす要素を取り出すために使用されます。この例では、enemy.Health > 20という条件を指定しています。したがって、enemiesOver20helthは、ヘルスが20以上の敵キャラクターのリストです。
  • foreachループは、enemiesOver20helthの各要素に対して、enemy.Health = 0を実行します。つまり、ヘルスが20以上の敵キャラクターのヘルスを0に設定します。

以上のように、このコードはUnityのゲームオブジェクトで、Statusコンポーネントを持つ敵キャラクターのうち、ヘルスが20以上のものを見つけ、ヘルスを0に設定します。

RigidBodyがアタッチされている条件で、重力で落ちるようにする

各オブジェクト(Cube)で、RigidBodyがアタッチされているものを選択して、useGravityプロパティをtrueにして重力で落下するようにします

実行結果

シーンのゲームオブジェクト構成

Helthが特定の値以下になったものはDestroyしたいの時と基本同じです
アタッチされているスクリプトは削除します
Cube1とCube2にはRigidBodyをアタッチしておきます

また、GameManagerには次のようなスクリプトをアタッチしておきます

スクリプト

GravityAddスクリプト

using UnityEngine;

public class GravityAdd : MonoBehaviour
{
    void Start()
    {
        var enemiesWithGravity = FindObjectsByType<Rigidbody>(FindObjectsSortMode.None);

        foreach (var eneny in enemiesWithGravity)
        {
            eneny.useGravity = true;
        }
    }
}

このコードは、Unityエンジンで動作するC#スクリプトで、GravityAddという名前のクラスが定義されています。

このスクリプトは、オブジェクトの開始時にStart()メソッドが呼び出され、シーン内の全てのRigidbodyコンポーネントを持つ敵オブジェクトを検索し、それぞれのRigidbodyコンポーネントのuseGravityプロパティをtrueに設定します。

具体的には、FindObjectsByType(FindObjectsSortMode.None)メソッドが、Rigidbodyコンポーネントを持つ全てのオブジェクトを検索し、enemiesWithGravityという変数に格納します。次に、foreachループを使って、enemiesWithGravityリスト内の全てのオブジェクトに対して、useGravityプロパティをtrueに設定します。

つまり、このスクリプトは、シーン内の全ての敵オブジェクトに対して、重力を有効にするという処理を行います。

必須ではないですが、次のような記述もできます

using System.Linq;
using UnityEngine;

public class GravityAdd : MonoBehaviour
{
    void Start()
    {
        var enemiesWithGravity = FindObjectsByType<Rigidbody>(FindObjectsSortMode.None);

        enemiesWithGravity.ToList().ForEach(enemy => enemy.useGravity = true);
    }
}

ForEach() メソッドを使用して、リスト内のすべてのオブジェクトに対して、useGravity プロパティを true に設定して重力を有効にします。ForEach() メソッドは、ラムダ式を引数に取り、リスト内の各要素に対して同じ処理を実行します。このスクリプトでは、ラムダ式内で enemy.useGravity = true を実行することで、各 Rigidbody コンポーネントの useGravity プロパティを true に設定しています。

参考

Unity

Posted by hidepon