Unity 3D编辑器扩展介绍、教程(一) —— 创建菜单项

简介: Unity编辑器扩展教程本文提供全流程,中文翻译。Chinar坚持将简单的生活方式,带给世人!(拥有更好的阅读体验 —— 高分辨率用户请根据需求调整网页缩放比例)...

Unity编辑器扩展教程


本文提供全流程,中文翻译。

Chinar坚持将简单的生活方式,带给世人!

(拥有更好的阅读体验 —— 高分辨率用户请根据需求调整网页缩放比例)




Brief Introduction —— 简介


我们在做工程的时候,需要对数据进行操作。

为节省时间,会使用一些快捷键,菜单栏上的功能、或是右键菜单

这些便捷的功能,都是Unity官方为了方便我们对所需数据进行操作。

对Unity编辑进行了一些封装处理,简化数据操作流程,封装为一个按钮/一个窗口/窗口功能。

这些诸如此类的功能就是编辑器的扩展,和封装

功能键、Inspector面板、Game视窗等等都是编辑器的功能


注意:编辑器类脚本,必须放在 Assets/Editor 资源目录中

此文件夹下的脚本只对编辑器进行操作。最后资源打包,Editor文件夹下的所有资源都不会被打包到工程中

如果没有此文件夹,需自行创建:在Project视窗下,右键Create - - Folder

举个栗子黑白88

这里写图片描述

这里写图片描述


Create MenuItem —— 创建菜单项


主要使用:静态方法

MenuItem (itemName : string, isValidateFunction : bool, priority : int)


1

- - Create Level 1 Menu —— 创建一级菜单


在菜单栏上创建一个菜单项,并创建一个一级菜单按钮

注意:编辑器类脚本,必须放在 Assets/Editor 资源目录中

此文件夹下的脚本只对编辑器进行操作。最后资源打包,Editor文件夹下的所有资源都不会被打包到工程中

如果没有此文件夹,需自行创建:在Project视窗下,右键Create - - Folder

举个栗子黑白88

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


/// <summary>
/// 创建一个脚本工具类
/// </summary>
public class Tools//脚本无需继承自MonoBehaviour
{
    /// <summary>
    /// 创建新的菜单项
    /// </summary>
    /// //在菜单栏中创建一个 我的工具 菜单项目,并生成一个 “一级选项” 的按钮:需要对应一个静态方法(名字最好保持一致,不一致也可),方法体自由定义
    [MenuItem("我的工具/一级选项")] //菜单项(“菜单栏名称/子类名称”)—— 经过测试可为中文
    static void 一级选项()      //必须设置成静态方法 —— 经过测试,亦可为中文
    {
        Debug.Log(111);
    }
}

会有生成一个 一级选项 的按钮,点击后打印“111”
这里写图片描述


2

- - Create Level 2 Menu —— 创建二级菜单


在菜单栏上创建一个菜单项,并创建一个二级菜单按钮

举个栗子黑白88

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


/// <summary>
/// 创建一个脚本工具类
/// </summary>
public class Tools//脚本无需继承自MonoBehaviour
{
    /// <summary>
    /// 创建二级菜单项
    /// </summary>
    /// //在菜单栏中创建一个 我的工具 菜单项目,并生成一个 “二级选项” 的按钮:需要对应一个静态方法(名字最好保持一致,不一致也可),方法体自由定义
    [MenuItem("我的工具/一级选项/二级选项")]    //菜单项(“菜单栏名称/子类名称”)—— 经过测试可为中文
    static void 二级选项() //必须设置成静态方法 —— 经过测试,亦可为中文
    {
        Debug.Log(222);
    }
}

会有生成一个 二级选项 的按钮,点击后打印“222”
这里写图片描述


3

- - Create Level 2 Menu in System Menu —— 在系统菜单中创建二级菜单


在系统菜单 Edit 中创建二级菜单

举个栗子黑白88

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


/// <summary>
/// 创建一个脚本工具类
/// </summary>
public class Tools//脚本无需继承自MonoBehaviour
{
    /// <summary>
    /// 在系统默认的菜单项中,创建子按钮
    /// </summary>
    /// //在系统默认菜单项 Edit 中创建按钮:(名字最好保持一致,不一致也可)
    [MenuItem("Edit/一级选项/二级选项2")]    
    static void 二级选项2() 
    {
        Debug.Log(333);
    }
}

Edit 中最下方,会有生成一个 二级选项2 的按钮,点击后打印“333”
这里写图片描述


4

- - Menu grouping —— 菜单分组


完成菜单的分组,例如系统中的多个菜单项分组管理

