Unity学习之_编辑器扩展

Unity编辑器扩展是对现有的Unity进行自定义功能扩展的一种方法,可以简化一些重复的开发动作,也可以用于制作插件

unity编辑器模式

unity的编辑器扩展绝大部分是用于unity的编辑器模式下,我们扩展的方法都是为了提高开发效率,但是这些方法在游戏运行时并没有作用。不需要将他们打包进工程,所以我们需要把这些不需要打包的资源和脚本放入名字是Editor的文件夹下,这个文件夹可以是跟目录也可以是子目录只要名字不写错就可以。

MenuItem特性

这里先介绍MenuItem特性(以下仅是我知道的)

  • 添加自定义菜单项到Unity的大部分面板
  • MenuItem是能做用于静态方法,因为Unity需要通过类名来调用
  • MenuItem特性的方法可以放在任何脚本中
  • MenuItem的三个参数(string itemName, bool isValidateFunction,int priority)
    • string itemName:按钮方法的路径
    • bool isValidateFunction:默认值false,剩下的一句话说不清,看下面。。。
    • int priority:按钮在列表里的显示顺序和分组情况

在Unity菜单栏上添加自定义方法按钮
Unity学习之_编辑器扩展_第1张图片
第一步、在Editor文件夹下新建一个脚本,写上下面的代码

using UnityEngine;
using UnityEditor;

//因为这个脚本不需要作为组件存在所以不需要继承自MonoBehaviour
public class NewButton
{
    //MenuItem(string itemName,bool isValidateFunction,int priority);
    [MenuItem("NewButton/Test1",false,1)]
    static void Test1()
    {
        Debug.Log("Test1");
    }
}

菜单栏上就会显示,我们点击Test1就会运行debug方法
在这里插入图片描述
再加上几行代码

[MenuItem("NewButton/Test2",false,2)]
    static void Test2()
    {
        Debug.Log("Test2");
    }

    [MenuItem("NewButton/Test3", false, 13)]
    static void Test3()
    {
        Debug.Log("Test3");
    }

在这里插入图片描述
这里我们发现 int priority 参数越小,在菜单列表的位置越靠上,当两个相邻的int priority值的差 >=11时就会分组,这一规律也适用于系统自带的Edit GameObeject列表

假设我们现在需要一个批量删除的方法,这个方法只有在选中对象的情况下可以调用,没选中对象就无法调用
bool isValidateFunction 参数解释

[MenuItem("NewButton/MyDelete",false,14)]
    static void MyDelete()
    {
        //                      获取选中的所有对象
        foreach (Object item in Selection.objects)
        {
            //这里不能使用GameObject.Destory,因为在编辑模式下不能使用
            //可以使用GameObject.DestroyImmediate 但是建议使用下面方法
            //Undo类里面的删除方法可以撤销(ctrl z)
            Undo.DestroyObjectImmediate(item);
        }
    }

    [MenuItem("NewButton/MyDelete", true, 14)]
    static bool MyDeleteTest()
    {
        //判断是否选中对象
        if(Selection.objects.Length>0)
        {
            return true; //有返回true 执行相同路径方法
        }
        else
        {
            return false; //没有选中返回false 不执行相同路径方法
        }
    }

