返回
Featured image of post Unity 编辑器扩展

Unity 编辑器扩展

Unity窗口扩展

菜单栏添加方法

基础结构

在Unity的菜单栏中添加一个可执行方法,并指定路径。效果如图:

using UnityEditor;//引用编辑器命名空间
using UnityEngine;

public class Tools
{
    [MenuItem("Tools/Test")]//引用特性,并指定路径,使Unity菜单栏上能出现对应的选项菜单
    static void Test()//执行方法必须是静态的
    {
        Debug.Log("Test~");
    }
}

MenuItem第一个参数为路径,第二个参数是否使验证函数,第三个参数优先层级(默认层级为1000)

优先层级可以设置排序顺序,当两个方法优先级相差大于10时Unity会对其进行分类(在菜单中添加横杠)

    //MenuItem第一个参数为路径,第二个参数是否使验证函数,第三个参数优先层级(默认层级为1000)
    [MenuItem("Tools/Test1", false, 0)]//引用特性,并指定路径,使Unity菜单栏上能出现对应的选项菜单
    static void Test1()//执行方法必须是静态的
    {
        Debug.Log("Test~");
    }

    [MenuItem("Tools/Test2", false, 5)]
    static void Test2() { }

    [MenuItem("Tools/Test3", false, 16)]
    static void Test3() { }

右击选项

  • 在Project面板中添加右击选项Test4

        [MenuItem("Assets/Test4")]
        static void Test4() { }
    
  • 在Hierarchy面板中添加右击选项Test5

    [MenuItem("GameObject/Test5",false,10)]
    static void Test5() { }
  • 在组件上添加右击选项Test6

    [MenuItem("CONTEXT/Transform/Test6")]// CONTEXT 组件名 按钮名
    static void Test6(MenuCommand cmd)//MenuCommand 是当前正在操作的组件,不需要赋值,Unity会自动找到该组件
    {
        //需要将MenuCommand进行强制转型,转换成操作的组件
        //需要注意转型对象命名空间,命名空间错误会导致转型不成功
        Transform transform = cmd.context as Transform;
        transform.position = Vector3.zero;
    }

选择对象并删除

	[MenuItem("Tools/Test7", false, 100)]
    static void Test7()
    {
        //Selection.objects返回当前选中的目标对象
        foreach (var item in Selection.objects)
        {
            //编辑模式下需要使用DestroyImmediate代替Destroy操作
            //GameObject.DestroyImmediate(item);
            //运用Undo进行删除操作可以在Unity中撤销
            Undo.DestroyObjectImmediate(item);
        }
    }

添加快捷键

    //_=不加组合键 %=ctrl #=shift &=alt
    [MenuItem("Tools/Test8 %t")]//路径后面添加空格,在添加组合键前缀符,在添加按键字母(小写)
    static void Test8()
    {
        Debug.Log("Test8~");
    }

按钮失活

    //验证方法
    [MenuItem("Tools/Test9", true, 10)]
    static bool Test9Validate()
    {
        //如果没有选中对象,则Test9按键失活
        if (Selection.objects.Length>0)
        {
            return true;
        }
        return false;
    }
    [MenuItem("Tools/Test9", false, 10)]
    static void Test9() { }

组件右击选项

与前面右击选项不同的是,接下来添加的方法是直接在组件脚本中添加。

组件添加右击选项归零

组件字段Num添加右击选项递增

public class TestEditor : MonoBehaviour
{
    [ContextMenuItem("递增","AddNum")]//该特性可以为组件的字段增加右击选项,【按钮名,执行方法名】
    public int Num;

    void AddNum()
    {
        Num++;
    }

    [ContextMenu("归零")]//该特性可以直接为组件增加右击选项
    void SetZero()
    {
        Num = 0;
    }
}

脚本窗口

一个简单的脚本窗口,可以实现对选中物体的TestEditor组件的Num属性修改

