【Unity】Collider のアタッチされた Prefab をリストアップするツール

はじめに

画像のように Collider のアタッチされた Prefab をリストアップします。
子 GameObject にアタッチされている場合は, Root の GameObject からのパスを表示します。

ソースコード

public class ColliderListWindow : ComponentListWindow<Collider>
{
    [MenuItem("EditorWindow/ColliderListWindow")]
    private static void Init()
    {
        var window = GetWindow(typeof(ColliderListWindow));
        window.titleContent = new GUIContent(nameof(ColliderListWindow));
        window.Show();
        window.minSize = new Vector2(330, 400);
    }
}

public class ComponentListWindow<T> : EditorWindow where T : Component
{
    private SingleTreeView m_TreeView;
    private TreeViewState m_TreeViewState;
    private List<UnityObjectModel> m_ModelList = new();

    private void OnEnable()
    {
        m_TreeViewState = new TreeViewState();
        m_TreeView = new SingleTreeView(m_TreeViewState);
        if (m_ModelList.Count == 0)
        {
            m_ModelList.Add(UnityObjectModelFactory.instance.CreateEmpty());
        }

        m_TreeView.Setup(m_ModelList);
    }

    private void OnGUI()
    {
        if (GUILayout.Button("実行"))
        {
            m_ModelList.Clear();

            var paths = AssetDatabase.FindAssets("a: assets t:Prefab")
                .Select(guid => AssetDatabase.GUIDToAssetPath(guid))
                .ToList();

            for (int i = 0; i < paths.Count(); i++)
            {
                var path = paths[i];
                var asset = AssetDatabase.LoadAssetAtPath<GameObject>(path);
                foreach (var child in asset.GetComponentsInChildren<T>())
                {
                    var name = GetPath(child.transform);
                    var model = UnityObjectModelFactory.instance.CreateModel(name, child);
                    m_ModelList.Add(model);
                }
            }

            m_TreeView.Setup(m_ModelList);
        }

        var rect = EditorGUILayout.GetControlRect(false, GUILayout.ExpandHeight(true));
        m_TreeView.OnGUI(rect);
    }

    public static string GetPath(Transform transform)
    {
        var result = transform.name;
        var parent = transform.parent;
        while (parent != null)
        {
            result = parent.name + "/" + result;
            parent = parent.parent;
        }

        return result;
    }
}

public class SingleTreeView : TreeView
{
    private List<UnityObjectModel> m_ModelList;

    public SingleTreeView(TreeViewState treeViewState) : base(treeViewState)
    {
        showAlternatingRowBackgrounds = true;
    }

    public void Setup(List<UnityObjectModel> modelList)
    {
        m_ModelList = modelList;
        Reload();
    }

    protected override TreeViewItem BuildRoot()
    {
        var root = new TreeViewItem { id = 0, depth = -1, displayName = "Root" };
        foreach (var model in m_ModelList)
        {
            var baseItem = new TreeViewItem { id = model.Id, displayName = model.Name, icon = model.Icon };
            root.AddChild(baseItem);
        }

        SetupDepthsFromParentsAndChildren(root);
        return root;
    }
}

public class UnityObjectModelFactory : ScriptableSingleton<UnityObjectModelFactory>
{
    [SerializeField]
    private int m_IdCounter;

    public UnityObjectModel CreateModel(string name, Object unityObject)
    {
        m_IdCounter++;
        var model = new UnityObjectModel(m_IdCounter, name, unityObject);
        return model;
    }

    public UnityObjectModel CreateEmpty()
    {
        m_IdCounter++;
        return new UnityObjectModel(m_IdCounter, "なし", null);
    }
}

public class UnityObjectModel
{
    private int m_Id;
    private string m_Name;
    private List<UnityObjectModel> m_Children = new();
    private Object m_UnityObject;
    private Texture2D m_Icon;

    public int Id => m_Id;
    public string Name => m_Name;
    public Object UnityObject => m_UnityObject;
    public Texture2D Icon => m_Icon;
    public List<UnityObjectModel> Children => m_Children;

    public UnityObjectModel(int id, string name, Object unityObject)
    {
        m_Id = id;
        m_Name = name;
        m_UnityObject = unityObject;
        if (m_UnityObject != null)
        {
            m_Icon = (Texture2D)EditorGUIUtility.ObjectContent(m_UnityObject, m_UnityObject.GetType()).image;
        }
    }

    public void AddChild(UnityObjectModel singleTreeViewModel) => m_Children.Add(singleTreeViewModel);
}