没有选中对象
Unity学习之_编辑器扩展_第2张图片
选中对象
Unity学习之_编辑器扩展_第3张图片
给自定以方法添加快捷键
在路径名后面+空格+下划线+快捷键(%代表ctrl #代表shift &代表alt)

[MenuItem("NewButton/Test1 _%e",false,1)]
    static void Test1()
    {
        Debug.Log("Test1");
    }

Unity学习之_编辑器扩展_第4张图片
给脚本组件添加右键扩展方法按钮
首先在场景中添加一个Cube,然后再Inspector面板上右键Box Colider组件,只有这几个选项,这时我们添加自定义方法按钮,来控制IsTrigger开关(听起来很傻,明明在Inspector就可以调整,但是这个方法可以用于所有组件包括我们自定义的脚本,并且可以修改脚本里的字段。其实最合适的用处我也没遇到,作为一个知识先学)
Unity学习之_编辑器扩展_第5张图片
添加下面代码
注意,如果有一个自定义脚本挂在多个对象上,修改只作用于当前脚本挂在的对象

 //        CONTEXT(固定写)/组件名/按钮名
    [MenuItem("CONTEXT/BoxCollider/ChangeTrigger")]
    static void ChangeCollider(MenuCommand cmd)//MenuCommand是当前正在操作的组件对象(这个参数不用传递,系统会帮传递)
    {
        //拿到对应的组件
        //这里使用(BoxCollider)转型如果失败会直接报错,使用as转型如果失败会返回Null,并且本行不会报错
        BoxCollider collider = cmd.context as BoxCollider;
        //isTrigger属性取反
        collider.isTrigger = !collider.isTrigger;

    }

效果
Unity学习之_编辑器扩展_第6张图片
对字段添加右键扩展方法
现在我们给Cube添加一个CharacterPlayer的脚本,在这个脚本里我们定义了一个health字段,
然后我们想给这个字段在Inspector面板上添加一个右键加血量的方法

using UnityEngine;

public class CharacterPlayer : MonoBehaviour
{
   //ContextMenuItem特性(“按钮名”,“方法名”)
    [ContextMenuItem("AddHealth", "AddHp")]
    public int playerHealth = 100;

    private void AddHp()
    {
        playerHealth += 10;
    }
}

效果
Unity学习之_编辑器扩展_第7张图片
通过弹出对话框对属性进行批量修改

现在我们自定义一个对话框,对我们选中的对象进行批量修改,首先把上面的cube做成一个预制体,然后把他复制100份,然后我们统一修改这些预制体,给他们的playerHealth字段+10,并且可以看到实时进度。
然后新创立一个脚本,NewWindow

介绍一下代码中用到的类
ScriptableWizard类 继承自EditorWindow

  • ScriptableWizard.DisplayWizard 静态方法用来创建对话框
  • OnWizardCreate 监听事件 监听默认按钮点击
  • OnWizardOtherButton 监听事件 监听新按钮点击
  • OnWizardUpdate 监听事件 监听面板打开 和修改面板字段
  • helpString 属性 可以设置帮助提示
  • errorString 属性 可以设置错误提示

EditorWindow类

  • OnSelectionChange 监听事件 监听当选中对象发生改变时调用
  • ShowNotification 方法 创建提示信息

EditorUtility类

  • DisplayProgressBar 静态方法 显示或更新进度条
using UnityEditor;
using UnityEngine;

//创建对话框类需要继承自:ScriptableWizard
public class NewWindow:ScriptableWizard
{
    //对话框内显示的字段
    public int Hp = 10;

    [MenuItem("NewButton/NewWindow",false,30)]
    static void CreatWizard()
    {
        //创造对话框
        //DisplayWizard是ScriptableWizard的一个静态方法               (对话框名称,默认按钮名称(不写默认名是Create),新按钮名称(不写就不显示这个按钮))
        NewWindow window = ScriptableWizard.DisplayWizard("修改血量","ChangeHp","NewButton");
    }

    //监听默认按钮按下 此按钮按下 面板会关闭
    private void OnWizardCreate()
    {
        //先拿到所有选中预制体
        GameObject[] playerfabs = Selection.gameObjects;

        //计数器
        int count = 0;
        //创建进度条窗口                (进度条名称,提示信息,                 完成百分比进度条数值 0~1,(float类型))
        EditorUtility.DisplayProgressBar("进度", count + "/" + playerfabs.Length + "完成修改", 0);

        foreach (GameObject item in Selection.gameObjects)
        {
            //拿到组件
            CharacterPlayer player = item.GetComponent();

            //记录指定Object的操作,用于撤销操作(对象,操作名)
            Undo.RecordObject(player, "change health");
            //修改血量
            player.playerHealth += Hp;

            //操作时间长点让进度条可见(废操作)
            while (Hp<10000000)
            {
                Hp += 1;
            }
            Hp= EditorPrefs.GetInt("NewWindow.Health", 10);
            
            //计数器自增
            count++;
            EditorUtility.DisplayProgressBar("进度", count + "/" + playerfabs.Length + "完成修改", (float)count / playerfabs.Length);
        }

        //关闭进度条
        EditorUtility.ClearProgressBar();

        //提示信息(EditorWindow里的方法)
        ShowNotification(new GUIContent(playerfabs.Length + "个对象值被修改"));
    }

    //监听新按钮按下 此按钮按下 面板不会关闭
    private void OnWizardOtherButton()
    {
        OnWizardCreate();
    }

    //监听面板打开 和修改面板字段
    private void OnWizardUpdate()
    {
        errorString = null;
        helpString = null;
        if (Selection.gameObjects.Length>0)
        {
            helpString = "当前选中了" + Selection.gameObjects.Length + "个对象";
        }
        else
        {
            errorString = "请至少选中一个对象";
        }
        //编辑器模式下保存数据和PlayerPrefs用法相同
        //当作字段改变,保存改变数据
        EditorPrefs.SetInt("NewWindow.Health", Hp);
    }

    //打开窗口时读取字段数据
    private void OnEnable()
    {
        Hp = EditorPrefs.GetInt("NewWindow.Health", 10);
    }

    //因为OnWizardUpdate只会在面板打开 和修改面板字段时调用,所有提示信息不能及时显示
    //OnSelectionChange是继承自EditorWindow,监听 当选中对象发生改变时调用,
    //因为ScriptableWizard是继承自EditoeWindow 所以这里可以使用
    private void OnSelectionChange()
    {
        //当选中对象发生改变后调用
        OnWizardUpdate();
    }
}

注意这类窗口可以同时打开多个
效果
Unity学习之_编辑器扩展_第8张图片
分享让知识变得有意义!后续会继续更新一些学习中问题。
OJMars
InTheMars

你可能感兴趣的:(unity学习,Unity编辑器扩展,unity,C#)