1. Unity编辑器扩展入门:编辑器扩展的概念、应用场景、第一个Editor脚本
大家好,欢迎来到这门课的第一讲。
说实话,我刚开始用Unity那会儿,压根没想过还能自己改编辑器。那时候就觉得——编辑器嘛,官方给啥我用啥。直到有一次,项目里要批量处理几百个预制体,手动操作到凌晨三点...嗯,从那以后,我彻底入了编辑器扩展的坑。
什么是编辑器扩展?
说白了,编辑器扩展就是让你能修改Unity编辑器本身的行为。你可以加按钮、加窗口、加菜单,甚至改写Inspector面板的显示方式。
我个人的理解是:编辑器扩展 = 给Unity编辑器写插件。只不过这个插件是给开发者自己用的,不是给玩家用的。
核心概念:编辑器扩展运行在Editor模式下,不会被打包进游戏。它只影响开发阶段的工作流。
应用场景:什么时候需要写编辑器扩展?
我总结了几类最常见的场景,你看看有没有戳中你的痛点:
- 批量操作:比如批量修改材质参数、批量重命名资源
- 自定义Inspector:让策划同学在Inspector里看到更友好的界面
- 工具窗口:像项目管理器、数据配置面板这类独立窗口
- 自动化流程:资源导入后自动处理、打包前自动检查
- 可视化调试:在Scene视图里画线、画框,辅助调试
你想想看,如果每次改个参数都要手动打开十个窗口,那效率得多低?编辑器扩展就是来解决这个问题的。
第一个Editor脚本:从零开始
好,咱们直接上手写代码。我习惯先创建一个Editor文件夹,这是Unity的约定——所有编辑器脚本都要放在这个文件夹里,或者它的子文件夹下。
小提示:Editor文件夹可以放在Assets根目录,也可以放在任意子目录下。但建议统一放在Assets/Editor/里,方便管理。
来看一个最简单的例子:
// 文件路径:Assets/Editor/MyFirstEditorTool.cs
using UnityEngine;
using UnityEditor;
public class MyFirstEditorTool
{
[MenuItem("Tools/我的第一个工具")]
public static void ShowTool()
{
Debug.Log("Hello from Editor Extension!");
}
}
写完这段代码,回到Unity编辑器,你会看到顶部菜单栏多了一个「Tools」菜单,下面有个「我的第一个工具」。点击它,控制台就会打印出那句话。
是不是很简单?但这里有个坑——我曾经忘记把脚本放在Editor文件夹里,结果打包时报错,找了半天才发现是编辑器代码混进了游戏代码里。
注意:编辑器脚本如果放在非Editor文件夹,会被编译进游戏包体,导致打包失败或运行时异常。一定要放在Editor文件夹下!
MenuItem属性的更多玩法
刚才我们用[MenuItem]属性创建了一个菜单项。这个属性其实挺灵活的,我常用的几种写法:
| 写法 | 效果 |
|---|---|
[MenuItem("Tools/工具A")] |
在Tools菜单下创建子菜单 |
[MenuItem("GameObject/我的工具", false, 10)] |
在GameObject右键菜单里添加,优先级10 |
[MenuItem("Assets/我的工具")] |
在Project面板右键菜单里添加 |
[MenuItem("CONTEXT/组件名/功能")] |
在组件的右键菜单里添加 |
我个人最常用的是CONTEXT那个。比如给Transform组件加个「重置位置到原点」的功能,策划同学用起来特别顺手。
验证菜单项是否可用
有时候我们希望菜单项只在特定条件下才可点击。比如选中了某个类型的对象才显示。这时候可以用第二个参数:
[MenuItem("Tools/处理选中物体", true)]
public static bool ValidateSelection()
{
return Selection.activeGameObject != null;
}
[MenuItem("Tools/处理选中物体")]
public static void ProcessSelection()
{
// 处理逻辑
Debug.Log("处理了: " + Selection.activeGameObject.name);
}
注意看,两个方法用了同一个菜单路径。第一个方法返回bool,用来控制菜单是否可用。第二个方法才是实际执行的逻辑。
为什么会这样设计?我猜Unity是想让验证和执行分离,这样代码更清晰。你想想看,如果验证逻辑写在执行方法里,那菜单的灰显状态就没法实时更新了。
Editor脚本的编译流程
这里有个知识点,我觉得有必要提一下。Unity的脚本编译是分阶段的:
- 第一阶段:编译Runtime脚本(非Editor文件夹下的脚本)
- 第二阶段:编译Editor脚本(Editor文件夹下的脚本)
这意味着:Editor脚本可以引用Runtime脚本,但Runtime脚本不能引用Editor脚本。如果你在Runtime脚本里用了UnityEditor命名空间,编译会直接报错。
避坑指南:我曾经在MonoBehaviour里写了using UnityEditor;,结果打包时死活编译不过。后来用#if UNITY_EDITOR预处理指令才解决。
正确的做法是:
using UnityEngine;
public class MyBehaviour : MonoBehaviour
{
void Start()
{
#if UNITY_EDITOR
Debug.Log("只在编辑器中执行");
#endif
}
}
小结一下
这一讲我们聊了编辑器扩展是什么、能干什么、怎么开始写第一个脚本。说白了,编辑器扩展就是帮你偷懒的工具——把重复劳动交给代码,把时间留给真正有价值的事情。
下一讲我们会深入EditorWindow,做一个真正能用的工具窗口。到时候你会看到,编辑器扩展能做的事情远比今天展示的要多得多。
嗯,今天就到这里。记得把第一个脚本跑起来,感受一下「自己改编辑器」的快感。