ゴマちゃんフロンティア

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

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

time 2015/11/24

というわけで、今回はUnityのタグに関するお話です!

shot2ss20151124230737479

GameObjectのFindや判定系の処理に大活躍のタグですが、量が多いと管理が面倒であったり、複数のタグを付けれなかったりします。
特に似たような特徴のタグを複数用意する際は雑多になってしまいます。

例えば「ステージ上のオブジェクト」というタグを考えた場合、その種類として
 →「破壊可能なオブジェクト」
 →「破壊不可能なオブジェクト」
 →「持って投げることが可能なオブジェクト」
 →「ブロックオブジェクト」
等が考えられます。

これらを普通に追加するとタグ設定時の選択肢が増えて見にくくなります。
また、グループ分けしての判別もできないので「ブロックオブジェクト」を「ステージ上のオブジェクト」として判定したい場合に面倒なことになります。
今回はそのあたりをいい具合になるよう考えてみました!

タグの階層表示

タグの名前に/(スラッシュ)を入れると、タグが階層構造で表示されるようになります。
メニューのEdit→ProjectSettings→Tag and Layersでタグ一覧を表示し、スラッシュ込みで入力します。

shot2ss20151124230814769

これはタグに限らず、レイヤーやシェーダーなども同様です。
自分はカスタマイズしたシェーダーを「Custom/(シェーダー名)」という名前にし、階層構造にしています。

数が多くなってくると選択するのが大変なので、分けておくと便利です。
冒頭のタグも「StageObject/(タグ名)」といった感じで整理できます。

タグ名の判定

スラッシュを入れると階層構造に出来ますが、参照の仕方は変わりません。
つまり、タグを指定する場合「StageObject/Block」といった形になります。
やや冗長な上、「親タグや子タグを参照」といったことも出来ません。

ただ階層は必ずスラッシュで区切っているので、その前後でタグを見分けることができます。
ということで、親タグ名や子タグ名を取得するUtilityクラスを作ってみました!

using UnityEngine;
using System.Collections;

public static class TagUtility {

    public static string getParentTagName(string name) {
        int pos = name.IndexOf("/");

        if (0 < pos) {
            return name.Substring(0, pos);
        } else {
            return name;
        }
    }

    public static string getParentTagName(GameObject gameObject) {
        string name = gameObject.tag;
        int pos = name.IndexOf("/");

        if (0 < pos) {
            return name.Substring(0, pos);
        } else {
            return name;
        }
    }

    public static string getChildTagName(string name) {
        int pos = name.IndexOf("/");

        if (0 < pos) {
            return name.Substring(pos + 1);
        } else {
            return name;
        }
    }

    public static string getChildTagName(GameObject gameObject) {
        string name = gameObject.tag;
        int pos = name.IndexOf("/");

        if (0 < pos) {
            return name.Substring(pos + 1);
        } else {
            return name;
        }
    }
}

実際にOnTriggerEnter等で使う場合は以下のような感じ。
TagUtilityクラスの関数を呼ぶだけ!

 
public void OnTriggerEnter(Collider c){
    if (TagUtility.getParentTagName(c.gameObject) == "StageObject") {
        // 処理
    }

    if (TagUtility.getChildTagName(c.gameObject) == "Block") {
        // 処理
    }
}

getParentTagName()で親タグ名、getChildTagName()で子タグを取得します。
指定文字列が見つからない場合(=階層構造になっていない)場合はタグ名をそのまま返却します。
文字列での指定の他、GameObjectを渡すことでも取得できるようにしました。

「StageObject/Block」の場合、「StageObject」と「Block」の2パターンで判定できることになります。
Unityは1オブジェクト1タグですが、これで親タグを使ったグループ分けができます。
擬似的ですが、複数のタグを扱っているような感じですね。

これで「ステージオブジェクト」で「ブロックオブジェクト」なものを判別できるようになりました!
他にも敵キャラクターやアイテムを判別する際にも重宝しそうです。
なかなか便利なので、今後も使っていきたいと思います!

余談

シルリスのモデリングを修正し、靴を履いているような感じにしてみました!
他2キャラと比べると適当な足だったので気になっていたところです。
パッと見では短い長靴を履いているようにしか見えませんが、とりあえずこれで十分です。

shot2ss20151124230652229

コメント

  • スミマセン、応用が出来なかったので質問があります。

    親タグ名や子タグ名を取得するUtilityクラス スクリプトはどのオブジェクトに着けたらいいですか?
    GameObject[] gameobject= GameObject.FindGameObjectsWithTag(“tag名”);
    上のスクリプトに親タグ名や子タグ名を代入するにはどの様に書いたらいいですか?
    現在、Utilityクラス スクリプトはプレイヤー・オブジェクトにつけて、同じくプレイヤーオブジェクトにつけた別ファイルから上記のスクリプトを読ませようとしてます。

    H  2016年6月5日 4:41 PM

    • Hさん

      TagUtilityクラスは静的クラスなので、特定のオブジェクトに付ける必要はありません。
      記載頂いた例で使用する場合、以下のような形になると思われます。

      【親タグ】
      GameObject[] gameobject= GameObject.FindGameObjectsWithTag(TagUtility.getParentTagName(“タグ名”));

      【子タグ】
      GameObject[] gameobject= GameObject.FindGameObjectsWithTag(TagUtility.getChildTagName(“タグ名”));

      ただ、上記コードで「特定の親(子)タグを持ったオブジェクトを取得したい」といった場合、TagUtilityクラスでは難しいと思います。
      FindGameObjectsWithTagはUnity側のAPIなので、/込みの完全なタグ名で指定する必要があるためです。
      もしやりたい場合は独自で実装するしかないと思われます。

      [2016/06/07 追記]
      以下の記事にてオブジェクトの一括取得の実装を考えてみました。
      よろしければご参照下さい。
      http://gomafrontier.com/unity/594

      riberunn  2016年6月6日 9:15 PM

  • ご丁寧に有難うございました。
    (親 / 子)でタグ名を書いたら普通に挙動したので良かったです。

    H  2016年6月11日 11:02 PM

down

コメントする