How to Develop a Game
Unity Editor Extensions
PublishDate: 2025-06-01 | CreateDate: 2025-06-01 | LastModify: 2025-06-01 | Creator:ljf12825

Unity编辑器扩展就是用C#编写一些工具或界面,去增强Unity自带的编辑器功能,从而让开发流程更高效、更可控
它的本质是:利用UnityEditor API在编辑模式下定制Inspector、菜单、窗口、场景视图、资源导入等功能

基础概念

常见扩展方式

自定义Inspector
让某个组件在Inspector面板中显示定制的界面

using UnityEditor;
using UnityEngine;

[CustomEditor(typeof(MyComponent))]
public class MyComponentEditor : Editor
{
    public override void OnInspectorGUI()
    {
        var myComp = (MyComponent)target;

        EditorGUILayout.LabelField("自定义字段");
        myComp.health = EditorGUILayout.IntSlider("生命值", myComp.health, 0, 100);

        if (GUILayout.Button("重置生命值")) myComp.health = 100;

        // 如果值改变,标记为脏数据
        if (GUI.changed) EditorUtility.SetDirty(myComp);
    }
}

优点:

自定义窗口(EditorWindow)
可以创建一个独立的工具窗口,比如批量修改工具、关卡生成器

using UnityEditor;
using UnityEngine;

public class MyToolWindow : EditorWindow
{
    string newName = "Object";

    [MenuItem("Tools/批量改名工具")]
    public static void ShowWindow() => GetWindow<MyToolWindow>("批量改名");

    void OnGUI()
    {
        GUILayout.Label("改名设置", EditorStyles.boldLabel);
        newName = EditorGUILayout.TextField("新名字", newName);

        if (GUILayout.Button("改名选中物体"))
        {
            foreach (var obj in Selection.objects) obj.name = newName;
        }
    }
}

菜单扩展 在Unity顶部菜单栏或右键菜单添加功能

[MenuItem("GameObject/重置位置", false, 0)]
static void ResetPosition()
{
    if (Selection.activeTransform != null)
        Selection.activeTransform.position = Vector3.zero;
}

SceneView扩展
在场景视图中绘制自定义Gizmos或工具按钮

using UnityEditor;
using UnityEngine;

[CustomEditor(typeof(Transform))]
public class TransformGizmo : Editor
{
    void OnSceneGUI()
    {
        Handles.Label(((Transform)target).position + Vector3.up * 2, "这是一个提示");
    }
}

可以绘制线条、形状、文字等辅助开发

资源导入扩展(AssetPostprocessor) 拦截模型、贴图、音频导入过程,自动修改导入设置

using UnityEditor;

public class MyTextureImporter : AssetPostprocessor
{
    void OnPreprocessTexture()
    {
        var importer = (TextureImporter)assetImporter;
        importer.textureType = TextureImporterType.Sprite;
        importer.mipmapEnabled = false;
    }
}

UnityEditor

UnityEditor是Unity提供的一套专门用于编辑器扩展的API,这些类和方法只能在编辑器里运行,不会包含在游戏打包中;所以,所有用到UnityEditor的代码,必须放在Editor文件夹下

核心作用

主要分成五大类功能

  1. 自定义Inspector和窗口
  1. 菜单和快捷工具
  1. 资源与导入
  1. 场景与物体操作
  1. 调试与分析

注意事项

  1. 不要在运行时脚本里因哟个UnityEditor,否则打包错误
  1. 编辑器API不能在游戏运行时使用,比如AssetDatabase.LoadAssetAtPath打包后无效
  2. 一般项目里会把编辑器扩展集中到

SerializedObject / SerializedProperty

在自定义Inspector的时候,通常会写类似这样的代码

var myComp = (MyComponent)target;
myComp.health = EditorGUILayout.IntField("生命值", myComp.health);

这样确实能显式和修改数值,但有几个严重问题

为了解决这些问题,Unity提供了序列化编辑API

核心概念

类/方法作用
SerializedObject打开 Unity 对象的序列化数据流,可同时针对多个对象
SerializedProperty访问 SerializedObject 内的字段
ApplyModifiedProperties()将修改写回对象,并触发 Undo/Prefab 系统
Update()刷新 SerializedObject,如果对象在外部被修改过,需要先 Update
OnValidate()MonoBehaviour 回调,确保数据合法性(如 Range)

通过SerializedProperty修改数据不会走属性setter,因此需要在OnValidate()或其他地方做数据校验

SerializedObject

SerializedObject就是把一个Unity对象包装成可序列化的版本

SerializedObject so = new SerializedObject(target);

SerializedProperty

SerializedProperty是对单个字段的包装

SerializedProperty healthProp = so.FindProperty("health");

