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

# はじめに
Unityのヒエラルキーに表示されているオブジェクト一覧を取得する方法を調べてみました。
![1.png](https://qiita-image-store.s3.amazonaws.com/0/44288/9522bdd4-ef64-389d-4ecb-ec0cf94a7c80.png)


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

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

![image.png](https://qiita-image-store.s3.amazonaws.com/0/44288/72469a36-3926-4a1f-38da-3f46982c531a.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の中に記述されている以下の１行をリフレクションを使って実行し、オブジェクト一覧を取得
            // 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](https://qiita-image-store.s3.amazonaws.com/0/44288/d3a7ffe3-0e7f-e10d-9017-0d5cee3becdc.png)


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

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

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

<img width = 600 src = "https://qiita-image-store.s3.amazonaws.com/0/44288/d372193e-092b-0335-c6d2-6063141e9251.png">


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

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

## コード解説: フィールドm_TreeViewの取得
以下のコードではSceneHierarchyWindowクラスの中にあるm_TreeViewを取得しています。

```csharp
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()メソッドを実行しています。

```csharp
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**を指定しています。