すくまりのメモ帳すくまりのメモ帳
← 記事一覧に戻る

【Unity】Tagを使用した高速なオブジェクトの参照方法「FindWithTag」

【Unity】Tagを使用した高速なオブジェクトの参照方法「FindWithTag」

はじめに

この記事ではオブジェクトの参照方法を紹介します。

準備

Hierarchy上で右クリックして、

「Create Empty」より空オブジェクトを生成し、

「Parent」という名前に変更しました。

次に、Parentの子オブジェクトにCubeを設置してください。

Cubeを子オブジェクトにするには、

CubeをドラッグしてParentの上でドロップしてください。

今回は「Test.cs」スクリプトにコードを記入し、

GameObjectにアタッチしてCubeを取得していきます。

GameObject.Findを使った参照方法

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
 
public class Test : MonoBehaviour
{
 
    // Use this for initialization
    void Start()
    {
        GameObject g = GameObject.Find("Parent/Cube");
        Debug.Log("Name:" + g.name);
    }
 
    // Update is called once per frame
    void Update()
    {
        
    }
 
}
実行結果
 
Name:Cube

Hierarchy上のオブジェクトを取得するときは、

GameObject.Find("オブジェクト名");

のように記入します。

今回のように子オブジェクトを取得するときは、

GameObject.Find(親/");

のようにスラッシュで区切って下の階層に降りてください。

ただし、子オブジェクトが非アクティブの場合は

この方法ではエラー(NullReferenceException)になります。

SetActive = false 等で非アクティブにした場合は

以下のコードで取得できます。

GameObject g = GameObject.Find("Parent").transform.Find("Cube").gameObject;
 

上記のように、一度アクティブなオブジェクトを取得し、

transform.Find("オブジェクト名")と記入すると、

非アクティブなオブジェクトも取得できます。

これが最も基本的な参照方法ですが、

GameObject.Findは比較的処理が重く、

多用は推奨されておりません。

そこで、以下のように、

Hierarchyから直接参照するか、

Tagを使って参照する方法があります。

Hierarchyから直接参照する方法

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
 
public class Test : MonoBehaviour
{
 
    public GameObject g;
 
    [SerializeField] private GameObject k;
 
    // Use this for initialization
    void Start()
    {
        Debug.Log("Name:" + g.name);
 
        Debug.Log("Name:" + k.name);
    }
 
    // Update is called once per frame
    void Update()
    {
        
    }
 
}
実行結果
 
Name:Cube
 
Name:Cube

処理の遅い「GameObject.Find」を使わずに参照するには、

public GameObject g;

のようにpublic変数で宣言してください。

スクリプトをアタッチしたオブジェクトをクリックすると、

public変数はInspectorに表示されていると思います。

その変数に参照したいオブジェクトを

ドラッグ&ドロップしてください。

これで、Findを使わずに参照できます。

これはシーンをロードしたときから取得しているので、

比較的負荷が軽いみたいです。

注意点として、private変数はInspectorには表示されません。

そこで、

[SerializeField] private GameObject k;

のように[SerializeField]を頭につけてください。

これでInspector上に表示されます。

private や [SerializeField] について知りたい方はこちらの記事もおすすめです。

グローバル変数とローカル変数の違いと「Serializefirld」でインスペクター上に変数を表示させる方法

Tagを使った参照方法「FindWithTag」

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
 
public class Test : MonoBehaviour
{
 
    // Use this for initialization
    void Start()
    {
 
        GameObject g = GameObject.FindWithTag("Cube");
 
        Debug.Log("Name:" + g.name);
    }
 
    // Update is called once per frame
    void Update()
    {
        
    }
 
}
実行結果
 
Name:Cube

Tagを使ってFindする場合は、

まず、オブジェクトにTagを付ける必要があります。

CubeのInspectorのTagをクリックし、「Add Tag」をクリック。

Tagsの右下にある+ボタンをクリックし、

New Tag Name に Cubeと入力してSaveしてください。

Tag名は何でも構いません。

これでCube Tagが現れるので選択します。

これで、以下のコードを入力すると、

Tagを使ったFindが可能になります。

GameObject g = GameObject.FindWithTag("Cube");

ちなみに、Tagを使えば直接参照できるので、

親子の関係を考慮する必要が無くなります。

しかも、通常のFindと比較して低負荷で取得できます。

各種Findで速度テストをした記事があるので、

興味がある方はどうぞ。

— コガネブログ ―

【Unity】GameObject.Find 系関数の処理速度の検証結果

しかしながら、このFindには1つ注意点があります。

それは、Cube Tagが複数のオブジェクトについているとき、

上記のコードではどのオブジェクトを取得するか分からない点です。

もし、似たようなオブジェクトの中から

特定の1つを指定したい場合は、

TagをCube1、Cube2のように分けるか、

普通のFindを使用してください。

Tagが付いた複数のオブジェクトを同時に取得する方法

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
 
public class Test : MonoBehaviour
{
 
    // Use this for initialization
    void Start()
    {
 
        GameObject[] g = GameObject.FindGameObjectsWithTag("Cube");
 
        Debug.Log("Name:" + g[0].name);
        Debug.Log("Name:" + g[1].name);
        Debug.Log("Name:" + g[2].name);
    }
 
    // Update is called once per frame
    void Update()
    {
        
    }
 
}
実行結果(今回の場合)
 
Name : Cube1
 
Name : Cube2
 
Name : Cube

HierarchにCube1とCube2を追加し、

両方ともTagにCubeを設定します。

Cubeタグが付いているオブジェクトを全て取得したい場合、

GameObject[] g = GameObject.FindGameObjectsWithTag("Cube");

のように記入します。

配列データとして取得しているので、

使用する際は以下のようになります。

Debug.Log("Name:" + g[0].name);
Debug.Log("Name:" + g[1].name);
Debug.Log("Name:" + g[2].name);

ただし、これもどういう順番で配列に格納されるかは分からないので、

上記のように番号を指定して使用するのは難しいです。

これはforeachを使って、

全てのオブジェクトを消したり、

移動させるといった使い方がほとんどです。

例えば、爆風に巻き込まれて

Cubeタグが付いているオブジェクトは全て消す、

といった場合は以下のように消します。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
 
public class Test : MonoBehaviour
{
 
    // Use this for initialization
    void Start()
    {
 
        GameObject[] g = GameObject.FindGameObjectsWithTag("Cube");
 
        foreach (var obj in g)
        {
            Destroy(obj);
        }
 
    }
 
    // Update is called once per frame
    void Update()
    {
        
    }
 
}

忙しい人のためのUnity入門講座へ戻る