【UnityEditor】ヒエラルキーウィンドウに表示されているオブジェクトの一覧を取得してみる

はじめに

Unityのヒエラルキーに表示されているオブジェクト一覧を取得する方法を調べてみました。
1.png

環境

Windows 10
Unity5.6.2p4 (Unity2017系でもおそらく動きます)

作ったもの

ヒエラルキーウィンドウ上に表示されているオブジェクト一覧を取得して表示するというものを作ってみました。

image.png

ソースコード

プロジェクト内にEditorフォルダを作成し、以下のスクリプトを入れてください

HierarchyTest.cs
namespace HierarchyTest
{
    using System.Collections.Generic;
    using System.Reflection;
    using UnityEngine;
    using UnityEditor;
    using UnityEditor.IMGUI.Controls;

    public class HierarchyTest
    {
        /// <summary>
        /// ヒエラルキー上に表示されているオブジェクトの一覧を取得するテスト
        /// </summary>
        [MenuItem("Test/GetHierarchyRowsTest")]
        public static void GetHierarchyRowsTest()
        {
            // Hierarchyウィンドウ取得
            var asm = Assembly.Load("UnityEditor.dll");
            var typeWindow = asm.GetType("UnityEditor.SceneHierarchyWindow");
            var window = EditorWindow.GetWindow(typeWindow);

            // SceneHierarchyWindow.csの中に記述されている以下の1行をリフレクションを使って実行し、オブジェクト一覧を取得
            // IList<TreeViewItem> rows = this.m_TreeView.data.GetRows();
            var m_TreeView = typeWindow.GetField("m_TreeView", BindingFlags.Instance | BindingFlags.NonPublic)
            .GetValue(window);
            var data = m_TreeView.GetType().GetProperty("data", BindingFlags.Instance | BindingFlags.Public)
            .GetValue(m_TreeView, null);
            var rows = (IList<TreeViewItem>)data.GetType().GetMethod("GetRows", BindingFlags.Instance | BindingFlags.Public)
            .Invoke(data, null);

            // 取得したオブジェクト一覧をコンソールに出力
            foreach (var row in rows)
            {
                Debug.Log(row);
            }
        }
    }
}

このエディター拡張を使う

画面上部のメニューから Test/GetHierarchyRowsTest を選択するとこのエディター拡張を使用することができます。
image.png

解説

今回のスクリプトを作成するにあたって下記URLにあるUnityのDLLデコンパイルコードを参考にさせていただきました。
https://github.com/MattRix/UnityDecompiled

ヒエラルキーウィンドウのソースコードはSceneHierarchyWindow.csの中に記述されています。



補足: この記事を書いた時点でのGitHubリポジトリのUnityバージョンはUnity2017.1.0f3でした。

コード解説: ヒエラルキーウィンドウの取得

以下のコードではUnityエディタのヒエラルキーウィンドウの取得を行っています。

var asm = Assembly.Load("UnityEditor.dll");
var typeWindow = asm.GetType("UnityEditor.SceneHierarchyWindow");
var window = EditorWindow.GetWindow(typeWindow);

コード解説: フィールドm_TreeViewの取得

以下のコードではSceneHierarchyWindowクラスの中にあるm_TreeViewを取得しています。

var m_TreeView = typeWindow.GetField("m_TreeView", BindingFlags.Instance | BindingFlags.NonPublic)
.GetValue(window);

SceneHierarchyWindowの中で
private TreeViewController m_TreeView; 
のようにprivateなフィールドが定義されているので、GetField()のBindingFlagsに
BindingFlags.Instance | BindingFlags.NonPublic
を指定しています。

コード解説: プロパティdataの取得

以下のコードではTreeViewControllerクラスの中にあるdataを取得しています。

var data = m_TreeView.GetType().GetProperty("data", BindingFlags.Instance | BindingFlags.Public)
.GetValue(m_TreeView, null);

TreeViewControllerの中で
public ITreeViewDataSource data { get; set; }
のようにpublicなプロパティが定義されているので、GetProperty()のBindingFlagsに
BindingFlags.Instance | BindingFlags.Public を指定しています。

コード解説: メソッドGetRows()の実行

以下のコードでは、ITreeViewDataSourceの中にあるGetRows()メソッドを実行しています。

var rows = (IList<TreeViewItem>)data.GetType().GetMethod("GetRows", BindingFlags.Instance | BindingFlags.Public)
.Invoke(data, null);

ITreeViewDataSourceの中で
IList<TreeViewItem> GetRows();
のようにprivateなメソッドが定義されているので、GetMethod()のBindingFlagsに
BindingFlags.Instance | BindingFlags.NonPublic
を指定しています。

GetRows()は引数無しなので、Invokeメソッドの2番目の引数にnullを指定しています。