静态方法 MenuItem (itemName : string, isValidateFunction : bool, priority : int)


MenuItem (表示菜单项:就是路径名 , 验证函数 : 同名的按钮在菜单函数调用之前调用 , 优先级:用来管理菜单项的层级关系)

注意: Priority 优先级如果设置为:-1 ,那么必然是在第一个

举个栗子黑白88

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


/// <summary>
/// 创建一个脚本工具类
/// </summary>
public class Tools//脚本无需继承自MonoBehaviour
{
    /// <summary>
    /// 菜单分组 —— 层级10
    /// </summary>
    /// //每个菜单栏的 priority 属性:优先级默认为1000。相差 11 可以分为另一个组。也就是大于10就另建一组
    [MenuItem("按钮/功能1", false, 10)] 
    static void 功能1()
    {
        Debug.Log("功能1");
    }

    /// <summary>
    /// 菜单分组 —— 层级:如果不填,系统默认为1000,所以排序在最后
    /// </summary>
    [MenuItem("按钮/功能2")]
    static void 功能2()
    {
        Debug.Log("功能2");
    }


    /// <summary>
    /// 菜单分组 —— 层级:21
    /// </summary>
    /// //与按钮1的层级10,相差11,故而分到了另一组中
    [MenuItem("按钮/功能3", false, 21)]
    static void 功能3()
    {
        Debug.Log("功能3");
    }
}

菜单栏会有生成一个 功能 的菜单项,其中有:功能1/3/2。点击后分别打印“1/3/2”
这里写图片描述


5

- - Menu display and hide. —— 菜单的显示和隐藏


完成菜单的显示和隐藏,有些时候菜单项是灰色,不可用状态/可用状态

静态方法 MenuItem (itemName : string, isValidateFunction : bool, priority : int)


验证函数 isValidateFunction 值为 true 时,此验证函数下的函数方法,会在菜单函数之前调用

满足条件,则按钮显示/否则隐藏

注意: Hierarchy 面板中,右键菜单是 菜单栏里 GameObject 的菜单项。

所以在 GameObject 菜单栏中创建一个按钮,并且优先级设置到第一组中,即可在 Hierarchy 的右键菜单中显示 该按钮

注意: Priority 优先级如果设置为:-1 ,那么必然是在第一个
举个栗子黑白88

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


/// <summary>
/// 创建一个脚本工具类
/// </summary>
public class Tools//脚本无需继承自MonoBehaviour
{
    /// <summary>
    /// 验证“删除物体”按钮的 显示/隐藏
    /// </summary>
    [MenuItem("GameObject/删除物体", true, -1)]
    static bool 删除物体Alternative()
    {
        if (Selection.objects.Length > 0)//如果选择了物体
        {
            return true;//就返回真:按钮可用
        }
        else//否则
        {
            return false;//返回假:按钮不可用
        }
    }


    /// <summary>
    /// 在系统默认的菜单项 GameObject 中,创建 删除物体 按钮,优先级第一个
    /// </summary>
    [MenuItem("GameObject/删除物体", false, -1)]
    static void 删除物体()
    {
        //Selection.objects 返回值是一个 Object数组,就是选中的所有物体
        foreach (var o in Selection.objects) //遍历选中的所有物体
        {
            //GameObject.DestroyImmediate(o);//直接删除,但是无法撤销
            Undo.DestroyObjectImmediate(o); //直接删除,但是可以撤销(用Ctrl+z)//Immediate:直接的,立即的
        }
    }
}

菜单栏 GameObject 会有生成一个 删除物体 的菜单项

如果选了物体,按钮可用

否则不可用
这里写图片描述


6

- - Shortcuts —— 快捷键


完成对菜单项目的快捷键设置

静态方法 MenuItem (itemName : string)


参数 itemName 为字符串,表示菜单项。+ 空格 + _O)就表示快捷键设为 O 键,不区分大小写
参数 itemName 为字符串,表示菜单项。+ 空格 + %l)就表示组合键设为 Ctrl+L 键,不区分大小写

注意:名字和快捷键中间必须要有空格

组合键: % : Ctrl
组合键: # : Shift
组合键: & : Altl
举个栗子黑白88

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


/// <summary>
/// 创建一个脚本工具类
/// </summary>
public class Tools//脚本无需继承自MonoBehaviour
{
       /// <summary>
    /// 快捷键测试
    /// </summary>
    [MenuItem("我的工具/快捷键测试 _o")]//_o 是指定快捷键 O ,并不区分大小写 (名字和快捷键中间必须要有空格)
    static void 选中物体个数()
    {
        Debug.Log("快捷键"+Selection.objects.Length);//打印选中物体的个数
    }


