Unity提供了灵活多变的编辑器拓展API接口,通过代码反射,可以修改一些系统自带的编辑器窗口。此外,丰富的EditorGUI接口也可以拓展出各式各样的编辑器窗口。
拓展Project视图
属于编辑模式下的代码,需要放在Editor文件夹下;属于运行时执行的代码,放在任意非Editor文件夹下即可。Editor文件夹的位置比较灵活,它还可以作为多个目录的子文件夹存在,这样开发者就可以按功能来划分,将不同功能的编辑代码放在不同的Editor目录下。例如可以有多个Editor目录,它们各自处理各自的逻辑。
拓展右键菜单
选中资源
1 | using UnityEngine; |
Create按钮
1 | using UnityEngine; |
拓展布局
在右侧拓展自定义按钮,在代码中既可以设置拓展按钮的区域,也可监听按钮的点击事件。
在方法前面添加[InitializeOnLoadMethod]表示此方法会在C#代码每次编译完成后首先调用。监听EditorApplication.projectWindowItemOnGUI委托,即可使用GUI方法来绘制自定义的UI元素。GUI还提供了丰富的元素接口,可以用来添加文本、图片、滚动条和下拉框等复杂元素。
1 | using UnityEngine; |
监听事件
1 | using UnityEngine; |
拓展Hierarchy视图
Hierarchy视图中出现的都是游戏对象,这些对象之间同样具有一定的关联关系。Hierarchy视图中的游戏对象会通过摄像机最终投影在发布的游戏中。
拓展菜单
1 | using UnityEngine; |
拓展布局
1 | using UnityEngine; |
重写菜单
1 | using UnityEngine; |
在上述代码中,使用Event.current来获取当前的事件。当监听到鼠标抬起的事件后,并且满足游戏对象的选中状态,开始执行自定义事件。其中,EditorUtility.DisplayPopupMenu用于弹出自定义菜单,Event.current.Use()的含义是不再执行原有的操作,所以就实现了重写菜单。
此外,Hierarchy视图还可以重写系统自带的菜单行为。例如,觉得Unity创建的Image组件不好,可以复写它的行为。创建Image组件时,会自动勾选RaycastTarget。如果图片不需要处理点击事件,这样会带来一些额外的开销。下面的代码让RaycastTarget默认不勾选。由于重写了菜单,所以需要通过脚本自行创建Image对象和组件。接着,获取到image组件对象,直接设置它的raycastTarget属性即可。
1 | using UnityEngine; |
拓展Inspector视图
拓展源生组件
摄像机就是典型的源生组件。可以在摄像机组件的最上面添加一个按钮。它的局限性就是拓展组件只能加在源生组件的最上面或者最下面。
1 | using UnityEngine; |
拓展继承组件
1 | using UnityEngine; |
组件不可编辑
1 | using UnityEngine; |
1 | using UnityEngine; |
Context菜单
1 | using UnityEngine; |
1 | using UnityEngine; |
拓展Scene视图
辅助元素
1 | using UnityEngine; |
辅助UI
1 | using UnityEngine; |
常驻辅助UI
1 | using UnityEngine; |
禁用选中对象
1 | using UnityEngine; |
拓展Game视图
MenuItem菜单
面板拓展
脚本挂在游戏对象上时,右侧会出现它的详细信息面板,这些信息是根据脚本中声明的public可序列化变量而来的。此外,也可以通过EditorGUI来对它进行绘制,让面板更具可操作性。
Inspector面板
EditorGUI和GUI的用法几乎完全一致,目前来说前者多用于编辑器开发,后者多用于发布后调试编辑器。总之,它们都是起辅助作用的。EditorGUI提供的组件非常丰富,常用的绘制元素包括文本、按钮、图片和滚动框等。做一个好的编辑器,是离不开EditorGUI的。如下图所示,将EditorGUI拓展在Inspector面板上了。
1 | using UnityEngine; |
在上述代码中,将脚本部分和Editor部分的代码合在一个文件中。如果需要拓展的面板比较复杂,建议分成两个文件存放,一个是脚本,另一个是Editor脚本。
EditorWindows窗口
Unity提供编辑器窗口,开发者可以自由拓展自己的窗口。Unity编辑器系统自带的视图窗口其实也是用EditorWindows实现的。如下图所示,它绘制元素时同样适用EditorGUI代码。
使用EditorWindow.GetWindow()方法即可打开自定义窗口,在OnGUI()方法中可以绘制窗口元素。注意代码中EditorWindos窗口的生命周期。
1 | using UnityEngine; |
EditorWindows下拉菜单
在EditorWindows编辑窗口的右上角,有个下拉菜单,也可以对该菜单中的选项进行拓展,不过这里需要实现IHasCustomMenu接口。
1 | using UnityEngine; |
上述代码中,通过AddItem()方法来添加列表元素,并且监听选择后的事件。
预览窗口
选择游戏对象或者游戏资源后,Inspector面板下方将会出现它的预览窗口,但是有些资源是没有预览信息的,不过可以监听它的窗口方法来重新绘制它。如下图所示。
1 | using UnityEngine; |
这段代码的原理就是继承ObjectPreview并且重写OnPreviewGUI()方法,接着就可以通过代码进行绘制了。[CustomPreview(typeof(GameObject))]中的GameObject代表需要重新绘制的预览对象,也可以换成别的系统对象或自定义的脚本对象。
获取预览信息
有些资源是有预览信息的,比如模型资源。在预览窗口中,可以看到它的样式。如果需要在自定义窗口中显示它,就需要获取它的预览信息。如下图所示,选择一个游戏对象后,会在自定义窗口中显示它。
1 | using UnityEngine; |
在上述代码中,预览对象首先需要通过Editor.CreateEditor()拿到它的Editor实例对象,接着调用OnPreviewGUI()方法传入窗口的显示区域。
Unity编辑器的源码
Unity编辑器几乎都是用C#编写而成,视图中也大量使用EditorGUI来编辑布局。例如,对于常见的5大布局视图,所有的代码都放在UnityEditor.dll中。打开Unity安装目录,在Unity\Editor\Data\Managed子目录中存放着引擎所需要用到的所有DLL文件。
查看DLL
拿到UnityEditor.dll以后,就可以通过第三方工具来分析和查看了。常用的工具包括.NET Reflector以及ILSpy。其实Unity的C#版API接口都在UnityEngine.dll里,只是源码的核心功能都是在C/C++中完成的,DLL只负责中间调用接口而已。
清空控制台日志
系统日志以及Debug.Log()产出的日志都输出在Console窗口中。在Console窗口的左上角,有个Clean按钮,它用于清空控制台日志。如果希望脚本可以灵活自动清空日志,就必须使用反射了。首先找到控制台的窗口类(ConsoleWindows.cs),接着在OnGUI()方法中可以看到:点击Clean按钮后,Unity会执行LogEntries.Clear()方法。
1 | using UnityEngine; |
获取EditorStyles样式
1 | using UnityEngine; |
获取内置图标样式
1 | using UnityEngine; |
拓展默认面板
1 | using UnityEngine; |
UIElements
1 | TextField |
1 | using UnityEngine; |