Godot 编辑器插件开发 1
通过编辑器插件,我们可以为原生编辑器新增各类自定义能力,常见实用场景如下:
-
新增编辑器快捷按钮、自定义快捷键
-
搭建专属自定义停靠面板、功能界面
-
定制节点属性检查器展示样式
-
实现自定义资源导入器、专属节点类型
-
开发自动化工具(自动生成碰撞体、批量处理资源等)
-
搭建对话编辑器、关卡管理器等专属功能模块
几乎所有编辑器个性化需求,都可以通过现有插件或自定义插件实现。但插件运行在编辑器内核中,若未掌握 @tool 注解、插件生命周期核心规则,极易引发编辑器卡顿、崩溃、内存泄漏等问题。
本文将从零起步,从基础核心语法到实战案例,循序渐进讲解插件开发,带你掌握自定义停靠面板、工具栏按钮、专属属性检查器三大核心插件功能。
基础:@tool 注解
@tool 是 Godot 编辑器扩展开发的必备注解。在脚本头部添加该注解后,当前脚本将不再仅运行于游戏运行时,而是可以在编辑器环境中直接执行。
所有编辑器插件主脚本、编辑器预览脚本、自定义编辑器UI脚本,都必须添加 @tool 注解,否则无法在编辑器中生效。
编辑器与运行时逻辑分离
添加 @tool 后,脚本逻辑会同时作用于编辑器和游戏运行场景。我们必须通过Engine.is_editor_hint() 做逻辑分支判断,严格区分编辑器编辑逻辑和游戏运行逻辑,避免游戏逻辑在编辑器中异常执行。
@toolextends Node2D# 帧更新逻辑func _process(delta):# 仅在编辑器环境执行预览、绘制等编辑逻辑if Engine.is_editor_hint():queue_redraw()# 仅在游戏运行时执行游戏核心逻辑else:move_character(delta)
未做逻辑分支判断,会导致游戏运行代码在编辑器中执行,引发数据异常、编辑器报错甚至崩溃。
@tool 核心应用场景
@tool 广泛应用于各类编辑器自定义场景:
|
应用场景 |
详细说明 |
|---|---|
|
自定义编辑器绘制 |
通过 |
|
属性实时预览 |
监听 |
|
编辑器插件开发 |
所有继承 EditorPlugin 的插件主脚本,必须添加该注解(强制要求) |
实战:属性联动实时绘制
在属性检查器中修改半径数值时,编辑器内实时刷新圆形范围预览,仅编辑器生效,不影响游戏运行逻辑。
@toolextends Sprite2D# 导出可编辑半径属性,绑定属性修改回调@export var radius: float = 100.0:set(value):radius = valuequeue_redraw() # 属性变更后触发重绘# 编辑器绘制逻辑func _draw():# 仅编辑器环境执行绘制if Engine.is_editor_hint():# 绘制半透明绿色圆形范围预览draw_circle(Vector2.ZERO, radius, Color(0, 1, 0, 0.3))
插件基础结构与配置
掌握 @tool 基础后,我们正式开始搭建标准 Godot 编辑器插件框架。Godot 插件拥有固定的目录和配置规范,编辑器可自动识别、加载和启用插件。
插件标准目录结构
所有自定义插件必须放置在项目根目录的 addons 文件夹中(无该文件夹可手动创建),单插件独立文件夹隔离,结构清晰、便于维护。
addons/└── my_plugin/ # 自定义插件根目录(插件名)├── plugin.cfg # 插件核心配置文件(必须存在)├── my_plugin.gd # 插件主脚本(生命周期入口)└── dock/ # 自定义停靠面板资源目录(可选)└── my_dock.tscn # 停靠面板场景文件
目录命名为 addons 而非 plugins,是因为 Godot 将所有引擎附加扩展工具统一归类为附加组件,而 编辑器插件 特指继承自 EditorPlugin 的标准化扩展脚本。
插件配置文件 plugin.cfg
plugin.cfg 是插件的唯一识别配置文件,用于定义插件名称、作者、版本、入口脚本等核心信息,编辑器依靠该文件识别插件。
[plugin]name="我的自定义编辑器插件"description="实现自定义停靠面板、工具栏按钮、属性检查器扩展"author="开发者名称"version="1.0.0"script="my_plugin.gd" # 绑定插件主脚本(相对路径)
插件主脚本基础生命周期
插件主脚本必须继承 EditorPlugin 类,并实现两大核心生命周期函数,这是插件运行的核心规则:
-
_enter_tree():插件启用/编辑器加载时触发,用于初始化UI、注册功能 -
_exit_tree():插件禁用/编辑器关闭时触发,用于销毁UI、释放资源(核心避坑点)
@toolextends EditorPlugin# 插件启用、加载时执行func _enter_tree():print("我的插件:加载成功!")# 插件禁用、卸载时执行func _exit_tree():print("我的插件:卸载成功!")
插件启用步骤
-
将完整插件目录放入项目
addons文件夹,刷新项目文件; -
点击顶部菜单栏 项目 → 项目设置 → 插件,进入插件管理面板;
-
在插件列表中找到自己的插件,勾选前方复选框,即可启用插件;
-
启用后编辑器实时加载插件功能,禁用后立即卸载。
实战:自定义编辑器停靠面板
自定义停靠面板是最常用的编辑器扩展方式,可实现常驻编辑器的自定义功能界面,常用于调试面板、资源预览、批量工具、参数配置等场景。
实现停靠面板挂载
通过 add_control_to_dock() 函数可将自定义场景挂载到编辑器指定停靠区域,插件卸载时必须手动移除并释放资源。
@toolextends EditorPluginvar dock: Control # 定义停靠面板根节点变量# 插件加载:初始化并挂载停靠面板func _enter_tree():# 预加载并实例化自定义面板场景dock = preload("res://addons/my_plugin/dock/my_dock.tscn").instantiate()# 挂载到编辑器左上停靠区域add_control_to_dock(DOCK_SLOT_LEFT_UL, dock)# 插件卸载:销毁面板、释放资源func _exit_tree():# 空值校验,避免报错if dock:remove_control_from_docks(dock)dock.queue_free()
停靠面板位置常量
Godot 编辑器预设4个停靠区域,可根据需求自由选择挂载位置:
|
位置常量 |
对应编辑器位置 |
|---|---|
|
DOCK_SLOT_LEFT_UL |
左侧面板 – 上方区域 |
|
DOCK_SLOT_LEFT_BL |
左侧面板 – 下方区域 |
|
DOCK_SLOT_RIGHT_UL |
右侧面板 – 上方区域 |
|
DOCK_SLOT_RIGHT_BL |
右侧面板 – 下方区域 |
制作停靠面板UI场景
停靠面板本质是普通UI场景,必须以 Control 系列节点作为根节点(推荐 VBoxContainer/HBoxContainer),可自由添加按钮、文本、输入框等UI控件。
面板逻辑脚本(my_dock.gd)
@toolextends VBoxContainer# 绑定场景内UI控件@onready var status_label: Label = $StatusLabel@onready var run_btn: Button = $RunButtonfunc _ready():# 绑定按钮点击信号run_btn.pressed.connect(_on_run_click)# 自定义按钮点击逻辑func _on_run_click():status_label.text = "执行中..."# 自定义工具逻辑(可拓展批量处理、校验等功能)status_label.text = "执行完成!操作成功"
停靠面板独立于主插件脚本,如需和编辑器核心交互,可通过信号传参、插件主脚本调用等方式实现。
实战:自定义编辑器工具栏按钮
对于单次触发、无需常驻界面的工具功能(一键校验、批量导出、快速重置等),可使用工具栏按钮实现,更加轻便简洁。
实现工具栏按钮
@toolextends EditorPluginvar tool_btn: Button# 插件加载:创建并挂载工具栏按钮func _enter_tree():# 实例化按钮tool_btn = Button.new()tool_btn.text = "自定义工具按钮"# 绑定点击事件tool_btn.pressed.connect(_on_tool_btn_click)# 挂载到编辑器顶部主工具栏add_control_to_container(CONTAINER_TOOLBAR, tool_btn)# 插件卸载:销毁按钮资源func _exit_tree():if tool_btn:remove_control_from_container(CONTAINER_TOOLBAR, tool_btn)tool_btn.queue_free()# 按钮点击回调逻辑func _on_tool_btn_click():print("自定义工具栏按钮已触发!")push_warning("工具执行成功") # 编辑器弹窗提示
编辑器容器位置常量
除顶部工具栏外,还可将自定义控件挂载到编辑器多个内置容器:
|
容器常量 |
对应编辑器位置 |
|---|---|
|
CONTAINER_TOOLBAR |
编辑器顶部主工具栏 |
|
CONTAINER_SPATIAL_EDITOR_MENU |
3D 编辑器菜单栏 |
|
CONTAINER_CANVAS_EDITOR_MENU |
2D 编辑器菜单栏 |
|
CONTAINER_INSPECTOR_BOTTOM |
属性检查器底部区域 |
实战:自定义属性检查器插件
Godot 编辑器默认自动展示节点属性,通过 EditorInspectorPlugin 类,可针对指定节点类型,定制专属的属性检查器UI,实现属性美化、附加信息展示、自定义操作等功能。
功能:选中 CharacterBody2D 节点时,在属性面板新增专属角色信息展示,自定义移动速度属性的显示样式。
主插件注册检查器插件
在主插件脚本中注册自定义属性检查器,插件卸载时同步注销,避免内存泄漏。
@toolextends EditorPluginvar custom_inspector: MyInspectorPluginfunc _enter_tree():# 实例化并注册自定义属性检查器插件custom_inspector = MyInspectorPlugin.new()add_inspector_plugin(custom_inspector)func _exit_tree():# 注销并释放检查器资源if custom_inspector:remove_inspector_plugin(custom_inspector)custom_inspector.queue_free()
自定义检查器逻辑
新建脚本继承 EditorInspectorPlugin,实现节点匹配、自定义UI绘制、属性重写等核心逻辑。
@toolclass_name MyInspectorPluginextends EditorInspectorPlugin# 判断当前节点是否由本检查器接管func _can_handle(object: Object) -> bool:# 仅对 CharacterBody2D 节点生效return object is CharacterBody2D# 在属性面板顶部添加自定义UI(节点选中时触发)func _parse_begin(object: Object):var title_label = Label.new()title_label.text = "===== 角色专属信息面板 ====="title_label.custom_minimum_size.x = 200add_custom_control(title_label)# 拦截并自定义指定属性的展示样式func _parse_property(object, type, name, hint_type, hint_string, usage_flags, wide):# 定制 speed 移动速度属性展示if name == "speed":var speed_label = Label.new()speed_label.text = "当前移动速度:" + str(object.speed)add_custom_control(speed_label)return true # 拦截原生属性展示,使用自定义样式return false
插件开发最佳实践
编辑器插件运行在引擎内核环境,资源管理不当会直接导致编辑器崩溃、内存泄漏、卡顿报错,以下是官方推荐开发规范与避坑要点。
|
注意事项 |
详细开发建议 |
|---|---|
|
空值强制校验 |
所有UI控件、插件对象在销毁前,必须做空值判断,避免空指针报错 |
|
逻辑环境分离 |
全程使用 |
|
资源彻底清理 |
|
|
统一资源预加载 |
插件资源、场景、素材统一使用 |
|
标准化异常提示 |
使用 |
案例对比
错误写法(会导致内存泄漏、编辑器崩溃)
func _exit_tree():# 未清理任何资源,控件残留内存,插件重复启用会叠加报错pass
规范写法
func _exit_tree():# 清理停靠面板if dock:remove_control_from_docks(dock)dock.queue_free()# 清理属性检查器插件if custom_inspector:remove_inspector_plugin(custom_inspector)custom_inspector.queue_free()# 清理工具栏按钮if tool_btn:remove_control_from_container(CONTAINER_TOOLBAR, tool_btn)tool_btn.queue_free()
总结
@tool 注解:编辑器扩展开发基础,让脚本在编辑器环境运行,必须通过 Engine.is_editor_hint() 分离双环境逻辑;
插件基础框架:遵循addons 目录规范,通过 plugin.cfg 配置插件信息,依托 EditorPlugin 生命周期管理插件;
三大插件功能:可自定义停靠面板(常驻界面)、工具栏按钮(快捷操作)、节点专属属性检查器;
核心开发原则:插件卸载时必须彻底清理所有自定义资源,做空值校验,杜绝内存泄漏和编辑器异常。
夜雨聆风