49.UnityEditor基础知识总结

  1. 49.总结
    1. 49.1 知识点
      1. 总结主要内容
      2. 更多内容
      3. 主要用处
    2. 49.2 核心要点速览
      1. 自定义菜单栏(MenuItem / AddComponentMenu)
      2. 自定义窗口(EditorWindow)
      3. EditorGUI / EditorGUILayout(IMGUI 控件)
      4. EditorGUIUtility(辅助 API)
      5. Selection(编辑器当前选中)
      6. Event(编辑器内输入)
      7. Inspector 自定义(Editor · SerializedObject)
      8. Scene 视图 · Handles
      9. HandleUtility(句柄与 Scene 交互)
      10. Gizmos(MonoBehaviour 上的 Scene 辅助绘制)
      11. EditorUtility(编辑器通用工具)
      12. AssetDatabase(编辑器侧资源数据库)
      13. PrefabUtility(编辑器侧 Prefab 操作)
      14. EditorApplication(编辑器本体状态与回调)
      15. CompilationPipeline(UnityEditor.Compilation)
      16. AssetImporter 与 AssetPostprocessor(导入管线)
    3. 49.3 面试题精选
      1. 基础题
        1. 1. Editor 程序集、UnityEditor 与 MenuItem / AddComponentMenu
          1. 题目
          2. 深入解析
          3. 答题示例
          4. 参考文章
        2. 2. EditorGUI 与 EditorGUILayout、典型使用场景
          1. 题目
          2. 深入解析
          3. 答题示例
          4. 参考文章
        3. 3. Gizmos 与 Handles 的分工
          1. 题目
          2. 深入解析
          3. 答题示例
          4. 参考文章
      2. 进阶题
        1. 1. GetWindow 与 CreateWindow
          1. 题目
          2. 深入解析
          3. 答题示例
          4. 参考文章
        2. 2. AssetDatabase 的路径、Refresh 与 LoadAssetAtPath
          1. 题目
          2. 深入解析
          3. 答题示例
          4. 参考文章
        3. 3. PrefabUtility:编辑资产内容 vs 摆进场景
          1. 题目
          2. 深入解析
          3. 答题示例
          4. 参考文章
      3. 深度题
        1. 1. EditorWindow:OnGUI、Update、OnInspectorUpdate
          1. 题目
          2. 深入解析
          3. 答题示例
          4. 参考文章
        2. 2. 自定义 Inspector:SerializedObject 与直接改 target
          1. 题目
          2. 深入解析
          3. 答题示例
          4. 参考文章
        3. 3. 导入管线:AssetPostprocessor 与 AssetImporter 子类
          1. 题目
          2. 深入解析
          3. 答题示例
          4. 参考文章

49.总结


49.1 知识点

总结主要内容

更多内容

主要用处


49.2 核心要点速览

