0. 准备工作
- Editor文件夹(可以多个):主要用来存放编辑器下使用的一些脚本和资源,一般用来扩展Unity编辑器使用,不会发布到应用程序中,也不会在运行时运行
- Editor Default Resources文件夹(根目录唯一):用来存储编辑器下的一些默认资源,这些资源只能通过EditorGUIUtility.Load函数按需进行加载
- Editor文件夹中的子文件夹Resources:用来存储一些原型设计时可以从脚本中按需加载的资源,其中的资源需要通过Editor脚本进行加载,并会从构建发布中剥离
- Gizmos文件夹:用来存储编辑器中的特殊对象图标,用来标记特殊对象或位置,Gizmos允许将图形添加到Scene视图中,以帮助可视化不可见的设计细节。同样也不会发布到运行时
- Editor文件夹内针对编辑器组件的方法,需要设置为Static方法
1. MenuItem
- 需要引用UnityEditor命名空间
1.1 添加菜单栏按钮
[MenuItem(string path, bool? hide, int? priority)]
- 第一个参数:菜单的路径
- 第二个参数:是否为有效函数,是否需要显示
- 第三个参数:优先级,用来表示菜单按钮的先后顺序,默认值为1000。数值相差大于10会分栏
注意:需要是静态方法
- 示例:
1 | [MenuItem("MyTools/ShowMsg/msg1", false, 1000)] |
1.2 添加菜单栏按钮快捷键
符号 字符
% Ctrl/Command
# Shift
& Alt
LEFT/RIGHT/DOWN 方向键
F1-F12 F功能键
_g 字母g
- 示例:
1 | [MenuItem("MyTools/ShowMsg/msg1 %_t", false, 1000)] |
1.3 给特定组件添加右键菜单栏按钮
[MenuItem(string path)]
- 参数:按钮的路径,以”CONTEXT/[ComponentName]/“开头
- 示例:
1 | [MenuItem("CONTEXT/Rigidbody/Init")] |
1.4 获取当前操作的组件
MenuCommand
- 示例:给自定义组件Test添加右键Init按钮
1 | [MenuItem("CONTEXT/Test/Init")] |
2. Selection.objects
- 需要引用UnityEditor命名空间
- 返回场景或者Project中选择的多个对象
- 示例:
1 | [MenuItem("MyTools/DeleteAllObj &d", false)] |
3. ContextMenu
- 无需引用UnityEditor命名空间
3.1 给某组件添加右边小齿轮菜单选项
[ContextMenu(string buttonName)]
- 示例:
1 | [ContextMenu("TestFunc")] |
3.2 给某属性添加右键菜单选项
[ContextMenuItem(string buttonName, string functionName)]
- 示例:
1 | [ContextMenuItem("ChangeNum", "ChangeNumFunc")] |
4. Gizmos辅助调试工具
4.1 绘制
Gizmos是Scene窗口的可视化调试或辅助工具
可以通过两种方式实现
- 通过OnDrawGizmos或者OnDrawGizmosSelected方法,无需引用UnityEditor命名空间
- 通过DrawGizmos特性,需要引用UnityEditor命名空间
OnDrawGizmos方法:绘制效果一直显示
OnDrawGizmosSelected方法:绘制效果在选中对象时显示
DrawGizmo特性:该方法需要将该类放在Editor文件夹内,使用特性的方法可以将业务逻辑和调试脚本分开
GizmosType:
GizmosType 描述 Active 如果激活,则绘制 SelectedOrChild 如果被选择或者选择子物体时,则绘制 NotSelected 如果全没选择,则绘制 Selected 如果选择,则绘制 Pickable 在编辑器中Gizmo可以被点选
常用Gizmos的方法:
- Gizmos.DrawCube() : 绘制实体立方体
- Gizmos.DrawWireCube() : 绘制立方体边框
- Gizmos.DrawRay() : 绘制射线
- Gizmos.DrawLine() : 绘制直线
- Gizmos.DrawIcon() : 绘制Icon,Icon素材需要放在Gizmos文件夹中,代码中需要加图片后缀名
- Gizmos.DrawFrustum() : 绘制摄像机视椎体的视野范围
方式一示例:
1 | private void OnDrawGizmos() |
- 方式二示例:
1 | // 表示物体显示并且被选择状态,绘制Gizmos |
- 一直显示主摄像机视野范围示例:
1 | // 业务逻辑代码 |
5. 特性
5.1 System命名空间下的特性
- Serializable : 序列化一个类,作为一个子属性显示在监视面板
- NonSerialized : 反序列化一个变量,在监视面板上隐藏
5.2 UnityEngine命名空间下的特性
AddComponentMenu : 可以添加一个组件菜单项到编辑器里
- 效果:
- 效果:
AssemblyIsEditorAssembly : 汇编级别的属性。带了这个属性的类就被认为是编辑器类。只能对于程序集有效
ColorUsage : 可以修改Color的配置,是否显示Alpha通道,或者使用HDR模式
- 参数1:是否显示透明度(Alpha)
- 参数2:是否用HDR模式,若为true,需要下面四个参数
- 3、4:最小、最大亮度
- 5、6:最小、最大曝光
- 示例:[ColorUsageAttribute(true, true)] public Color targetColor;
ContextMenu : 给脚本的右键菜单添加一个自定义方法,不能是静态的
ContextMenuItem : 给字段的右键菜单添加一个自定义方法,不能是静态的
CreateAssetMenu : 用于Scriptable的子类,使其可以在Asset菜单项中创建
- 参数1:fileName 新创建的此类实例使用的默认文件名(创建文件必须以 .asset 结尾)
- 参数2:menuName 此类型显示的名称显示在”Asset/Create”菜单中
- 参数3:order 菜单项在”Asset/Create”菜单中的位置
- 示例:
1
2
3
4
5
6
7
8
9[CreateAssetMenu(fileName = "New Material Item", menuName = "Inventory/New Material Item")]
public class ItemMaterial : Item
{
}
public class Item : ScriptableObject
{
}
Delayed : 用于float、int或string变量,只有按了回车或焦点离开字段才会返回新值
DisallowMultipleComponent : 用于MonoBehaviour或其子类,不能重复添加这个类的组件,重复添加会弹出对话框
ExecuteInEditMode : 带了这个特性的实例会直接在编辑模式下执行,但不是像进入游戏模式那样时刻执行
- (1)Update在这个场景中任意物体变化了执行
- (2)OnGUI在Game View接收到一个Event时执行
- (3)OnRenderObject和其他渲染回调函数在Scene View或Game View重新渲染时执行
GUITarget : 选择哪些显示器调用OnGUI函数
- 示例:
1
2
3
4
5
6
7
8
9
10using UnityEngine;
public class ExampleClass1 : MonoBehaviour
{
// Label will appear on display 0 and 1 only
[GUITarget(0, 1)]
void OnGUI()
{
GUI.Label(new Rect(10, 10, 300, 100), "Visible on TV and Wii U GamePad only");
}
}
- 示例:
Header : 标题特性,给监视面板上的属性加一个小标题
HelpURL : 给类提供一个自定义文档URL,可以点击组件右上角小书或代码中按Ctrl+鼠标左键跳转到目标
HideInInspector : 在监视面板里隐藏变量,不改变序列化属性
ImageEffectAllowedInSceneView : 使用了这个特性的图像特效可以渲染在SceneView的摄像机上
ImageEffectOpaque : 可以在不透明通道直接执行图像特效
ImageEffectTransformsToLDR : 在HDR渲染模式下,使用图像特效用LDR渲染模式
- ImageEffet在Unity Pro上才有
Multiline : 可以让string变量在监视面板上多行显示
PreferBinarySerialization : 只能用于ScriptableObject子类,用二进制序列化,有利于处理大量数据的资源文件,提升读写性能。主要缺点是二进制的文件我们看不懂,并且不能用版本控制软件合并它
Property : 监视面板里面修改样式的抽象基类,例如显示小标题、显示多行编辑文本等等都是以它为基类
Range : 在监视面板里限制int或float类型的变量值
RequireComponent : 自动添加需要的组件。若已存在则不额外添加。这使得脚本可以安全的使用该组件
RPC : 用于Networking,但废弃了
RuntimeInitializeOnLoadMethod : 不用作为组件添加到对象也可以直接自动调用初始化方法。要求方法为静态,类、方法可以为私有。当游戏开始就会调用,但有多个这种特性的方法调用时,执行顺序是不能确定的
- 场景加载前调用:[RuntimeInitializeOnLoadMethodAttribute(RuntimeInitializeLoadType.BeforeSceneLoad)]
- 场景加载后调用:[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterSceneLoad)]
SelectionBase : 带这个特性的GameObject,如果点击本身就一定选中本身,即便父对象也有这特性;如果子对象没有带这个特性,则当在场景点击子对象时,选中的是带特性的父对象;如果父对象和父父对象都有这特性,选父对象
SerializeField : 序列化字段,主要用于序列化私有字段
SharedBetweenAnimators : 用于StateMachineBehaviour,类似Prefab,Animator之间共用这个实例,减少内存消耗
Space : 在监视面板上加空行
TextArea : 让string在监视面板上显示成带滚动条的文本域
- 第1参数:默认显示几行,默认值为3
- 第2参数:最多显示几行,默认值为3
- [TextArea]默认显示3行,最多显示3行,超出自动显示滚动条
- [TextArea(2,5)]默认显示2行,最多显示5行,当大于5行,会自动显示滚动条
Tooltip : 给监视面板的字段添加小贴士,即鼠标指向字段显示的提示
UnityAPICompatibilityVersion : 用来声明程序集API版本,避免处理时是否可以用旧版本的Unity API
5.3 UnityEditor命名空间下的特性
- CallbackOrder : 所有带order(顺序)回调属性的特性基类
- CanEditMultipleObjects : 使自定义编辑器支持同时编辑多个对象,一般配合CustomEditor使用类
- 示例:
- 示例:
- CustomPreview : 添加自定义类型的preview在监视面板
- CustomPropertyDrawer : 自定义属性渲染,如果要自定义PropertyDrawer或DecoratorDrawer,要加上该特性
- DrawGizmo : 自定义Gizmo渲染方法,用法见4.1方法二
- InitializeOnLoad : 当Unity工程装载时,会自动调用一个类来初始化,这个类必须有静态构造函数
- InitializeOnLoadMethod : InitializeOnLoad的静态方法
- MenuItem : 添加菜单项,必须是静态方法。第二参数若为true,则会先判断该方法是否返回true,是则可以使用,否则按钮是不可用(灰色)的
- PreferenceItem : 给Preference窗口添加菜单项,调用的也是静态方法
- 官方示例:
- 官方示例:
6. 自定义Inspector面板
- 新建一个脚本(一般命名为需要被扩展的脚本名+Editor,例如Test脚本的Inspector扩展类命名为TestEditor),脚本需要继承自Editor,我们知道自定义的Window窗口需要在OnGUI中绘制,而自定义的Inspector面板需要在OnInspectorGUI中绘制
- 案例:
1 | using UnityEngine; |
1 | using UnityEditor; |
枚举示例:
1 | public enum TaskType |
7. Inspector面板上数组或List集合的显示方式
- 新版本Unity已经实现了显示数组或List,以及可排序列表的功能
- 示例:
1 | using System.Collections.Generic; |
1 | using UnityEditor; |
- ReorderableList可以实现通过鼠标拖动,修改列表元素的排列顺序,其命名空间为UnityEditorInternal
- 更多功能参考 CSDN
8. 自定义编辑器窗口
- 示例:
1 | using UnityEditor; |
9. 具体应用
通过反射来拷贝自定义组件的字段
1 | [ ] |
编辑器拓展ScriptableObject的显示
1 | using System.Collections; |
拓展Spine插件中的Timeline轨道创建SkeletonAnimat Clip时自动引用SkeletonDataAsset
1 | /// In SpineAnimationStateTrack.cs |
拓展Spine插件中SkeletonAnimation组件的AnimationName属性的popup下拉框显示方式
1 | /// in SpineAttributeDrawers.cs void PopulateMenu(GenericMenu menu, SerializedProperty property, SpineAnimation targetAttribute, SkeletonData data) |