今回はUnityのエディター拡張をしていきます。
最近エディター拡張を書くことが多いので、自分用の忘備録です。
やること
Projectビューの指定のフォルダにあるPrefabを検索し、それをScriptのListに格納する
開発環境
Unity 2021.3.12f1
事前準備
先に格納したいPrefabを作成します。
Assets/Prefabsフォルダを作成し、適当にGameObjectをPrefab化しておきます。
Scriptの作成
以下のScriptを作成します。
ObjectList.cs
GameObject型のListがあるScript。
Listを設定する関数と空にする関数を持つ。
using System.Collections.Generic; using UnityEngine; public class ObjectList : MonoBehaviour { [SerializeField] List<GameObject> m_List = new List<GameObject>(); /// <summary> /// GameObjectのListを受け取りm_Listに格納する /// </summary> /// <param name="objects"></param> public void SetObjects(List<GameObject> objects) { m_List = objects; } /// <summary> /// m_Listを空にする /// </summary> public void Clear() { m_List.Clear(); } }
ObjectListEditor.cs
ObjectList.csのエディター拡張Script。
プレハブをロードしてListに格納するボタンと、Listを空にするボタンを表示する。
using System.Linq; using UnityEngine; using UnityEditor; [CustomEditor(typeof(ObjectList))] public class ObjectListEditor : Editor { public override void OnInspectorGUI() { base.OnInspectorGUI(); var objectList = target as ObjectList; if(GUILayout.Button("プレハブロード")) { LoadPrefabs(objectList); EditorUtility.SetDirty(objectList); } if(GUILayout.Button("クリア")) { objectList.Clear(); EditorUtility.SetDirty(objectList); } } /// <summary> /// プレハブのロード /// </summary> static public void LoadPrefabs(ObjectList objectList) { // ロード先のディレクトリパス var path = "Assets/Prefabs"; var guids = AssetDatabase.FindAssets("t:GameObject", new string[] { path }); var paths = guids.Select(guid => AssetDatabase.GUIDToAssetPath(guid)).ToArray(); var list = paths.Select(_ => AssetDatabase.LoadAssetAtPath<GameObject>(_)).ToList(); if(list.Count == 0) { Debug.LogWarning("プレハブがない\n" + "検索パス[" + path + "]"); return; } Debug.Log("プレハブを検索:" + list.Count + "つ格納\n" + "検索パス[" + path + "]"); objectList.SetObjects(list); } }
これで完成
実行
空のGameObjectを作成し、ObjectListをアタッチするとボタンが表示されます。
ロードボタンを押すと、指定のフォルダにあるPrefabをListに格納します。
調整
以下細かい調整
読み込むフォルダの変更
ObjectListEditor.csのLoadPrefabsにある
var path = "Assets/Prefabs";
でディレクトリパスを指定しているのでここを書き換えればよし。
ここも指定できるようにしていいかも。
特定のコンポーネントがアタッチされているPrefabのみ格納する
Prefabを検索する時、特定コンポーネントがあるかWhere句を挟むとよい。
例えば、RigidbodyがアタッチされているPrefabだけ格納したいならこうする。
// 特定のコンポーネントがあるものだけ格納
var list = paths.Select(_ => AssetDatabase.LoadAssetAtPath<GameObject>(_))
.Where(_ => _.TryGetComponent(out Rigidbody rigidbody))
.ToList();
/// <summary> /// プレハブのロード /// </summary> static public void LoadPrefabs(ObjectList objectList) { // ロード先のディレクトリパス var path = "Assets/Prefabs"; var guids = AssetDatabase.FindAssets("t:GameObject", new string[] { path }); var paths = guids.Select(guid => AssetDatabase.GUIDToAssetPath(guid)).ToArray(); // 特定のコンポーネントがあるものだけ格納 var list = paths.Select(_ => AssetDatabase.LoadAssetAtPath<GameObject>(_)) .Where(_ => _.TryGetComponent(out Rigidbody rigidbody)) .ToList(); if(list.Count == 0) { Debug.LogWarning("プレハブがない\n" + "検索パス[" + path + "]"); return; } Debug.Log("プレハブを検索:" + list.Count + "つ格納\n" + "検索パス[" + path + "]"); objectList.SetObjects(list); }
AssetDatabase.FindAssets()のフィルタを使えばもっと簡単にできそうだけど、
なぜかうまくいかないのでLINQで対応しています。
まとめ
指定のフォルダにあるPrefabを検索し、ScriptのListに格納するエディター拡張を作りました。
Inspectorを拡張し、格納するボタンを配置しています。
Scriptを編集することで、対象のフォルダや格納するPrefabの条件を設定できます。
以上です。
参考資料