unity 3d 教程 有什么编辑器吗

2015年02月07日 13:17 0 点赞 0 评论 更新于 2025-11-21 16:05

编辑器代码触发机制

Unity 3D 允许通过事件触发来执行编辑器代码,不过需要借助一些编译器参数告知编译器何时触发特定代码。在函数上方使用 [MenuItem(XXX)] 声明,能为 Unity 3D 编辑器添加一个菜单项,点击该菜单项时会调用此函数。触发函数中可编写任何合法代码,比如实现一个资源批处理程序,或者弹出一个编辑器窗口。代码里可通过 Selection 类访问当前选中的内容,并据此确定显示视图。类似地,[ContextMenu("XXX")] 可向上下文菜单中添加菜单项。

若编写了一些 Component 脚本,希望在其附属于某个 GameObject 时,能在编辑视图(即 Scene 视图)观察到效果,可在类上方添加 [ExecuteInEditMode],通知编译器该类的 OnGUIUpdate 等函数在编辑模式下也会被调用。此外,使用 [AddComponentMenu("XXX/XXX")] 可将脚本关联到 Component 菜单,点击相应菜单项就能为 GameObject 添加该 Component 脚本。

开始编写编辑器

为避免不必要的包含,Unity 3D 的运行时和编辑器类分别存储在不同的程序集(UnityEngineUnityEditor)中。准备编写编辑器前,需使用 using UnityEditor 导入编辑器的命名空间。若部分代码在运行时和编辑器中都要执行,可使用 #if UNITY_EDITOR ... #endif 宏对编辑器代码进行特殊处理。

在真正编写代码前,还需了解:所有放在名为 Editor 目录下的脚本会在其他脚本之后编译,这便于使用运行时的内容,但其他目录下的脚本无法访问 Editor 目录下的内容。因此,建议将编辑器脚本放在 Editor 目录下。

如何创建自定义编辑器窗口

创建窗口

若要自定义一个可编辑的面板,需编写一个继承自 EditorWindow 的类。通常还需编写一个 [MenuItem] 告知编译器何时打开该面板,此事件的回调应为静态方法,并返回一个窗口的实例。

点击对应的菜单项时,会弹出一个空白窗口,且该窗口可像 Unity 3D 编辑器预制的窗口一样随意拖动和停靠。接下来探讨如何在窗口内实现所需功能。

扩展窗口

和运行时的 GUI 类似,若要在窗口中添加交互控件,需重写 OnGUI 方法,具体重写方式与运行时的 GUI 相同,甚至可使用任何扩展自原生 GUI 系统的插件(如 iGUIGUIX)简化插件开发流程(仅经过初步测试,更深层次的可用性尚待验证)。同时,UnityEditor 命名空间下的 EditorGUILayout 在原生 GUI 之上提供了更便捷的接口和控件,可轻松使用一些编辑器特有的 UI 控件。

OnGUI 外,可能还需以下回调触发特定逻辑(完整列表请参考官方文档):

  • OnSelectionChange:点击选择物品时触发。
  • OnFocus / OnLostFocus:获得和失去焦点时触发。

进一步扩展窗口

自定义控件

和运行时 GUI 的使用方式一样,若要自定义控件,最简单的方法是实现一个静态方法(也可为非静态),并提供一些可选参数,在方法内部根据这些参数完成控件的布局(如同在 OnGUI 中操作)。若将自定义控件实现在窗口类内部,可使用 Partial 类更好地管理代码。

绘制 2D 内容

  • 绘制图片:可使用 GUI.DrawTexture 绘制图片资源。
  • 绘制基础图元:GUI 本身未提供绘制基础图元的方法,但可通过一些方式封装。
  • 绘制线段:通过一个像素的贴图资源配合 GUI.DrawTexture 和矩阵旋转完成线段绘制。
  • 绘制矩形框:通过 GUI.Box 和样式设置封装矩形框和矩形填充框。

资源选择器

EditorLayout.ObjectField 控件提供资源选择逻辑,生成时需指定某种资源类型,可拖动该种资源到控件或点击控件旁边的小圆圈进行列表选择。

如何存储编辑内容

可创建一个继承自 SerializedObject 的类来保存编辑的数据。继承自 SerializedObject 的对象可用于存储数据而不参与渲染,并最终打包到 AssetBundle。针对当前编辑选项等内容的存储,可能需要另一个 SerializedObject 类(与具体系统设计相关)。

向导式的编辑窗口

很多情况下,可能需要一个包含多个参数的编辑面板,编辑结束后有一个确认按钮。无需自行实现,UnityEditor 提供了 ScriptableWizard 帮助快速开发。它继承自 EditorWindow,使用方式类似。点击确认按钮时,OnWizardCreate() 会被调用。另外,ScriptableWizard.DisplayWizard 可帮助生成并显示该窗口。

如何扩展 INSPECTOR 面板

在 Unity 3D 中点击一个对象时,Inspector 面板会显示该对象的属性。可针对某个类型的对象扩展该面板,这在为 Unity 3D 开发插件时非常有用。

定义 INSPECTOR 何时被触发

自定义的 Inspector 面板需继承 Editor 类。由于功能相对具体,无需定义代码何时触发,点击对应物体时代码会自动执行。要定义其对应的类型,只需在类定义前使用编译器命令 [CustomEditor(typeof(XXX))] 即可。

访问被编辑的对象

Inspector 视图中,常需访问正在编辑的对象。Editor 类的成员变量 target 提供了这一关联。需注意,targetObject 类型的对象,具体使用时可能需要进行类型转换(可使用 C# 的泛型避免重复的类型转换)。

实现自己的 INSPECTOR 界面

扩展 Editor 与扩展 EditorWindow 的唯一区别在于,需重写 OnInspectorGUI 而非 OnGUI。若要绘制默认的可编辑项,调用 DrawDefaultInspector 即可。

在 SCENE 界面定义编辑句柄

选中一个物体时,可能希望在 Scene 视图中定义一些编辑或展现操作。这可通过 OnSceneGUIHandle 类完成。OnSceneGUI 用于处理来自 Scene 视图的事件,Handle 类用于在 Scene 视图实现一些 3D 的 GUI 控件(如控制对象位置的 Position 控制器)。具体使用方式可参考官方参考文档。

一些常用的功能说明

  • AssetDatabase.CreateAsset:可从资源目录中创建一个资源实例。
  • Selection.activeObject:返回当前选中的对象。
  • EditorGUIUtility.PingObject:实现在 Project 窗口中点击某一项的操作。
  • Editor.Repaint:重绘界面所有的控件。
  • XXXImporter:设置某种资源的具体导入设置(如某些情况下需设置导入的贴图为可读)。
  • EditorUtility.UnloadUnusedAssets:释放未使用的资源,避免插件产生内存泄漏。
  • Event.Use:标记事件已处理结束。
  • EditorUtility.SetDirty:通知编辑器数据已修改,下次保存时新数据将被存储。