シーンにゲームオブジェクトが大量にあると、少しの修正にも時間がかかります。そこで、エディタ拡張で、条件にあったヒエラルキーにあるゲームオブジェトを素早く選択できるようにしてみました。
今回は、シーンの中からオーディオミキサーの設定されていないAudioSourceコンポーネントを持ったゲームオブジェクトだけをエディタウィンドウに表示してみます。
Editorウィンドウを作る
まず、プロジェクトウィンドウで「Editor」という名前のフォルダを作り、その中にC#スクリプトを新規作成しました。このクラスはMonoBehaviourではなく、EditorWindowクラスを継承させます。
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
public class TestEditorWindow1 : EditorWindow
{
// 条件に合うゲームオブジェクトのリスト
List<GameObject> objectsInScene = new List<GameObject>();
// メインメニューからウィンドウを表示できるようにする。
[MenuItem("Window/TestEditorWindow1")]
static public void CreateWindow()
{
EditorWindow.GetWindow<TestEditorWindow1>();
}
private void OnGUI()
{
// 検索ボタンを押す
if (GUILayout.Button("検索"))
{
// リストをクリア
objectsInScene.Clear();
// すべてのゲームオブジェクト
foreach (GameObject go in Resources.FindObjectsOfTypeAll(typeof(GameObject)) as GameObject[])
{
// ヒエラルキーにあるゲームオブジェクト
if (!EditorUtility.IsPersistent(go.transform.root.gameObject) && !(go.hideFlags == HideFlags.NotEditable || go.hideFlags == HideFlags.HideAndDontSave))
{
// AudioSourceを取得
var a = go.GetComponent<AudioSource>();
// AudioSourceがあって、オーディオミキサーが未設定の場合
if (a != null && a.outputAudioMixerGroup == null)
{
// リストの先頭に追加
objectsInScene.Insert(0, go);
}
}
}
}
// クリアボタンを押す
else if(GUILayout.Button("クリア"))
{
// リストをクリア
objectsInScene.Clear();
}
// リストにゲームオブジェクトがあるとき
if (objectsInScene.Count > 0)
{
// 縦にレイアウト
using (new EditorGUILayout.VerticalScope())
{
// リストを一つずつ見る
for(int i = 0; i < objectsInScene.Count; i++)
{
// ボタンを表示する。ボタン上にゲームオブジェクトの名前を表示。
if (GUILayout.Button(objectsInScene[i].name, EditorStyles.textField))
{
// ボタンをクリックすると、そのゲームオブジェクトを選択する。
Selection.activeGameObject = objectsInScene[i];
}
}
}
}
}
}
まずグローバル変数として、検索したゲームオブジェクトを入れるリストを作ります。
List<GameObject> objectsInScene = new List<GameObject>();
このウィンドウを作成する静的メソッドを定義します。これにはMenuItem属性を付けて、メインメニューから実行できるようにしています。
[MenuItem("Window/TestEditorWindow1")]
static public void CreateWindow()
{
EditorWindow.GetWindow<TestEditorWindow1>();
}
ウィンドウの内容をOnGUIメソッドに書きます。ウィンドウには「検索」ボタンと「クリア」ボタンを表示します。
検索ボタンをクリックすると、まずリストをクリアし、ヒエラルキーウィンドウにあるゲームオブジェクトをすべて検索します。
private void OnGUI()
{
// 検索ボタンを押す
if (GUILayout.Button("検索"))
{
// リストをクリア
objectsInScene.Clear();
// すべてのゲームオブジェクト
foreach (GameObject go in Resources.FindObjectsOfTypeAll(typeof(GameObject)) as GameObject[])
{
// ヒエラルキーにあるゲームオブジェクト
if (!EditorUtility.IsPersistent(go.transform.root.gameObject) && !(go.hideFlags == HideFlags.NotEditable || go.hideFlags == HideFlags.HideAndDontSave))
{
// ...
}
}
}
Resources.FindObjectsOfTypeAllメソッドでは、指定した型のオブジェクトをすべて取得できます。Object.FindObjectsOfTypeメソッドとは違って、無効なオブジェクトも検索できます。
その内、シーンにあるゲームオブジェクトだけを処理します。そのために、まずルートのオブジェクトをEditorUtility.IsPersistentメソッドの引数に渡しています。オブジェクトがシーンにある場合はfalseを返します。
さらに、ハイドフラッグを使って、インスペクターで編集不可のものと、ヒエラルキーに表示されずシーンに保存されないものを除外しています。
シーンにある場合、AudioSourceコンポーネントを取得します。それがnullでなく、オーディオミキサーがnullのときにリストに追加します。ヒエラルキーウィンドウの順番と揃うように、先頭に追加しています。
{
// AudioSourceを取得
var a = go.GetComponent<AudioSource>();
// AudioSourceがあって、オーディオミキサーが未設定の場合
if (a != null && a.outputAudioMixerGroup == null)
{
// リストの先頭に追加
objectsInScene.Insert(0, go);
}
クリアボタンを押すとリストをクリアします。
else if(GUILayout.Button("クリア"))
{
// リストをクリア
objectsInScene.Clear();
}
そして、リストにゲームオブジェクトがあるときは、その数だけボタンを縦に並べます。ボタン上には各ゲームオブジェクトの名前を表示し、スタイルも変更しています。
if (objectsInScene.Count > 0)
{
// 縦にレイアウト
using (new EditorGUILayout.VerticalScope())
{
// リストを一つずつ見る
for(int i = 0; i < objectsInScene.Count; i++)
{
// ボタンを表示する。ボタン上にゲームオブジェクトの名前を表示。
if (GUILayout.Button(objectsInScene[i].name, EditorStyles.textField))
{
// ボタンをクリックすると、そのゲームオブジェクトを選択する。
Selection.activeGameObject = objectsInScene[i];
}
}
}
}
ボタンをクリックすると、対応するゲームオブジェクトがヒエラルキーウィンドウで選択されます。
使ってみる
シーンにAudioSourceゲームオブジェクトを複数新規作成しました。シーンには他にカメラとディレクショナルライトがあります。
検索ボタンを押すと、オーディオソースだけがリストアップされます。エディタウィンドウ上でクリックすると、ヒエラルキーウィンドウで選択されます。
オーディオソースの条件がない場合、カメラなども表示されます。ヒエラルキーウィンドウに表示されない、InternalIdentityTransformは操作しないほうが良さそうです。
ハイドフラッグやEditorUtility.IsPersistentを使わないと、リストの要素がさらに増えました。
5つあるオーディオソースのうち、「Audio Source (2)」と「Audio Source (4)」にオーディオミキサーを設定してみます。
検索ボタンをクリックすると、オーディオミキサーを設定したゲームオブジェクトがリストから除外されました。
これで条件にあったゲームオブジェクトを素早く選択できるようになりました。
参考:https://docs.unity3d.com/ja/2019.4/ScriptReference/Resources.FindObjectsOfTypeAll.html