Unity编辑器扩展教程


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

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

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



Brief Introduction —— 简介

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

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

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

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

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

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



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

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

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


Create MenuItem —— 创建菜单项


主要使用:静态方法

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


1

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

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

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

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

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

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 —— 创建二级菜单

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

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 中创建二级菜单

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 ,那么必然是在第一个

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 ,那么必然是在第一个

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

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 (对象,键) 此函数用于记录对象之后的数据变化,没有则不能回退操作

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 (对象,键) 此函数用于记录对象之后的数据变化,没有则不能回退操作

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 (对象,键) 此函数用于记录对象之后的数据变化,没有则不能回退操作

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


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

Unity 3D编辑器扩展介绍、教程(一) —— 创建菜单项的更多相关文章

  1. Unity 3D编辑器扩展介绍、教程(二) —— 创建窗口

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

  2. Cocos2d-X中创建菜单项

    Cocos2d-X中创建菜单的类: CCMenuItemFont:创建纯文本的菜单项 CCMenuItemAtlasFont:创建带有艺术字体的菜单项 CCMenuItemImage:用图片创建菜单项 ...

  3. Unity 3D UGUI Toggle用法教程

    UGUI Toggle用法教程 本文提供全流程,中文翻译. Chinar 坚持将简单的生活方式,带给世人!(拥有更好的阅读体验 -- 高分辨率用户请根据需求调整网页缩放比例) Chinar -- 心分 ...

  4. unity shader 编辑器扩展类 ShaderGUI

    这应该unity5才出的新功能了,今天看文档时刚巧看到了,就来尝试了一下. 效果如图: shader 的编辑器扩展分为2种方法: 是通过UnityEditor下的ShaderGUI类来实现的,形式比较 ...

  5. Eclipse扩展点实践之添加菜单项(ActionSet方式实现)

    ActionSet方式比起Command方式,比较直观,但是功能有限. 首先:新建一个项目,在Extension中添加org.eclipse.ui.actionSets的扩展. 然后,new-> ...

  6. Unity 3D入门简介

    最近在刚开始学习Unity 3D,在这里记录一下学习心得和学习笔记,边学边写,可能会比较零散.好了,废话不多说,今天从Unity 3D入门写起,主要简要介绍一下Unity 3D的和一些学习资料.以下如 ...

  7. Unity 3D类结构简介

    趁着周末,再来一发.对于Unity3D,我也是刚开始学习,希望能够与大家多多交流.好了,废话不多说,下面继续. 本篇文章使用C#进行举例和说明.关于Unity 3D编辑器中的各种窗口,网上有很多资料了 ...

  8. Unity 3D使用GameObject创建一个简单的可移动物体

    于Unity 3D游戏的开发.游戏脚本需要3D模拟组合,该脚本将被写入阻力3D为了达到效果对象. 以下是一个小实例,使用Unity 3D实现一个可控制移动的小人.小人能够向前.向后.向左和向右移动. ...

  9. Unity编辑器扩展

    在开发中有可能需要自己开发编辑器工具,在Unity中界面扩展常见两种情况,拿某插件为例: 1,自建窗口扩展 2,脚本Inspector显示扩展 不管使用那种样式,都需要经常用到两个类EditorGUI ...

随机推荐

  1. zlib__ZC

    官网:http://www.zlib.net/ ,所有版本下载:http://www.zlib.net/fossils/ ZC: 我下载的是 zlib-1.2.3.tar.gz 和 zlib-1.2. ...

  2. Fisher线性判别分析

    Fisher线性判别分析 1.概述 在使用统计方法处理模式识别问题时,往往是在低维空间展开研究,然而实际中数据往往是高维的,基于统计的方法往往很难求解,因此降维成了解决问题的突破口. 假设数据存在于d ...

  3. 1 python基础知识

    一.python简介 编译型:将所有的源码先编译成机器型语言,并保存为二进制文件,然后一次性执行c c++ go swift 解释型:将代码一行一行边编译边解释python javascript ph ...

  4. ssh The authenticity of host '10.11.26.2 (10.11.26.2)' can't be established

    The authenticity of host '10.11.26.2 (10.11.26.2)' can't be established. ECDSA key fingerprint is SH ...

  5. python-day37--协程

    一. 协程介绍 单线程下实现并发,提升运行效率, 1.自己控制切换,保存状态 2.遇到I/O切         (单纯的CPU切没意义,只有在遇到I/O的时候切才有效率) 一句话说明什么是线程:协程是 ...

  6. python-day18--匿名函数

    一.lambda表达式 1.匿名函数的核心:一些简单的需要用函数去解决的问题,匿名函数的函数体只有一行 2.参数可以有多个,用逗号隔开 3.返回值和正常的函数一样可以是任意的数据类型 4.练习: 请把 ...

  7. python-day13--装饰器

    1.开放封闭的原则: 1.对扩展是开放的 为什么要对扩展开放呢? 我们说,任何一个程序,不可能在设计之初就已经想好了所有的功能并且未来不做任何更新和修改.所以我们必须允许代码扩展.添加新功能. 2.对 ...

  8. 巧妙利用SVN 实现复制需要部署的文件。

    http://blog.csdn.net/xiaoding133/article/details/39252357 http://blog.csdn.net/sinat_29173167/articl ...

  9. JAVA 中CLOB与Clob有区别

    在JAVA中CLOB与Clob是有区别的类型. (oracle.jdbc.internal.OracleCallableStatement)OracleCallableStatement能接收CLOB ...

  10. 标准的EO验证提示错误不够完整,抛出自定义的异常。

    我们通常会在EO里面对某些数据进行验证,比如在邀请供应商注册的时候,ORACLE标准逻辑会验证被邀请的供应商是否已经存在. 其验证逻辑在 oracle.apps.pos.schema.server.S ...