自定义菜单栏(MenuItem / AddComponentMenu)

  • 使用 UnityEditor 的脚本放在 Editor 文件夹下,避免编辑器代码打进包体。
  • MenuItem:修饰静态方法;不要求继承 MonoBehaviour;路径分隔符必须是 **/**,不能用 \
  • AddComponentMenu:命名空间 UnityEngine,给继承 MonoBehaviour 的脚本出现在 Component 菜单;一般不放在 Editor 文件夹。
入口 MenuItem 路径前缀 说明
主菜单自定义项 一级/二级/... 直接写菜单层级
Hierarchy / GameObject 菜单与右键 GameObject/... 主菜单 GameObject 里也会出现同名项
Project / Assets 菜单与右键 Assets/... 主菜单 Assets 里也会出现同名项
Inspector 组件右键 CONTEXT/脚本类名/... 脚本类名与目标组件类名一致
  • 快捷键:在路径字符串末尾加 _键名;组合键用 % Ctrl、**#** Shift、**&** Alt;支持单键与方向键、F1–F12、HOME、END、PGUP、PGDN 等(系列正文已列举)。

自定义窗口(EditorWindow)

继承 EditorWindow,在 OnGUI 里用 GUILayout / EditorGUILayout 画控件;通常由 MenuItem 里调用 GetWindow 取实例,设 titleContentShow

创建与查询(静态 API)

API 作用 何时用
GetWindow 获取或创建该类型窗口,同类型常表现为单例 大多数工具窗:只保留一个面板
CreateWindow 创建窗口,同一类型可多个实例 要并排多个独立面板、对照编辑
GetWindowWithRect 指定初始矩形(位置与大小)创建/显示 需要固定弹出区域
HasOpenInstances 判断某 EditorWindow 类型是否已有打开实例 「已打开则聚焦、未打开则创建」

GetWindow 重载里常见参数utility 为 true 时偏可自由拖动、缩放的浮动工具窗;为 false 偏普通停靠式窗口;另有 titlefocusdesiredDockNextTo(靠 dock 到某类窗口旁)等。

事件回调(与 Hierarchy / Project / 选中 / 焦点 联动)

回调 何时触发 可用来做什么
OnHierarchyChange 场景层次里对象创建、删除、重命名等 场景结构变了之后刷新列表、缓存
OnProjectChange 工程资源增删改 资源变了之后刷新路径、依赖显示
OnSelectionChange 当前选中对象变化 窗口内容与 Inspector 选中对象对齐
OnFocus / OnLostFocus 本窗口获得 / 失去键盘焦点 焦点相关状态、暂停昂贵刷新
OnInspectorUpdate 随 Inspector 刷新节奏调用 需要与检视器刷新同步的轻量更新

生命周期(窗口自身)

回调 作用
OnEnable 窗口激活时做一次初始化(引用、缓存、订阅)
OnGUI 每帧绘制 IMGUI;按钮、布局、即时模式控件都放这里
Update 编辑器里每帧逻辑更新;与 OnGUI 分工,非绘制类持续逻辑可放这里
OnDestroy 窗口销毁时收尾、取消订阅

实例与静态成员(常用)

类别 名称 作用
静态只读 focusedWindow、mouseOverWindow 当前焦点窗口 / 鼠标下的 EditorWindow
实例 titleContent、position 窗口标题与屏幕矩形
实例 wantsMouseEnterLeaveWindow 为 true 时鼠标进入/离开窗口会多触发 OnGUI,做悬停高亮等
实例 Show、Repaint、Close 显示、强制重绘、关闭窗口

EditorGUI / EditorGUILayout(IMGUI 控件)

  • EditorGUI 对标 GUI:按 Rect 手动摆位;含编辑器常用专用控件。
  • EditorGUILayout 对标 GUILayout自动布局,系列正文以该类为主;与 EditorGUI 的差别主要是是否自算位置
  • 拓展里一般在 EditorWindow.OnGUI(或自定义 Inspector 等)里调用;可与 GUI / GUILayout 混用。

布局选项(GUILayoutOption,复习)Width / Height 固定宽高;MinWidth / MaxWidth 等约束;ExpandWidth(true/false) 等控制是否沿水平方向扩展占满。

文本 · 层级 · 标签 · 颜色

API 干什么用
LabelField 只读文本;重载可「左标题 + 右内容」
LayerField Layer(内部为 int),建议带前缀标签便于辨认
TagField Tag(string)
ColorField Color;重载可控制拾色器、透明度、HDR 等

枚举 · 整数下拉 · 特殊按钮

API 干什么用 注意
EnumPopup 单选枚举 返回值转回枚举类型
EnumFlagsField 多选(按位或) 枚举需按位赋值,并配好组合值
IntPopup 下拉文案用 strs返回 int 数组 ints 里选中的那个值 显示与存储分离
DropdownButton 鼠标按下当下就返回 true FocusType.Keyboard 可走 Tab 焦点;Passive 不接收键盘焦点

对象引用与各类输入

类别 作用
ObjectField 拖对象或选资源;typeof 指定类型;最后一参控制是否允许场景内对象
IntField、LongField、FloatField、DoubleField、TextField 基本数值与字符串
Vector2/3/4Field、RectField、BoundsField、BoundsIntField 向量、矩形、包围盒
DelayedIntField 等 Delayed* 按 Enter 或失焦前不提交新值,减少输入过程中频繁改动

折叠与开关

API 干什么用 和其它的区别
Foldout bool 表示展开;第三参为 true 时点标题整行可切换,false 时只能点箭头 轻量折叠行
BeginFoldoutHeaderGroup / EndFoldoutHeaderGroup 标题行高亮的折叠区,子控件包在 bool 为 true 的分支里 必须 End 配对
Toggle / ToggleLeft 开关;ToggleLeft 为勾选框在左
BeginToggleGroup / EndToggleGroup 一个总开关控制整段子控件是否启用(灰显) 必须 End 配对

滑动条

API 干什么用
Slider / IntSlider 在最小~最大间拖单个 float 或 int
MinMaxSlider 同一范围内用两个滑块调左右界(ref 两个 float)

提示与留白

API 干什么用
HelpBox 提示条;MessageType 为 None / Info / Warning / Error 控制图标与强调程度
Space 垂直方向空出指定像素

曲线与行列布局

API 干什么用
CurveField 编辑 AnimationCurve
BeginHorizontal / EndHorizontal 子控件横向排列
BeginVertical / EndVertical 子控件纵向排列
BeginScrollView / EndScrollView 滚动视图Vector2 存滚动偏移

EditorGUIUtility(辅助 API)

  • 定位:EditorGUI 侧的实用工具类,补充资源加载、对象选择器、跨窗口事件、GUI/屏幕坐标互转、光标、色块与曲线预览等,不负责替代 EditorGUILayout 画表单控件。

Editor Default Resources 与加载

API 干什么用 注意
Load Assets/Editor Default Resources/文件名+后缀加载 找不到返回 null
LoadRequired 同上路径规则 找不到会直接报错

对象选择器与 Ping

API / 机制 干什么用
ShowObjectPicker 弹出搜索选资源窗口;泛型为可选类型;参数含默认选中、allowSceneObjects、名称过滤字符串、controlID(示例常用 0)
GetObjectPickerObject 读取对象选择器当前选中的 Object
commandName + Event.current ObjectSelectorUpdated:选择变化时;ObjectSelectorClosed:选择器关闭时;在 OnGUI 里分支处理
PingObject 在 Project 等窗口定位并闪选传入对象(高亮选中)

跨窗口命令事件与坐标

主题 要点
CommandEvent + SendEvent EditorGUIUtility.CommandEvent("命令名") 创建事件,对目标 EditorWindow.SendEvent(e);接收端:Event.current.type == ExecuteCommandcommandName 匹配
传递副作用 自动打开接收方窗口,焦点移到该窗口
坐标系 屏幕:原点屏幕左上角GUI:原点当前窗口左上角
GUIToScreenPoint / GUIToScreenRect GUI 空间 → 屏幕
ScreenToGUIPoint / ScreenToGUIRect 屏幕 → GUI 空间
与 BeginGroup 等组合 布局/组内做转换时,要考虑布局偏移再换算

多显示器会参与坐标计算。

光标与装饰绘制

API 干什么用
AddCursorRect 在指定 Rect 内悬停时使用给定 MouseCursor(箭头、缩放、移动、手型等,见 MouseCursor)
DrawColorSwatch 在矩形区域绘制纯色块;常和 ColorField 搭配作参考色
DrawCurveSwatch 在矩形内预览曲线;传入 AnimationCurve 与线色/背景色,可选 SerializedProperty

Selection(编辑器当前选中)

  • 用途:在编辑器脚本里读取当前在 Hierarchy / Project 等处的选中对象不能用于运行时玩家包

主选「一个」与多选「全部」

成员 含义 多选时 未选或类型不符
activeObject 当前主选 Object(场景对象、资源等) 第一个 null
activeGameObject 当前主选 GameObject 第一个 null(非 GameObject 选中也为 null)
activeTransform 当前主选 Transform(对应 Hierarchy 场景对象) 第一个 null
objects 当前选中 Object[] 全部 未选可作 null;代码里常用 Selection.count 判断
gameObjects 当前选中 GameObject[] 全部遍历
transforms 当前选中 Transform[] 全部遍历

静态方法 · 委托

API 干什么用
Contains 判断某个 Object 是否在当前选中集合中(多选里包含也算)
GetFiltered(含泛型重载) 当前选中上按 SelectionMode 再筛选,得到 Object[]
selectionChanged 选中变化时触发;在 OnEnable +=OnDestroy -= 配对订阅

SelectionMode(可多选组合,用 | 位或)

模式 含义
Unfiltered 不过滤
TopLevel 只最上层,不含子对象
Deep 父与子都包含
ExcludePrefab 排除预制体
Editable 只要可编辑对象
OnlyUserModifiable 仅用户可修改内容
Assets 只返回 Assets 下资源
DeepAssets Assets 含子文件夹深度

Event(编辑器内输入)

  • 用途:在编辑模式下读键盘、鼠标等输入;运行时监听用 Input,编辑器里用 Event
  • 使用位置OnGUISceneView 相关回调等。
  • 入口Event.current 取当前正在处理的事件。

常用字段

类别 成员 含义
修饰键 alt、shift、control、command 是否按住 Alt / Shift / Ctrl / Win 或 Mac Command
鼠标 isMouse、button、mousePosition 是否鼠标事件;按键索引;GUI 空间鼠标位置
键盘 isKey、character、keyCode 是否键盘事件;字符;按键码
事件类型 type(配合 EventType) 区分按下、抬起、拖拽等(与鼠标/键盘阶段配合)
其它 capsLock、delta 大写锁定;鼠标位移增量
命令串 commandName 如 Copy / Paste / Cut 等(与菜单命令对应)
其它 functionKey、numeric 功能键;数字键盘区状态

处理完自定义逻辑后可调用 Use()阻止事件继续传递,减少与编辑器其它逻辑冲突。

Inspector 自定义(Editor · SerializedObject)

角色

概念 作用
SerializedObject 表示正在被检视的组件/对象的序列化视图
SerializedProperty 表示其上某一个字段(或子字段)
Editor.target 当前正在编辑的组件实例

基本流程

  • 新建类继承 Editor,加 **[CustomEditor(typeof(你的 MonoBehaviour))]**;脚本放 Editor 程序集。
  • OnEnableserializedObject.FindProperty("字段名") 缓存 SerializedProperty
  • 重写 OnInspectorGUI:整体包在 serializedObject.Update()ApplyModifiedProperties() 之间再画控件、改 SerializedProperty

数组 / List

方式 要点
PropertyField 按类型自动画数组或 List;不要再塞进 BeginFoldoutHeaderGroup 与自带折叠冲突,否则会报错
手写 arraySizeInsertArrayElementAtIndexDeleteArrayElementAtIndexGetArrayElementAtIndex 控制容量与每一项

可序列化自定义类

  • 类型加 **[Serializable]**;字段用 SerializedProperty 绑定。
  • 子字段: FindPropertyRelative("子名") 或 **FindProperty("父.子")**,二选一。

Dictionary 与 Inspector

  • Unity 不直接序列化 Dictionary 到 Inspector;用两个 List(或数组)存键值,内存里再维护 Dictionary
  • ISerializationCallbackReceiverOnBeforeSerialize 里把字典写入两列表;OnAfterDeserialize 里从列表还原字典。
  • 自定义 Inspector 里对 keys / values 两个 SerializedProperty 做增删改,与数组/List 手写逻辑类似。

Scene 视图 · Handles

  • 定位:在 Scene 窗口绘制 3D 辅助线、面、手柄等;与 GUI / EditorGUI 类似,但面向场景视图
  • CustomEditor 路线:前两步与自定义 Inspector 相同(继承 Editor[CustomEditor(typeof(T))]),再实现 void OnSceneGUI()仅当选中挂载该组件的对象时执行。
  • EditorWindow 路线:**SceneView.duringSceneGui +=** 在窗口 OnEnable 订阅,OnDestroy-= 移除。

颜色 · 文字 · 线

API 干什么用 注意
Handles.color 设置后续线框等绘制颜色 Label 不受此颜色控制,需 GUIStyle
Label 在世界坐标处显示文字
DrawLine 实线段 含线宽重载
DrawDottedLine 虚线段

弧 · 圆 · 体

API 干什么用
DrawWireArc / DrawSolidArc 圆弧:圆心、法线、起始朝向、角度、半径
DrawSolidDisc / DrawWireDisc 填充圆 / 线框圆
DrawWireCube 线框立方体(中心、尺寸)
DrawAAConvexPolygon 按顶点画凸多边形

标准移动 / 旋转 / 缩放手柄

API 干什么用 易错点
DoPositionHandle / PositionHandle 位置手柄 传入 Vector3.zero、Quaternion.identity 等写死值时,手柄不跟物体动
DoRotationHandle / RotationHandle 旋转手柄
DoScaleHandle / ScaleHandle 缩放手柄 最后一参为 HandleUtility.GetHandleSize(参考点)GetHandleSize(zero) 与传物体位置时柄长表现不同

自由移动 / 旋转

API 干什么用
FreeMoveHandle 无轴约束移动;含步进(Ctrl)、HandleCap(RectangleHandleCap、CircleHandleCap、ArrowHandleCap 等)
FreeRotateHandle 自由旋转

在 Scene 里叠 IMGUI

API 干什么用
BeginGUI / EndGUI 中间写 GUI / GUILayout
SceneView.currentDrawingSceneView 当前绘制的 SceneView;position 取窗口宽高,用于 GUILayout.BeginArea 等布局

HandleUtility(句柄与 Scene 交互)

  • 定位:处理 Handles 相关的鼠标、坐标转换、拾取等;鼠标位置用 **Event.current.mousePosition**(回顾)。
API 干什么用
GetHandleSize 给定世界坐标处句柄应有的大致尺寸,随距离与相机缩放变化
WorldToGUIPoint 世界坐标 → Scene 视图 GUI 像素,便于控件贴着物体画
GUIPointToWorldRay 屏幕点 → 世界射线,用于 Raycast
DistanceToLine 鼠标到空间线段的最短距离,可做悬停判断
PickGameObject 按屏幕坐标拾取场景 GameObject

Gizmos(MonoBehaviour 上的 Scene 辅助绘制)

  • 与 Handles 分工Gizmos 侧重辅助线、图标、几何示意Handles 侧重可交互编辑手柄
  • 挂载位置:写在继承 MonoBehaviour 的脚本里(非 Editor 脚本)。
回调 何时调用
OnDrawGizmos 每帧绘制,Scene 里始终可见
OnDrawGizmosSelected 仅当该 GameObject 被选中时每帧绘制

颜色 · 立方体 · 视锥 · 矩阵

要点 说明
Gizmos.color 设置后续绘制颜色
DrawCube / DrawWireCube 实心 / 线框立方体
DrawFrustum 视锥:中心、FOV、远/近裁切面、宽高比
Gizmos.matrix 默认立方体/视锥不随物体旋转;用 Matrix4x4.TRSlocalToWorldMatrix 让绘制跟随物体;Matrix4x4.identity 还原

贴图与图标

API 干什么用 注意
DrawGUITexture 在 Rect 上画贴图 仅 xy 跟物体走,z 无效;显示可能「默认反过来」
DrawIcon 世界坐标处画内置图标 图片放在 Assets/Gizmos/,参数为文件名

线 · 网格 · 射线 · 球

API 干什么用
DrawLine 线段
DrawMesh / DrawWireMesh 实心网格 / 线框网格
DrawRay 从点沿方向射线
DrawSphere / DrawWireSphere 实心球 / 线框球

EditorUtility(编辑器通用工具)

  • 定位:Unity 编辑器里的实用工具类,各类拓展里都能调;只存在于编辑器不能进玩家包

模态对话框与进度

API 干什么用 注意
DisplayDialog 单确认类弹窗 阻塞,关掉前后面逻辑不继续
DisplayDialogComplex 三键面板 返回 0 / 1 / 2 对应三个按钮;参数顺序为「左、右、中」式三键名(以 API 为准)
DisplayProgressBar 显示进度 0~1 不阻塞逻辑,但要记得 ClearProgressBar

系统文件 / 文件夹对话框

API 干什么用
SaveFilePanel 系统「另存为」,得完整路径,可写任意盘
SaveFilePanelInProject 限制在工程目录内保存
SaveFolderPanel 选保存用文件夹
OpenFilePanel 打开单个文件
OpenFolderPanel 打开文件夹

取消或关闭时常返回空字符串(可用 != "" 判断)。

其它常用

API 干什么用
CompressTexture Texture2D 压成指定 TextureFormat 与质量;常配合导入管线
CollectDependencies 传入根 Object[],返回其依赖资源列表;可赋给 Selection.objects 做全选依赖

AssetDatabase(编辑器侧资源数据库)

  • 定位:编辑器里对 Project / Assets 做增删改查的静态 API仅编辑器,不进包。
  • 路径:一律从 Assets/... 起;涉及文件的 API 通常要写扩展名
API 干什么用 注意
CreateAsset 把内存里的资源对象写成磁盘资产 不能在 StreamingAssets;不能直接创建 Prefab;路径带后缀;典型如材质球
CreateFolder 在父路径下建新文件夹 参数为 (父文件夹, 新文件夹名)
CopyAsset / MoveAsset 拷贝 / 移动资产 目标路径带后缀
DeleteAsset 删单个资产
DeleteAssets 批量删 失败路径写入传入的 List<string>
GetAssetPath Object工程内路径 常配合 Selection
LoadAssetAtPath<T> 按路径加载单个主资产 编辑器工具用;运行时打包流程不同
LoadAllAssetsAtPath 同路径下全部子对象 图集等:返回 **Object[]**,首个常为图集本体,其后为子 Sprite
Refresh 刷新资源数据库与 Project 视图 File 等非 Unity API 写进 Assets 后常需调用,否则窗口不更新
GetImplicitAssetBundleName 查路径对应的 AB 包名 路径从 Assets/

PrefabUtility(编辑器侧 Prefab 操作)

  • 定位:创建 / 加载 / 保存 / 实例化 Prefab 资产仅编辑器
API 干什么用 注意
SaveAsPrefabAsset 把场景里的 GameObject 存成 .prefab 可先 new GameObject 再保存;不想留在场景里可 DestroyImmediate
LoadPrefabContents 把 Prefab 展开到可编辑的临时实例(隐形场景) 用于加组件、改层级等;与 Unload 成对
UnloadPrefabContents 释放 LoadPrefabContents 打开的实例 不配会泄漏/状态异常
SavePrefabAsset 已加载的 Prefab 资产写回磁盘 常配合 LoadAssetAtPath<GameObject>存的是资产不是场景实例
InstantiatePrefab 在编辑器里把 Prefab 摆进当前场景 LoadPrefabContents 不同:后者为编辑资产内容

EditorApplication(编辑器本体状态与回调)

  • 定位:监听编辑器级更新与工程变化、查询播放/暂停/编译/刷新、取 Unity 安装路径、控制进入/退出播放模式等。
能力 说明
静态事件 update(每帧);hierarchyChangedprojectChangedplayModeStateChangedpauseStateChanged
状态 isPlaying / isPaused / isCompiling / isUpdating(刷新 AssetDatabase 时)
路径 applicationContentsPath(安装目录 Data);applicationPathUnity.exe
常用调用 EnterPlaymode / ExitPlaymodeExit 退出编辑器等(Lesson 注释)

订阅 update 等事件须在 OnEnable/OnDestroy+= / -= 成对注销。

CompilationPipeline(UnityEditor.Compilation

  • 用途:感知脚本编译进度;典型场景是动态生成代码后要等整次编译结束再使用新类型。
回调 何时触发 参数要点
assemblyCompilationFinished 某一个程序集编译完 (程序集名, CompilerMessage[]) — 含警告/错误
compilationFinished 全部程序集编译完 object(与活动生成状态相关)

OnEnable/OnDestroy+= / -= 订阅与取消。

AssetImporter 与 AssetPostprocessor(导入管线)

  • 分工AssetPostprocessor导入过程的通用逻辑;AssetImporter(及子类)对应 Inspector 里各类型导入设置
  • AssetPostprocessor:常用 **assetImporter(转为具体 Importer)、assetPath**;按资源类型实现 OnPreprocess* / **OnPostprocess***(纹理 / 模型 / 音频等)。
  • 典型用途:一类资源统一默认导入参数;导入后批量后处理(如 OnPostprocessTexture 里调用 EditorUtility.CompressTexture)。
  • 按需过滤:只想处理部分文件时,可用路径/命名规则收窄。
  • AssetImporter 子类(常见)TextureImporterModelImporterAudioImporterVideoClipImporterScriptedImporter(自定义扩展名导入)。

49.3 面试题精选

基础题

1. Editor 程序集、UnityEditor 与 MenuItem / AddComponentMenu

题目

为什么大量使用 UnityEditor 的脚本要放在 Editor 文件夹(或独立 Editor 程序集)?MenuItemAddComponentMenu 分别挂在什么代码上、各自影响什么界面?

深入解析
  • UnityEditor 只在编辑器内存在,运行时代码不能引用;打进包体会失败或报错。Editor 文件夹将脚本编译进 Editor-only 程序集,与玩家代码隔离。
  • MenuItem:修饰 static 方法,扩展顶部菜单 / GameObject / Assets / 组件右键等;必须能引用 UnityEditor
  • AddComponentMenu:在 UnityEngine 命名空间,给继承 MonoBehaviour 的类出现在 Add Component 里的分类路径;组件仍属运行时脚本,一般不放进 Editor
答题示例

UnityEditor 不能进玩家包,编辑器工具代码放 Editor 程序集。MenuItem 是加编辑器菜单命令的,方法 static,写在 Editor。AddComponentMenu 只是 Component 菜单里的显示路径,脚本还是挂在物体上的 MonoBehaviour,跟普通游戏脚本放一起。

参考文章
  • 2.自定义菜单栏拓展

2. EditorGUI 与 EditorGUILayout、典型使用场景

题目

编辑器 IMGUI 里 EditorGUIEditorGUILayout 的主要差别是什么?拓展里一般在什么地方调用它们?

深入解析
  • EditorGUI:按 Rect 手动布局,与 GUI 对应,适合已知矩形或要精细贴齐的区域。
  • EditorGUILayout自动布局,与 GUILayout 对应,多数工具窗、Inspector 拓展用 EditorGUILayout 写控件更省事。
  • 常见调用位置:EditorWindow.OnGUI、自定义 Editor.OnInspectorGUI 等;可与 GUI / GUILayout 混用。
答题示例

EditorGUI 要自己算 Rect 摆位置;EditorGUILayout 自动排版。做编辑器窗口和自定义 Inspector 一般用 EditorGUILayout 多。都在 OnGUI 或 OnInspectorGUI 里画。

参考文章
  • 4.EditorGUI-EditorGUI是什么、系列 EditorGUILayout 篇

3. Gizmos 与 Handles 的分工

题目

GizmosHandles 分别解决什么问题?脚本通常写在哪里、和 Scene 里「能不能交互」有什么关系?

深入解析
  • Gizmos辅助显示(线框、图标、范围等),多在 MonoBehaviourOnDrawGizmos / OnDrawGizmosSelected 中绘制,非 Editor 脚本,偏只读示意
  • Handles可编辑手柄(移动/旋转/缩放等),在 EditorOnSceneGUISceneView.duringSceneGui 等里绘制,常与工具逻辑、Undo 配合。
  • 面试常追问:选中才画OnDrawGizmosSelected;要场景内拖拽编辑走 Handles。
答题示例

Gizmos 是画给策划程序看的辅助线、范围,写在普通 MonoBehaviour 上,一般不交互。Handles 是 Scene 里能拖的手柄,在 Editor 的 OnSceneGUI 里画。一个偏展示,一个偏编辑。

参考文章
  • 34~38 Gizmos 篇、27~33 Handles 篇

进阶题

1. GetWindow 与 CreateWindow

题目

EditorWindow.GetWindowCreateWindow 在实例数量上典型差异是什么?什么需求下必须用 CreateWindow?

深入解析
  • GetWindow:同类型窗口常表现为单例,再次打开往往复用已有实例,适合全局工具、设置面板。
  • CreateWindow允许同类型多实例,适合多文档、多配置对照、并排多个独立面板。
  • 工程上:需要「同类工具开多个」时用 CreateWindow,避免 GetWindow 抢同一个实例。
答题示例

GetWindow 同类型通常就一个窗口。CreateWindow 可以同类型开多个。要并排开多个同类编辑器窗口时用 CreateWindow。

参考文章
  • 3.自定义窗口拓展

2. AssetDatabase 的路径、Refresh 与 LoadAssetAtPath

题目

AssetDatabase 里资源路径通常怎么写?什么情况下必须调用 RefreshLoadAssetAtPath 和运行时 Resources.Load 等有什么边界?

深入解析
  • 路径一般以 Assets/... 为根,带扩展名;创建/拷贝/移动等多处要求写全路径。
  • Refresh:用 System.IO绕过 Unity API 直接改 Assets 下文件时,Project 窗口与数据库可能不更新,需 **AssetDatabase.Refresh()**。
  • LoadAssetAtPath仅编辑器下按工程路径加载资产;运行时包内加载走 Resources、Addressables、AssetBundle 等,不把 AssetDatabase 打进包。
答题示例

路径从 Assets 写起,要带后缀。用 File 写进 Assets 了要 Refresh 一下才能在 Project 里看到。LoadAssetAtPath 是编辑器工具用的,真机跑游戏不能用这套,运行时有自己的加载方式。

参考文章
  • 43~44 AssetDatabase 篇

3. PrefabUtility:编辑资产内容 vs 摆进场景

题目

LoadPrefabContents + UnloadPrefabContentsInstantiatePrefabSavePrefabAsset 分别典型用于什么?Load 与 Instantiate 容易混在什么地方?

深入解析
  • LoadPrefabContents:把 Prefab 展开成可编辑根物体(隐形场景),改组件、层级后常再 SaveAsPrefabAsset;必须与 UnloadPrefabContents 配对。
  • InstantiatePrefab:在当前编辑场景里生成预制实例,偏「摆关卡」。
  • SavePrefabAsset:把已加载的 Prefab 资产(如 LoadAssetAtPath 得到的)的修改写回磁盘;与对场景实例改完点 Apply 的流程不同。
  • 易混:LoadPrefabContents 不是「往场景里放一个可玩的实例」那种 Instantiate,而是改磁盘上的 Prefab 资产的工作流。
答题示例

LoadPrefabContents 是把 prefab 拉出来编辑,改完保存再 Unload,两个要配对。InstantiatePrefab 是编辑器里往场景里实例化。SavePrefabAsset 是保存对 prefab 资产本身的修改。别把 LoadPrefabContents 当成普通 Instantiate。

参考文章
  • 45.PrefabUtility

深度题

1. EditorWindow:OnGUI、Update、OnInspectorUpdate

题目

EditorWindowOnGUIUpdateOnInspectorUpdate 调用节奏有何不同?各适合放什么逻辑?

深入解析
  • OnGUI每帧绘制 IMGUI,按钮、布局、控件交互以这里为主。
  • Update:窗口每帧 tick,适合不依赖 GUI 绘制顺序的持续逻辑(计时、轮询状态等)。
  • OnInspectorUpdate:随 Inspector 刷新触发,适合与当前 Selection / 检视对象同步的轻量更新,避免比 OnGUI 更频繁的无效重绘。
  • 取舍:纯界面跟 OnGUI;跟 Inspector 选中对象对齐用 OnInspectorUpdate
答题示例

OnGUI 每帧画界面。Update 也是每帧,放不画图但要每帧跑的逻辑。OnInspectorUpdate 跟着 Inspector 刷新,适合跟选中对象同步。要跟检视器对齐就用 OnInspectorUpdate。

参考文章
  • 3.自定义窗口拓展

2. 自定义 Inspector:SerializedObject 与直接改 target

题目

自定义 Editor 里为什么推荐 serializedObject.Update / ApplyModifiedProperties 配合 SerializedProperty,而不是在 OnInspectorGUI 里直接改 target 上的字段?

深入解析
  • SerializedObject 走 Unity 序列化与 Undo 系统,ApplyModifiedProperties 能正确标记脏、支持撤销、与多对象编辑更一致。
  • 直接改 target 容易绕过 Undo、Inspector 刷新异常,且 多选同一组件 时行为难保证。
  • 标准骨架:Update() → 画控件并改 SerializedPropertyApplyModifiedProperties()
答题示例

用 SerializedObject 和 SerializedProperty 改,能接 Undo,和多选、脏标记都一致。直接改 target 容易不能撤销,和多对象编辑也容易出问题。一般是 Update,改属性,再 Apply。

参考文章
  • 23~26 Inspector 窗口拓展篇

3. 导入管线:AssetPostprocessor 与 AssetImporter 子类

题目

AssetPostprocessor 在资源导入流程里起什么作用?OnPreprocess*OnPostprocess* 典型各做什么?和 TextureImporterAssetImporter 子类是什么关系?

深入解析
  • AssetPostprocessor 提供导入各阶段的全局回调,可据 assetPath 做命名规则过滤,实现「某类目录下纹理统一设为 Sprite」等批量策略
  • OnPreprocess*:导入完成前Importer 设置(如纹理类型、压缩)。
  • OnPostprocess*:导入完成后Object 再加工(如 OnPostprocessTexture 里再压格式)。
  • AssetImporter 子类是 Inspector 里该类型资源的设置模型;回调里通常 assetImporter as TextureImporter 等去改。
答题示例

AssetPostprocessor 是导入流水线里的钩子,可以统一改导入设置或导入后处理。Pre 是在导入完成前改 Importer,Post 是导入后再动资源。TextureImporter 那些是具体资源在 Inspector 里的设置类型,在回调里转型改就行。

参考文章
  • 48.AssetImporter和AssetPostprocessor


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com

×

喜欢就点赞,疼爱就打赏