关键点:这里用的是字符串名字(字段名必须是public[SerializeField]
然后用EditorGUILayout.PropertyField绘制

EditorGUILayout.PropertyField(healthProp, new GUIContent("生命值"));

示例

假设有一个脚本

public class MyComponent : MonoBehaviour
{
    public int health = 20;
    [SerializeField] private string playerName = "Hero";
}

对应的自定义Inspector

using UnityEditor;
using UnityEngnine;

[CustomEditor(typeof(MyComponent))]
public class MyComponentEditor : Editor
{
    SerializedObject so;
    SerializedProperty healthProp;
    SerializedProperty nameProp;

    void OnEnable()
    {
        so = new SerializedObject(target); // 包装目标对象
        healthProp = so.FindProperty("health");
        nameProp = so.FindProperty("playerName");
    }

    public override void OnInspectorGUI()
    {
        so.Update(); // 必须,包装数据最新

        EditorGUILayout.PropertyField(healthProp);
        EditorGUILayout.PropertyField(nameProp);

        if (GUILayout.Button("重置生命值"))
            healthProp.intValue = 100; // 修改属性
        
        so.ApplyModifiedProperties(); // 必须,应用修改
    }
}

这样做的好处

注意事项

  1. 多对象编辑
  1. 独立数据流
  1. Undo与Prefab
  1. 字段合法性

EditorGUILayout vs GUILayout

  1. GUILayout
void OnGUI()
{
    GUILayout.Label("Hello World!");
    if (GUILayout.Button("Click Me"))
        Debug.Log("Button clicked!");
    GUILayout.TextField("Input here");
}
  1. EditorGUILayout
using UnityEngine;
using UnityEditor;

[CustomEditor(typeof(MyComponent))]
public class MyComponentEditor : Editor
{
    SerializedProperty speedProp;

    void OnEnable() => speedProp = serializedObject.FindProperty("speed");

    public override void OnInspectorGUI()
    {
        serializedObject.Update();

        EditorGUILayout.PropertyField(speedProp); // 自动绘制 Inspector组件

        if (GUILayout.Button("Reset Speed")) // EditorGUILayout 和 GUILayout都能用
            speedProp.floatValue = 0;
        
        serializedObject.ApplyModifiedProperties();
    }
}
特性GUILayoutEditorGUILayout
所属命名空间UnityEngineUnityEditor
使用场景Runtime 或 Editor GUI编辑器 Inspector / EditorWindow
支持 SerializedProperty直接绑定字段,需要手动操作自动绑定 SerializedProperty,支持 Undo & Prefab
布局方式自动布局自动布局
控件类型Button、Label、TextField、Slider 等PropertyField、ObjectField、EnumPopup、Vector3Field 等
Undo/Inspector 自动刷新noyes

核心点:EditorGUILayout是为编辑器量身定制的GUILayout,它的优势在于可以直接操作SerializedProperty,同时支持Undo、Prefab、Inspector自动刷新等功能

使用关系

Undo.RecordObject

Editor Coroutines


完全没错,UnityEditor 绝对是一个 庞大而深入的主题,可以说它本身就是 Unity 编辑器扩展的核心,涉及的内容从基础到高级,范围非常广。我们可以把它拆解开来更系统地理解。


UnityEditor 的本质


核心模块

  1. Editor 类与 CustomEditor

    • Editor:用于自定义 Inspector。

    • [CustomEditor(typeof(MyComponent))]:绑定你想自定义的组件。

    • 核心方法:

      • OnInspectorGUI():绘制 Inspector UI。
      • serializedObject + SerializedProperty:安全修改组件字段。
  2. EditorWindow

    • 自定义窗口(可以挂在 Unity 窗口系统里)。

    • 核心方法:

      • OnGUI():绘制窗口 UI。
      • Show() / GetWindow<>():打开窗口。
    • 可用于做工具、调试面板、批量操作面板。

  3. GUILayout / EditorGUILayout

    • 自动布局的 GUI 系统。
    • EditorGUILayout 是专门支持 Inspector 的高级封装。
  4. MenuItem & 工具栏扩展

    • [MenuItem("Tools/MyTool")]:自定义菜单。
    • 可以调用你的 EditorWindow 或工具逻辑。
    • 支持快捷键。
  5. Scene 交互

    • Handles:在 Scene 视图中绘制可交互控件(如拖动 gizmo)。
    • EditorGUI / EditorGUILayout 用于 Inspector,Handles 用于 Scene。
  6. Asset / Prefab / Project 操作

    • AssetDatabase:操作资源、导入、创建、重命名、删除。
    • PrefabUtility:操作 Prefab 连接、替换、实例化。
    • EditorSceneManager:操作场景(打开、保存、加载)。
  7. 调试与自动化

    • Debug:编辑器内调试。
    • EditorApplication:监听编辑器生命周期事件(如更新、播放模式切换)。
    • 可做自动化批量处理(例如批量设置组件属性、生成资源、处理场景数据)。

使用层次感

可以把 UnityEditor 理解成三层:

UnityEditor
 ├─ Editor 类体系 → Inspector 自定义
 ├─ EditorWindow → 工具面板、独立窗口
 ├─ 编辑器 API → AssetDatabase, PrefabUtility, SceneManager, Handles
 └─ GUI 系统 → EditorGUILayout, EditorGUI, GUILayout

核心逻辑:Editor 类控制 Inspector,EditorWindow 控制独立窗口,GUI 绘制工具(GUILayout / EditorGUILayout / Handles)显示 UI,其他 API 操作资源和场景。


学习建议

  1. 先从 Editor 与 Inspector 自定义入手

    • 学会 SerializedObject + SerializedProperty,画出组件 Inspector。
  2. 进阶 EditorWindow

    • 写独立工具,熟悉 GUILayout / EditorGUILayout。
  3. Scene 编辑与 Handles

    • 做可拖拽 gizmo,理解 Scene 交互。
  4. Asset / Prefab / Project 操作

    • 用 AssetDatabase 和 PrefabUtility 做批量工具。
  5. 事件与自动化

    • EditorApplication 生命周期,自动化工具和调试。