    /// <summary>
    /// 在系统默认的菜单项中,创建子按钮
    /// </summary>
    /// % : Ctrl
    /// # : Shift
    /// & : Alt
    [MenuItem("我的工具/组合键测试 %l")] //%l 是指定组合键:Ctrl+L,并不区分大小写 (名字和快捷键中间必须要有空格)
    static void 快捷键测试()
    {
        Debug.Log("组合键"+ Selection.activeGameObject.name); //打印物体名/—— 默认打印第一个选中的物体,无论选中了几个
    }
}

点击键盘按钮 O ,即可打印 “选择物体的个数”

点击键盘按钮 Ctrl + L ,即可打印 “所选物体的名字”:
如果选择多个,默认打印第一个(根据自己代码来判定,如有需要可自己写)
这里写图片描述


Create MenuItem for the Component —— 创建组件上的菜单项


主要使用:静态方法

MenuCommand : Context —— 菜单命令的目标对象


1

- - Script Component —— 在脚本组件上添加菜单项


静态方法 MenuItem (itemName : string)


参数 itemName 为字符串,表示菜单项。

参数 “CONTEXT/ PlayerHealth” 为 组件 路径

若想对某个(组件/脚本)进行操作,必须写上 “CONTEXT/ (组件/脚本)名

Undo.RecordObject (对象,键) 此函数用于记录对象之后的数据变化,没有则不能回退操作
举个栗子黑白88

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


/// <summary>
/// 玩家脚本上的工具 —— 测试脚本
/// </summary>
public class PlayerTools
{
    /// <summary>
    /// 给玩家脚本组件上添加按钮:初始化人物
    /// </summary>
    /// //[菜单项函数(“环境(组件:想要给组件上加必须要用这个来表示路径)/所需控制组件(脚本名)/需要执行的方法名(就是按钮名)”)]
    [MenuItem("CONTEXT/PlayerHealth/初始化人物")]
    static void 初始化人物(MenuCommand command) //MenuCommand 正在操作的组件对象类
    {
        CompleteProject.PlayerHealth player = (CompleteProject.PlayerHealth) command.context; //声明一个PlayerHealt对象 th  —— 需要强转为 PlayerHealth类型
        Undo.RecordObject(player, "PlayerTools_player");                                      //记录对象 player 之后的数据变化,用于回退 —— 记录对象(对象,键);//键的名字随意,不能重复//如果没有这句话,是不能退会之前的修改的
        player.startingHealth = 100;                                                          //血量初始化到100
    }
}

右键点击组件 ,选择 初始化人物 : 即可完成对血量的初始化 —— Ctrl+z,回退操作

这里写图片描述


2

- - Syetem Component —— 在系统组件上添加菜单项


静态方法 MenuItem (itemName : string)


参数 itemName 为字符串,表示菜单项。

参数 “CONTEXT/ Rigidbody” 为 组件 路径

若想对某个(组件/脚本)进行操作,必须写上 “CONTEXT/ (组件/脚本)名

Undo.RecordObject (对象,键) 此函数用于记录对象之后的数据变化,没有则不能回退操作

举个栗子黑白88

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


/// <summary>
/// 玩家脚本上的工具 —— 测试脚本
/// </summary>
public class PlayerTools
{
    /// <summary>
    /// 给系统组件 Rigidbody 上添加按钮:取消重力
    /// </summary>
    /// <param name="command"></param>
    [MenuItem("CONTEXT/Rigidbody/取消重力")]
    static void 取消重力(MenuCommand command)
    {
        Rigidbody rig = (Rigidbody) command.context; //context是一个 (正操作/鼠标下) 的组件:返回值为Object —— 强转为需要的类型
        Undo.RecordObject(rig, "PlayerTools_rig");   //记录 rig 之后的数据变化,用于回退 —— 记录对象(对象,键);//键的名字随意,不能重复//没有这句话,是不能回退,因为系统没记录
        rig.mass       = 0;                          //质量为0
        rig.useGravity = false;                      //关闭重力
    }
}

右键点击刚体组件 ,选择 取消重力: 即可完成对重力的取消 —— Ctrl+z,完成回退

这里写图片描述


3

- - ContextMenu —— 组件菜单的用法


ContextMenu ContextMenuItem 均继承自: MonoBehaviour

所以可以直接在 自义定脚本中使用,也就是工程脚本中直接用



[ContextMenuItem(按钮名,方法名)] 需要写在所需控制变量之上

