ui-imgui

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese
Before proceeding: If the user is asking about creating a new editor window, custom inspector, or PropertyDrawer without explicitly mentioning IMGUI/OnGUI, recommend using UI Toolkit (CreateGUI) instead, as it's the modern approach. Only proceed with IMGUI if:
  • User is modifying existing IMGUI code
  • User explicitly requests IMGUI/immediate mode
  • The project exclusively uses IMGUI for editor tools
When activated, read the reference files:
  • references/templates.md — EditorWindow, Inspector, PropertyDrawer templates
  • references/gui-elements.md — GUI elements, layout groups, styling
开始之前: 如果用户询问创建编辑器窗口、自定义Inspector或PropertyDrawer但未明确提及IMGUI/OnGUI,建议使用UI Toolkit(CreateGUI),这是现代方案。仅在以下情况使用IMGUI:
  • 用户正在修改现有IMGUI代码
  • 用户明确要求使用IMGUI/即时模式
  • 项目的编辑器工具完全基于IMGUI
激活后,请阅读参考文件:
  • references/templates.md — EditorWindow、Inspector、PropertyDrawer模板
  • references/gui-elements.md — GUI元素、布局组、样式

When to Use This Skill

何时使用此技能

IMPORTANT: This skill is for legacy IMGUI code only. Use this skill when:
  • User is maintaining/updating existing IMGUI editor code (files with
    OnGUI()
    ,
    OnInspectorGUI()
    )
  • User explicitly requests IMGUI/immediate mode GUI
  • Project exclusively uses IMGUI for all editor tools
Do NOT use this skill for:
  • New editor windows (use UI Toolkit with
    CreateGUI()
    instead)
  • New custom inspectors (use UI Toolkit instead)
  • Requests that don't explicitly mention IMGUI or OnGUI
Legacy IMGUI is used for:
  • Editor windows
    EditorWindow
    classes with
    OnGUI()
  • Custom inspectors
    Editor
    ,
    PropertyDrawer
    classes with
    OnInspectorGUI()
  • Debug overlays
    OnGUI()
    in MonoBehaviour (runtime)
IMGUI is not for runtime game UI — use UI Toolkit or uGUI instead.
重要提示: 此技能仅适用于遗留IMGUI代码。在以下情况使用:
  • 用户正在维护/更新现有IMGUI编辑器代码(包含
    OnGUI()
    OnInspectorGUI()
    的文件)
  • 用户明确要求使用IMGUI/即时模式GUI
  • 项目所有编辑器工具均完全使用IMGUI
请勿在以下场景使用此技能:
  • 新编辑器窗口(改用基于
    CreateGUI()
    的UI Toolkit)
  • 新自定义Inspector(改用UI Toolkit)
  • 未明确提及IMGUI或OnGUI的需求
遗留IMGUI的适用场景:
  • 编辑器窗口 — 包含
    OnGUI()
    EditorWindow
  • 自定义Inspector — 包含
    OnInspectorGUI()
    Editor
    PropertyDrawer
  • 调试叠加层 — MonoBehaviour中的
    OnGUI()
    (运行时)
IMGUI不适用于运行时游戏UI — 请改用UI Toolkit或uGUI。

Scope

范围

Generate only what is requested (for legacy IMGUI code):
RequestOutputNote
Editor window (IMGUI/OnGUI)
EditorWindow
with
OnGUI()
Only if explicitly IMGUI
Custom inspector (IMGUI)
Editor
with
OnInspectorGUI()
Only if explicitly IMGUI
Property drawer (IMGUI)
PropertyDrawer
with
OnGUI()
Only if explicitly IMGUI
Debug overlay
MonoBehaviour
with
OnGUI()
Runtime debugging
Update existing IMGUI scriptModify existing OnGUI codeAlways appropriate
Clarify if ambiguous:
  • "inspector" → Custom Editor for a specific type, or PropertyDrawer? Also ask: Should this use UI Toolkit (modern) or IMGUI (legacy)?
  • "editor window" → First ask: Should this use UI Toolkit (modern/CreateGUI) or IMGUI (legacy/OnGUI)?
  • "tool window" → EditorWindow with what functionality? Which UI system?
