コガネブログ

平日更新を目標にUnityやC#、Visual Studioなどのゲーム開発アレコレを書いていきます

【Unity】指定したゲームオブジェクトから名前で子オブジェクトを検索する拡張メソッド

はじめに

f:id:baba_s:20140728191228p:plain

例えばこれらのオブジェクトが Hierarchy に存在する場合に
UIRoot から Button という名前の子オブジェクトを検索する場合、
次のように処理を書きますが

using UnityEngine;

public class UIRoot : MonoBehaviour
{
    private void Awake()
    {
        Transform result = null;
        
        // 見つからない
        result = transform.Find( "Button" );

        // 見つかる
        result = transform.Find( "Base/Button" );
    }
}

前者のように名前を指定するだけだと見つからないので
後者のように親子関係も指定する必要があります

この書き方だと Hierarchy で Button の親子関係が変わった場合に
Find 関数の指定も書き換える必要があるため少し修正が手間になってしまいます

そこで、名前を指定するだけで子オブジェクトを検索できる
FindDeep という名前の拡張メソッドを作成しました

ソースコード

using System.Linq;
using UnityEngine;

public static class GameObjectExtensions
{
    /// <summary>
    /// 深い階層まで子オブジェクトを名前で検索して GameObject 型で取得します
    /// </summary>
    /// <param name="self">GameObject 型のインスタンス</param>
    /// <param name="name">検索するオブジェクトの名前</param>
    /// <param name="includeInactive">非アクティブなオブジェクトも検索する場合 true</param>
    /// <returns>子オブジェクト</returns>
    public static GameObject FindDeep( 
        this GameObject self, 
        string name, 
        bool includeInactive = false )
    {
        var children = self.GetComponentsInChildren<Transform>( includeInactive );
        foreach ( var transform in children )
        {
            if ( transform.name == name )
            {
                return transform.gameObject;
            }
        }
        return null;
    }
}
    
public static class ComponentExtensions
{
    /// <summary>
    /// 深い階層まで子オブジェクトを名前で検索して GameObject 型で取得します
    /// </summary>
    /// <param name="self">GameObject 型のインスタンス</param>
    /// <param name="name">検索するオブジェクトの名前</param>
    /// <param name="includeInactive">非アクティブなオブジェクトも検索する場合 true</param>
    /// <returns>子オブジェクト</returns>
    public static GameObject FindDeep( 
        this Component self, 
        string name, bool 
        includeInactive = false )
    {
        var children = self.GetComponentsInChildren<Transform>( includeInactive );
        foreach ( var transform in children )
        {
            if ( transform.name == name )
            {
                return transform.gameObject;
            }
        }
        return null;
    }
}

使い方

using UnityEngine;

public class UIRoot : MonoBehaviour
{
    private void Awake()
    {
        Transform result = null;
        
        // 見つからない
        result = transform.Find( "Button" );
        
        // 見つかる
        result = transform.Find( "Base/Button" );
        
        // 見つかる
        result = transform.FindDeep( "Button" ).transform;
        
        // 見つからない
        result = transform.FindDeep( "Label" ).transform;
        
        // 見つかる
        result = transform.FindDeep( "Label", true ).transform;

        // GameObject 型でも使用可能
        result = gameObject.FindDeep( "Button" ).transform;
    }
}

この FindDeep 関数は階層を指定する必要がないので
Hierarchy でオブジェクトの親子関係が変わったとしても
引数の文字列を修正する必要がなくなります

ただし、同じ名前の子オブジェクトが 2 つ以上存在する場合は
どちらか片方しか取得されないので注意が必要です