public class AttributeChange : ScriptableWizard//需要继承自ScriptableWizard
{
    //创建对话框
    [MenuItem("Tools/CreateWizard", false, 1100)]
    static void CreateWizard()
    {
        //创建一个脚本窗口【名称,Create按钮名称,OtherButton按钮名称】(默认OtherButton不命名是不会存在的)
        ScriptableWizard.DisplayWizard<AttributeChange>("修改属性面板", "Change Value","Other Btn");
    }

    public int ChangeNumA = 10;
    const string NumA = "NumA";

    private void OnEnable()
    {
        //读取数据
        ChangeNumA= EditorPrefs.GetInt(NumA, ChangeNumA);
    }

    //Create按钮事件
    private void OnWizardCreate()
    {
        //获取选中物体
        GameObject[] Prefabes = Selection.gameObjects;

        //创建进度条
        EditorUtility.DisplayProgressBar("进度", "0/" + Prefabes.Length + "完成修改值", 0);
        int count = 0;
        
        foreach (var item in Prefabes)
        {
            //获取物体身上的组件
            TestEditor testEditor = item.GetComponent<TestEditor>();
            //撤销记录快门,之后对组件所有修改会被记录
            Undo.RecordObject(testEditor, "修改数值");
            testEditor.Num = ChangeNumA;

            //刷新进度条
            count++;
            EditorUtility.DisplayProgressBar("进度", "0/" + Prefabes.Length + "完成修改值",(float)count/ Prefabes.Length);
        }
        //关闭进度条
        EditorUtility.ClearProgressBar();

        //渐变提示框
        ShowNotification(new GUIContent(Prefabes.Length + "个物体值被修改了"));
    }

    //OtherButton与WizardCreate不同之处在于触发事件后不会关闭窗口
    private void OnWizardOtherButton()
    {
        OnWizardCreate();
    }

    //当面板字段被修改和被创建时调用
    private void OnWizardUpdate()
    {
        
    }

    //选择对象修改时调用
    private void OnSelectionChange()
    {
        //提示信息
        helpString = null;
        errorString = null;
        if (Selection.gameObjects.Length>0)
        {
            helpString = "您当前选择了" + Selection.gameObjects.Length + "个对象";
        }
        else
        {
            errorString = "请选择至少一个对象";
        }

        //保存数据
        EditorPrefs.SetInt(NumA, ChangeNumA);
    }
}

下面总结一些关键功能

  • 渐变提示框
ShowNotification(new GUIContent(Prefabes.Length + "个物体值被修改了"));
  • 进度条

            //创建进度条
            EditorUtility.DisplayProgressBar("进度", "0/" + Prefabes.Length + "完成修改值", 0);
            //刷新进度条
            count++;
            EditorUtility.DisplayProgressBar("进度", "0/" + Prefabes.Length + "完成修改值",(float)count/ Prefabes.Length);
            //关闭进度条
            EditorUtility.ClearProgressBar();
    
  • 提示信息

          //提示信息
            helpString = null;
            errorString = null;
    
  • 保存/读取Unity缓存数据

      public int ChangeNumA = 10;
        const string NumA = "NumA";
    
        private void OnEnable()
        {
            //读取数据
            ChangeNumA= EditorPrefs.GetInt(NumA, ChangeNumA);
            //保存数据
          EditorPrefs.SetInt(NumA, ChangeNumA);
        }   
    
    
  • 撤销

              //获取物体身上的组件
              TestEditor testEditor = item.GetComponent<TestEditor>();
              //撤销记录快门,之后对组件所有修改会被记录
              Undo.RecordObject(testEditor, "修改数值");
    

窗口控件

  • 显示文本

    GUILayout.Label($"AppId:");

  • 水平垂直布局

    //建立水平布局
    GUILayout.BeginHorizontal();
    
  • 下拉选框

    //依据string下拉选框
    int selectedIndex = EditorGUILayout.Popup(this.selectedIndex, filesArray);
    //依据枚举下拉选框
    startConfig.AppType = (AppType)EditorGUILayout.EnumPopup(startConfig.AppType);
    
  • 滚动框

    Vector2 scrollPos = GUILayout.BeginScrollView(this.scrollPos, true, true);

Licensed under CC BY-NC-SA 4.0
0