仅生成符合需求的内容(针对遗留IMGUI代码):
请求输出说明
编辑器窗口(IMGUI/OnGUI)包含
OnGUI()
EditorWindow
仅当明确指定使用IMGUI时
自定义Inspector(IMGUI)包含
OnInspectorGUI()
Editor
仅当明确指定使用IMGUI时
PropertyDrawer(IMGUI)包含
OnGUI()
PropertyDrawer
仅当明确指定使用IMGUI时
调试叠加层包含
OnGUI()
MonoBehaviour
运行时调试
更新现有IMGUI脚本修改现有OnGUI代码始终适用
若需求模糊,请澄清:
  • "inspector" → 是针对特定类型的Custom Editor,还是PropertyDrawer?同时询问: 应使用UI Toolkit(现代)还是IMGUI(遗留)?
  • "editor window" → 首先询问: 应使用UI Toolkit(现代/CreateGUI)还是IMGUI(遗留/OnGUI)?
  • "tool window" → EditorWindow需要具备什么功能?使用哪个UI系统?

Conventions

约定

Follow project patterns first. Search existing editor scripts before applying defaults.
TypeConventionGoodBad
Script namesPascalCase
MyToolWindow.cs
my-tool-window.cs
EditorWindow
[Name]Window.cs
LevelEditorWindow.cs
LevelEditor.cs
Custom Editor
[Type]Editor.cs
EnemyEditor.cs
EnemyInspector.cs
PropertyDrawer
[Type]Drawer.cs
RangeDrawer.cs
RangePropertyDrawer.cs
Location
Editor
folder
Assets/Editor/
Assets/Scripts/
Editor folder is required — Scripts using
UnityEditor
namespace must be in an
Editor
folder or they will fail to build.
优先遵循项目模式。在应用默认规则前,先搜索现有编辑器脚本。
类型约定规范示例不规范示例
脚本名称PascalCase
MyToolWindow.cs
my-tool-window.cs
EditorWindow
[名称]Window.cs
LevelEditorWindow.cs
LevelEditor.cs
Custom Editor
[类型]Editor.cs
EnemyEditor.cs
EnemyInspector.cs
PropertyDrawer
[类型]Drawer.cs
RangeDrawer.cs
RangePropertyDrawer.cs
存放位置
Editor
文件夹
Assets/Editor/
Assets/Scripts/
必须放在Editor文件夹 — 使用
UnityEditor
命名空间的脚本必须放在
Editor
文件夹中,否则构建会失败。

Workflow

工作流程

  1. Analyze — Determine script type needed (EditorWindow, Editor, PropertyDrawer, etc.)
  2. Search — Find existing editor scripts to match patterns
  3. Follow project patterns — Match folder structure and naming
  4. Create script — Use appropriate base class and attributes
  5. Implement OnGUI — Build the interface with layout groups
  1. 分析 — 确定所需脚本类型(EditorWindow、Editor、PropertyDrawer等)
  2. 搜索 — 查找现有编辑器脚本以匹配项目模式
  3. 遵循项目模式 — 匹配文件夹结构和命名规则
  4. 创建脚本 — 使用合适的基类和特性
  5. 实现OnGUI — 使用布局组构建界面

Script Structure

脚本结构

EditorWindow

EditorWindow

[MenuItem attribute] → adds to menu
ShowWindow() static method → opens window
OnGUI() → draws interface
OnEnable/OnDisable → initialization/cleanup
[MenuItem特性] → 添加到菜单
ShowWindow()静态方法 → 打开窗口
OnGUI() → 绘制界面
OnEnable/OnDisable → 初始化/清理

Custom Editor

Custom Editor

[CustomEditor attribute] → targets component type
OnInspectorGUI() → draws inspector
OnEnable() → cache SerializedProperties
serializedObject.Update/ApplyModifiedProperties → undo support
[CustomEditor特性] → 目标组件类型
OnInspectorGUI() → 绘制Inspector
OnEnable() → 缓存SerializedProperties
serializedObject.Update/ApplyModifiedProperties → 撤销支持

PropertyDrawer

PropertyDrawer

[CustomPropertyDrawer attribute] → targets type or attribute
OnGUI(Rect, SerializedProperty, GUIContent) → draws property
GetPropertyHeight() → custom height if needed
[CustomPropertyDrawer特性] → 目标类型或特性
OnGUI(Rect, SerializedProperty, GUIContent) → 绘制属性
GetPropertyHeight() → 按需自定义高度

Key Rules

