名古屋でアプリ・VR開発を行っています
ワクワクできるゲームをガンガン開発リリース中!

【Unity】エディタ拡張 オブジェクト名の完全一致検索

皆さん、こんにちは!SAT-BOXのカメです。

今回はUnityのエディタ拡張でHierarchyから指定した名称と完全一致するGameObjectを選択状態にするツールを作成してみました。
オブジェクトを配置するときに、同じ文字を含む名称を付けることがありますが、UnityのHierarchy検索機能では検索ワードを名称に含むGameObjectがすべて参照されてしまい、特定のGameObjectを探しにくい場合があります。
例えばHierarchyに"sat_test"と"test"が混在するとき、"test"を検索すると"sat_test"も一緒に検索結果に出てくる場合です。

そこで今回は名称検索して、GameObject名が完全一致する場合のみ選択状態にするエディタ拡張を作ってみました。
機能としてはシンプルに、
①検索ワードを入力
②検索ボタンを押すと対象のオブジェクトが選択状態になる
といったものになっています

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using UnityEditor.Experimental.SceneManagement;

public class ExactMatchSearch_Editor : EditorWindow
{
    // String型の文字を設定する変数
    static string stringValue = "";

    // 検索候補オブジェクトのリスト
    static object[] hierarchyList;

    // 名称一致したオブジェクトのリスト
    static List<Object> searchList = new List<Object>();

    [MenuItem("MyEditor/名称一致検索")]
    static void Open()
    {
        // この処理で作成した画面を開く
        GetWindow<ExactMatchSearch_Editor>();
    }

    void OnGUI()
    {
        GUILayout.Label("▼ 名称完全一致のGameObjectを選択状態にする");

        GUILayout.Label("検索するオブジェクト名");

        // [stringValue]に変更があるかを確認する処理
        EditorGUI.BeginChangeCheck();
        {
            // String型入力フィールド作成
            stringValue = GUILayout.TextArea(stringValue);
        }
        
        //検索ボタン表示
        if (GUILayout.Button("検索", GUILayout.Width(150)))
        {
            Search();
        }
    }

    private void Search() 
    {
        CreateHierarchyList();

        CheckObjName();
    }

    static void CreateHierarchyList()
    {
        // 非アクティブも含めたHierarchy,Project内の全てのゲームオブジェクトを取得
        hierarchyList = Resources.FindObjectsOfTypeAll(typeof(GameObject));
    }

    private void CheckObjName()
    {
        searchList.Clear();

        for (int i = 0; i < hierarchyList.Length; i++)
        {
            GameObject gameObj = (GameObject)hierarchyList[i];

            //プレハブモードの場合
            if (PrefabStageUtility.GetCurrentPrefabStage() != null)
            {
                if (PrefabStageUtility.GetCurrentPrefabStage().IsPartOfPrefabContents(gameObj))
                {
                    //名称一致するGameObjectをリストに加える
                    if (gameObj.name == stringValue)
                    {
                        searchList.Add(gameObj);
                    }
                }
            }
            else 
            {
                //Hierarchy上のGameObjectのみ検索候補に加える
                if (AssetDatabase.GetAssetOrScenePath(gameObj).Contains(".unity"))
                {
                    //名称一致するGameObjectをリストに加える
                    if (gameObj.name == stringValue)
                    {
                        searchList.Add(gameObj);
                    }
                }
            }
        }
        //リストに追加されたGameObjectを選択状態にする
        Selection.objects = searchList.ToArray();
    }
}

少し困った事があり、FindObjectsOfTypeAllで取得するオブジェクトはHierarchyだけでなく、Projectのオブジェクトも含まれます。
単純にFindObjectsOfTypeAllで取得したものを名称比較しても、Projectのオブジェクトも同時に選択されてしまいます。

今回はHierarchyのオブジェクトのみ選択対象にしたかったので、
AssetDatabase.GetAssetOrScenePath(gameObj).Contains(".unity")
こちらでHierarchyにあるか判定を取っています。

また、プレハブモードで編集中の場合、シーンのHierarchyにあるオブジェクトも選択されてしまい使いにくかった為、
PrefabStageUtility.GetCurrentPrefabStage().IsPartOfPrefabContents(gameObj)
こちらでプレハブ内のオブジェクトのみ選択対象にすることで、候補から除外するようにしました。

実際の確認画面がこちらです。こちらがシーン上で検索した結果です。
f:id:sat-box:20220318121951p:plain

こちらがプレハブモードで検索した結果です。狙い通りの動作になっていますね。
f:id:sat-box:20220318122224p:plain
作業効率を上げるためにもエディタ拡張を使いこなしていきましょう!

以上、カメでした。