ゴマちゃんフロンティア

アザラシが大好きなエンジニアの開発日記です

【Unity】階層構造のタグを持ったオブジェクトの一括取得

time 2016/06/07

というわけで、今回はUnityのタグとオブジェクト取得のお話です!
「階層構造のタグ」という表現が正しいのか分かりませんが、タグ名を / で区切った状態のことです。

shot2ss20160607190337887

流れ的には以下の記事の応用といった感じです。
コメントで頂いた「特定の親(子)タグを持ったオブジェクトの取得」について考えみました。

【Unity】タグの階層表示と判定方法について

※本記事では利便上、タグ名を / で区切った上位を親タグ、下位を子タグと記載します。

特定のタグのオブジェクトを取得

今更ですが、特定のタグを持ったオブジェクトの取得方法のおさらいです。
GameObject に関数があるので、それを使えば簡単です。

GameObject testObject = GameObject.FindWithTag("hoge")
GameObject[] testObjects = GameObject.FindGameObjectsWithTag("hoge");

普通にタグを付ける場合、このあたりの API を使えば十分です。

特定の親(子)タグを持ったオブジェクトの取得

ここから本題で、タグを階層構造にした場合の親(子)タグを判定し、そのオブジェクトを取得する方法です。
上記の Unity の API では、/ 込みの完全なタグ名を指定しないと取得してくれません。
そんなわけで、現状では自力で実装するしかないようです。

やや強引ですが、シーン上の GameObject を全取得し、1つ1つのタグを判定すれば何とかなりそう。
ということで、TagUtility クラスに getParentTagObjects() という関数を追加してみました!

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public static class TagUtility {

    /* 中略 */

    public static GameObject[] getParentTagObjects(string name) {
        List<GameObject> gameObjects = new List<GameObject>();

        foreach (GameObject obj in GameObject.FindObjectsOfType<GameObject>()) {
            if (getParentTagName(obj.tag) == name) {
                gameObjects.Add(obj);
            }
        }

        return gameObjects.ToArray();
    }
}

「シーン内の GameObject を全取得する」方法は Unity コミュニティに載っていたので、こちらを参考にしました。
http://answers.unity3d.com/questions/329395/how-to-get-all-gameobjects-in-scene.html

取得した GameObject を foreach で回し、オブジェクトのタグを比較していきます。
オブジェクトから親タグを取得するには getParentTagName() を使います。
このあたりの実装は冒頭で記載した記事をご参照下さい。
簡潔に言うと、GameObject から親タグを取得して返すものです。

親タグが引数のタグ名と一致している場合、List の中に放り込んでいきます。
最後に return で List を配列に変換して返します。

実際に使う場合は以下のような感じ。
TagUtility クラスは静的なので、どのクラスからでも呼べます。

using UnityEngine;
using System.Collections;

public class TagTest : MonoBehaviour {

    void Start () {
        GameObject[] gameObjects = TagUtility.getParentTagObjects("StageObject");

        foreach (GameObject obj in gameObjects) {
            Debug.Log(obj.name);
        }
    }
}

親タグ名が「StageObject」のものを取得し、そのオブジェクト名を出力してみます。
今作成しているステージで実行したらこんな出力になりました!

shot2ss20160607190745464

今回はテストなのでコンソールに出力するだけですが、foreach で回せば一括で処理が行えます。
ただし「シーン内の GameObject を全取得」という時点でパフォーマンス的にはよろしくないです。
なるべく使用は控えめで、かつ Awake() や Start() 内などで初期化するときにだけ行うように注意する必要がありそう。

この勢いで子タグを持ったオブジェクトの取得も実装してしまいます。
TagUtility クラスに getChildTagObjects() を追加します。

public static GameObject[] getChildTagObjects(string name) {
    List<GameObject> gameObjects = new List<GameObject>();

    foreach (GameObject obj in GameObject.FindObjectsOfType<GameObject>()) {
        if (getChildTagName(obj.tag) == name) {
            gameObjects.Add(obj);
        }
    }

    return gameObjects.ToArray();
}

if 文で呼び出す関数が使うだけで、あとはほとんど一緒です。
使用方法は親タグの場合と一緒なので割愛します。

まとめ

階層構造を持ったタグからオブジェクトを取得する方法を考えみました!
オブジェクトを一括で取得して操作する時などに使えそうです。
ただ重そうな処理なので乱用は控えたいところです。

down

コメントする