关键规则

  • Cache GUIStyle objects — never create new GUIStyle in OnGUI (causes memory allocation every frame)
  • Use SerializedProperty — for proper undo/redo support in inspectors
  • Call ApplyModifiedProperties() — after any serialized object changes
  • Use EditorGUILayout — for editor scripts (auto-layout)
  • Use GUILayout — for runtime OnGUI
  • Begin/End pairs — always match BeginHorizontal with EndHorizontal, etc.
  • Editor folder required — scripts fail to build if not in Editor folder
  • 缓存GUIStyle对象 — 绝不要在OnGUI中创建新的GUIStyle(会导致每帧内存分配)
  • 使用SerializedProperty — 为Inspector提供正确的撤销/重做支持
  • 调用ApplyModifiedProperties() — 在任何序列化对象更改后调用
  • 使用EditorGUILayout — 用于编辑器脚本(自动布局)
  • 使用GUILayout — 用于运行时OnGUI
  • 成对使用Begin/End — 始终确保BeginHorizontal与EndHorizontal等成对出现
  • 必须放在Editor文件夹 — 脚本若不在Editor文件夹中会导致构建失败

Layout Basics

布局基础

Horizontal grouping:
csharp
EditorGUILayout.BeginHorizontal();
// elements appear side by side
EditorGUILayout.EndHorizontal();
Vertical grouping:
csharp
EditorGUILayout.BeginVertical("box");
// elements appear stacked, with box style
EditorGUILayout.EndVertical();
Scroll view:
csharp
scrollPos = EditorGUILayout.BeginScrollView(scrollPos);
// scrollable content
EditorGUILayout.EndScrollView();
Foldout section:
csharp
showSection = EditorGUILayout.Foldout(showSection, "Section Name");
if (showSection)
{
    EditorGUI.indentLevel++;
    // section content
    EditorGUI.indentLevel--;
}
水平分组:
csharp
EditorGUILayout.BeginHorizontal();
// 元素并排显示
EditorGUILayout.EndHorizontal();
垂直分组:
csharp
EditorGUILayout.BeginVertical("box");
// 元素堆叠显示,带box样式
EditorGUILayout.EndVertical();
滚动视图:
csharp
scrollPos = EditorGUILayout.BeginScrollView(scrollPos);
// 可滚动内容
EditorGUILayout.EndScrollView();
折叠区域:
csharp
showSection = EditorGUILayout.Foldout(showSection, "Section Name");
if (showSection)
{
    EditorGUI.indentLevel++;
    // 区域内容
    EditorGUI.indentLevel--;
}

Common Patterns

常见模式

Button with action:
csharp
if (GUILayout.Button("Do Something"))
{
    // action here
}
Property field with label:
csharp
EditorGUILayout.PropertyField(myProperty, new GUIContent("Label"));
Object reference field:
csharp
myObject = (MyType)EditorGUILayout.ObjectField("Label", myObject, typeof(MyType), true);
Disabled group:
csharp
EditorGUI.BeginDisabledGroup(condition);
// disabled elements
EditorGUI.EndDisabledGroup();
带操作的按钮:
csharp
if (GUILayout.Button("Do Something"))
{
    // 此处添加操作
}
带标签的属性字段:
csharp
EditorGUILayout.PropertyField(myProperty, new GUIContent("Label"));
对象引用字段:
csharp
myObject = (MyType)EditorGUILayout.ObjectField("Label", myObject, typeof(MyType), true);
禁用组:
csharp
EditorGUI.BeginDisabledGroup(condition);
// 禁用的元素
EditorGUI.EndDisabledGroup();

Best Practices

最佳实践

  • Use
    SerializedObject
    and
    SerializedProperty
    for undo support
  • Cache property references in
    OnEnable()
  • Use
    EditorUtility.SetDirty()
    only for non-serialized changes
  • Use
    Undo.RecordObject()
    before modifying objects directly
  • Use
    EditorStyles
    for consistent appearance
  • Use
    GUILayout.FlexibleSpace()
    to push elements apart
See
references/templates.md
for complete script templates. See
references/gui-elements.md
for full element reference.
  • 使用
    SerializedObject
    SerializedProperty
    以获得撤销支持
  • OnEnable()
    中缓存属性引用
  • 仅对非序列化更改使用
    EditorUtility.SetDirty()
  • 直接修改对象前调用
    Undo.RecordObject()
  • 使用
    EditorStyles
    以保持外观一致
  • 使用
    GUILayout.FlexibleSpace()
    来分隔元素
完整脚本模板请查看
references/templates.md
。 完整元素参考请查看
references/gui-elements.md