Odin-Inspector-系列教程—–【小工具】ScriptableObjectCreator

本工具是基于Odin,为创建ScriptableObject对应的asset文件制作的菜单,即开即用
示例代码已经做好注释,易于理解、魔改
转载自:https://bitbucket.org/snippets/Bjarkeck/keRbr4

using Sirenix.OdinInspector.Editor;
using Sirenix.Utilities;
using Sirenix.Utilities.Editor;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using UnityEditor;
using UnityEngine;

public class ScriptableObjectCreator : OdinMenuEditorWindow
{
    /// 
    /// 获取继承 ScriptableObject 且不是Editor相关的所有自定义类(也就是自己编写的类)
    /// 
    static HashSet scriptableObjectTypes = AssemblyUtilities.GetTypes(AssemblyTypeFlags.CustomTypes)
        .Where(t =>
            t.IsClass &&
            typeof(ScriptableObject).IsAssignableFrom(t) &&
            !typeof(EditorWindow).IsAssignableFrom(t) &&
            !typeof(Editor).IsAssignableFrom(t))
       .ToHashSet();

    [MenuItem("Assets/Create Scriptable Object", priority = -1000)]
    private static void ShowDialog()
    {
        var path = "Assets";
        var obj = Selection.activeObject; //当前鼠标选中的 Object
        if (obj && AssetDatabase.Contains(obj))
        {
            path = AssetDatabase.GetAssetPath(obj);
            if (!Directory.Exists(path))//主要用来判断所选的是文件还是文件夹
            {
                path = Path.GetDirectoryName(path);//如果是文件则获取对应文件夹的全名称
            }
        }
        //设置窗口对应属性
        var window = CreateInstance();
        window.position = GUIHelper.GetEditorWindowRect().AlignCenter(800, 500);//设置窗口的宽和高
        window.titleContent = new GUIContent(path);
        window.targetFolder = path.Trim('/');//避免出现 / 造成路径不对
        window.ShowUtility();
    }

    /// 
    /// 选中的 ScriptableObject(等待创建)
    /// 
    private ScriptableObject previewObject;
    /// 
    /// 创建 ScriptableObject 时文件存储的目标文件夹
    /// 
    private string targetFolder;
    private Vector2 scroll;

    private Type SelectedType
    {
        get
        {
            var m = MenuTree.Selection.LastOrDefault();//因为可以多选,所以返回选中的是一个列表,这里返回的是列表的最后一个Object
            return m == null ? null : m.Value as Type;
        }
    }

    protected override OdinMenuTree BuildMenuTree()
    {
        MenuWidth = 300;//菜单的宽度
        WindowPadding = Vector4.zero;

        OdinMenuTree tree = new OdinMenuTree(false);//不支持多选
        tree.Config.DrawSearchToolbar = true;//开启搜索状态
        tree.DefaultMenuStyle = OdinMenuStyle.TreeViewStyle;//菜单设置成树形模式

        //筛选所有非抽象的类 并获取对应的路径
        tree.AddRange(scriptableObjectTypes.Where(x => !x.IsAbstract), GetMenuPathForType).AddThumbnailIcons();
        tree.SortMenuItemsByName();
        tree.Selection.SelectionConfirmed += x => 
        {
            Debug.Log($"双击确认并创建:{x}");
            this.CreateAsset();
        };
        tree.Selection.SelectionChanged += e =>
        {
            //每当选择发生更改时发生进行回调2次,一次SelectionCleared 一次是ItemAdded
            if (this.previewObject && !AssetDatabase.Contains(this.previewObject))
            {
                DestroyImmediate(previewObject);
            }

            if (e != SelectionChangedType.ItemAdded)
            {
                return;
            }

            var t = SelectedType;
            if (t != null && !t.IsAbstract)
            {
                previewObject = CreateInstance(t) as ScriptableObject;
            }
        };
        return tree;
    }

    private string GetMenuPathForType(Type t)
    {
        if (t != null && scriptableObjectTypes.Contains(t))
        {
            var name = t.Name.Split('').First().SplitPascalCase();//主要是为了去除泛型相关 例如:Sirenix.Utilities.GlobalConfig1[Sirenix.Serialization.GlobalSerializationConfig]
            return GetMenuPathForType(t.BaseType) + "/" + name;
        }
        return "";
    }

    protected override IEnumerable GetTargets()
    {
        yield return previewObject;
    }

    protected override void DrawEditor(int index)
    {
        //scroll 内容滑动条的XY坐标
        scroll = GUILayout.BeginScrollView(scroll);
        {
            base.DrawEditor(index);
        }
        GUILayout.EndScrollView();

        if (this.previewObject)
        {
            GUILayout.FlexibleSpace();//插入一个空隙
            SirenixEditorGUI.HorizontalLineSeparator(5);//插入一个水平分割线
            if (GUILayout.Button("Create Asset", GUILayoutOptions.Height(30)))
            {
                CreateAsset();
            }
        }
    }

    private void CreateAsset()
    {
        if (previewObject)
        {
            var dest = targetFolder + "/new " + MenuTree.Selection.First().Name.ToLower() + ".asset";
            dest = AssetDatabase.GenerateUniqueAssetPath(dest);//创建唯一路径 重名后缀 +1
            Debug.Log($"要创建的为{previewObject}");
            AssetDatabase.CreateAsset(previewObject, dest);
            AssetDatabase.SaveAssets();
            AssetDatabase.Refresh();
            Selection.activeObject = previewObject;
            EditorApplication.delayCall += Close;//如不需要创建后自动关闭可将本行注释
        }
    }
}

更多教程内容详见:革命性Unity 编辑器扩展工具 — Odin Inspector 系列教程

发表评论