[ContextMenu(按钮名)] 需要直接写在方法上

Undo.RecordObject (对象,键) 此函数用于记录对象之后的数据变化,没有则不能回退操作

举个栗子黑白88

using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;


/// <summary>
/// 玩家健康属性脚本
/// </summary>
public class PlayerHealth : MonoBehaviour
{
    [ContextMenuItem("增加血量50", "增加血量")]                    //按钮名,方法//需要写在所需控制变量之上
    public int startingHealth = 100;                            // 初始血量
       /// <summary>
        /// 直接在脚本中设置菜单项,即可在 面板中右键显示 该按钮
        /// </summary>
        [ContextMenu("设置属性")]//可以直接在脚本方法里写,需要直接写在方法上
        void 设置属性()
        {
            Debug.Log("设置属性");
        }


        /// <summary>
        /// 为变量 startingHealth 提供方法,每点击一次加 50
        /// </summary>
        void 增加血量()
        {
            Undo.RecordObject(this, "PlayerHealth_startingHealth");//记录值的改变,用于回退//(对象,键)
            startingHealth += 50;
        }
}

右键点击 PlayerHealth 脚本组件 ,即可看到按钮“设置属性”

点击 PlayerHealth 脚本组件 ,选择 startingHealth 属性,右键即可看到按钮“增加血量50”

这里写图片描述


END

本博客为非营利性个人原创,除部分有明确署名的作品外,所刊登的所有作品的著作权均为本人所拥有,本人保留所有法定权利。违者必究

对于需要复制、转载、链接和传播博客文章或内容的,请及时和本博主进行联系,留言,Email: ichinar@icloud.com

对于经本博主明确授权和许可使用文章及内容的,使用时请注明文章或内容出处并注明网址

相关文章
|
25天前
|
Rust 图形学
【unity实战】使用unity制作一个类似Rust的3D生存建造建筑系统,具有很好的吸附性(附项目源码)
【unity实战】使用unity制作一个类似Rust的3D生存建造建筑系统,具有很好的吸附性(附项目源码)
27 1
|
25天前
|
图形学
【制作100个unity游戏之25】3D背包、库存、制作、快捷栏、存储系统、砍伐树木获取资源、随机战利品宝箱10(附带项目源码)
【制作100个unity游戏之25】3D背包、库存、制作、快捷栏、存储系统、砍伐树木获取资源、随机战利品宝箱10(附带项目源码)
12 1
|
25天前
|
图形学
【实现100个unity特效之4】Unity ShaderGraph使用教程与各种特效案例(下)
【实现100个unity特效之4】Unity ShaderGraph使用教程与各种特效案例
32 0
|
25天前
|
数据可视化 图形学 开发者
【实现100个unity特效之4】Unity ShaderGraph使用教程与各种特效案例(上)
【实现100个unity特效之4】Unity ShaderGraph使用教程与各种特效案例
54 0
|
25天前
|
图形学
【推荐100个unity插件之19】武器拖尾特效插件——Pocket RPG Weapon Trails(2d 3d通用)
【推荐100个unity插件之19】武器拖尾特效插件——Pocket RPG Weapon Trails(2d 3d通用)
20 0
|
25天前
|
图形学
【unity实战】3D水系统,游泳,潜水,钓鱼功能实现
【unity实战】3D水系统,游泳,潜水,钓鱼功能实现
45 0
|
25天前
|
图形学
【制作100个unity游戏之25】3D背包、库存、制作、快捷栏、存储系统、砍伐树木获取资源、随机战利品宝箱12(附带项目源码)
【制作100个unity游戏之25】3D背包、库存、制作、快捷栏、存储系统、砍伐树木获取资源、随机战利品宝箱12(附带项目源码)
9 0
|
25天前
|
图形学
【制作100个unity游戏之28】花半天时间用unity复刻童年4399经典小游戏《黄金矿工》(附带项目源码)
【制作100个unity游戏之28】花半天时间用unity复刻童年4399经典小游戏《黄金矿工》(附带项目源码)
39 0
|
25天前
|
存储 JSON 关系型数据库
【unity实战】制作unity数据保存和加载系统——大型游戏存储的最优解
【unity实战】制作unity数据保存和加载系统——大型游戏存储的最优解
42 2
|
25天前
|
图形学
【制作100个unity游戏之29】使用unity复刻经典游戏《愤怒的小鸟》(完结,附带项目源码)(上)
【制作100个unity游戏之29】使用unity复刻经典游戏《愤怒的小鸟》(完结,附带项目源码)
41 2