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

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

相关文章
|
3月前
Axure设计之文本编辑器制作教程
本文介绍如何在Axure中模拟Web端富文本编辑器,实现基本的文本编辑功能,包括自定义字体样式、大小、颜色及对齐方式等。通过拖入矩形、文本域等元件,添加单选框和图标,并设置相应的交互,完成文本编辑器的制作。
115 2
|
10天前
|
图形学
Unity 获取鼠标位置下的UGUI或3D物体
本文总结了两种检测方法,分别用于UGUI和3D物体的检测。第一种方法`GetOverUIobj`专门用于检测鼠标悬停的UGUI元素,通过`GraphicRaycaster`实现。第二种方法`GetOverWordGameObject`则同时适用于UI和3D物体检测,利用`PhysicsRaycaster`进行射线检测。两者均返回悬停对象或null。
|
10天前
|
前端开发 图形学
unity UGUI跟随3D物体的坐标转换
在 Unity 中实现 UGUI 元素跟随 3D 物体,关键是将 3D 物体的世界坐标转换为屏幕或画布坐标。通过 Camera.WorldToScreenPoint 方法,可将 3D 物体位置映射到屏幕上,再更新 UGUI 元素的位置。代码示例展示了如何使用该方法,使 UGUI 图像跟随 3D 模型,并提供文字显示、图像和线条的显示/隐藏功能。
|
11天前
|
图形学 开发者
Unity编辑器脚本(添加/删除)碰撞盒
这段代码提供了两个Unity编辑器工具,用于批量处理模型的碰撞盒。一是“一键添加所有碰撞盒”,通过选择模型的父物体,自动为其子物体添加`MeshCollider`。二是“一键清理所有Collider碰撞盒”,同样选择父物体后,递归删除子物体上的`BoxCollider`组件。两者均通过Unity的菜单项实现便捷操作,方便开发者快速调整场景中的物理属性。
|
3月前
|
缓存 API 开发工具
有关Unity使用Rider编辑器无法弹出代码提示的有效解决方法
【11月更文挑战第13天】在 Unity 中使用 Rider 编辑器时,若遇到代码提示无法弹出的问题,可以通过检查 Rider 设置(如自动补全选项、Unity 插件安装、索引设置)、Unity 项目设置(如解决方案正确关联、脚本导入设置)以及环境和依赖关系(如 .NET SDK 版本兼容性、Unity 和 Rider 版本兼容性)等方面进行排查和解决。
475 5
|
4月前
|
Web App开发 JavaScript 前端开发
用来用去还是用回了ueditor-Vue富文本编辑器二次扩展
用来用去还是用回了ueditor-Vue富文本编辑器二次扩展
71 11
|
4月前
|
存储 移动开发 小程序
uniapp富文本editor输入二次扩展兼容微信小程序
uniapp富文本editor输入二次扩展兼容微信小程序
169 0
|
5月前
|
设计模式 存储 人工智能
深度解析Unity游戏开发:从零构建可扩展与可维护的游戏架构,让你的游戏项目在模块化设计、脚本对象运用及状态模式处理中焕发新生,实现高效迭代与团队协作的完美平衡之路
【9月更文挑战第1天】游戏开发中的架构设计是项目成功的关键。良好的架构能提升开发效率并确保项目的长期可维护性和可扩展性。在使用Unity引擎时,合理的架构尤为重要。本文探讨了如何在Unity中实现可扩展且易维护的游戏架构,包括模块化设计、使用脚本对象管理数据、应用设计模式(如状态模式)及采用MVC/MVVM架构模式。通过这些方法,可以显著提高开发效率和游戏质量。例如,模块化设计将游戏拆分为独立模块。
304 3
|
6月前
|
图形学 开发者 存储
超越基础教程:深度拆解Unity地形编辑器的每一个隐藏角落,让你的游戏世界既浩瀚无垠又细节满满——从新手到高手的全面技巧升级秘籍
【8月更文挑战第31天】Unity地形编辑器是游戏开发中的重要工具,可快速创建复杂多变的游戏环境。本文通过比较不同地形编辑技术,详细介绍如何利用其功能构建广阔且精细的游戏世界,并提供具体示例代码,展示从基础地形绘制到植被与纹理添加的全过程。通过学习这些技巧,开发者能显著提升游戏画面质量和玩家体验。
303 3
|
6月前
|
开发者 图形学 开发工具
Unity编辑器神级扩展攻略:从批量操作到定制Inspector界面,手把手教你编写高效开发工具,解锁编辑器隐藏潜能
【8月更文挑战第31天】Unity是一款强大的游戏开发引擎,支持多平台发布与高度可定制的编辑器环境。通过自定义编辑器工具,开发者能显著提升工作效率。本文介绍如何使用C#脚本扩展Unity编辑器功能,包括批量调整游戏对象位置、创建自定义Inspector界面及项目统计窗口等实用工具,并提供具体示例代码。理解并应用这些技巧,可大幅优化开发流程,提高生产力。
550 1

热门文章

最新文章