关于 godot-ui
面向 Godot 4.3+ 的 UI 技能,涵盖 Control 节点、布局、主题、焦点与常见界面模式,为使用 GDScript 或 C# 构建游戏界面的开发者提供指导。
主要功能
- 01Control 层级与布局
- 02Container 和锚点指南
- 03Theme 与 StyleBox 设置
- 04键盘和手柄焦点导航
- 05菜单、设置和暂停界面模式
- 06信号与可折叠 UI 元素
适用场景
- 01构建主菜单或设置界面
- 02安排 HUD 或对话框面板
- 03支持键盘和手柄导航
- 04制作可折叠面板和多层标签效果
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ jame581/ godotprompter --skill godot-ui安装后在 Claude Code 中输入/godot-ui确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/anchors-in-code.mdfocus-and-navigation.mdfoldable-container.mdsignals.mdtheme-system.mdui-patterns.md详细介绍
Godot UI——Control 节点、主题与布局
所有示例均面向 Godot 4.3+,不使用已弃用的 API;优先使用 GDScript,其次是 C#。
相关技能: 多分辨率缩放请参阅 responsive-ui,游戏内 HUD 模式请参阅 hud-system,对话 UI 展示请参阅 dialogue-system,UI 过渡与动画效果请参阅 tween-animation。
1. Control 节点层级
Control 与 Node2D 的区别
Control 是所有 UI 节点的基类——它位于与 Node2D/Node3D 不同的场景树分支中,采用完全不同的布局模型。
| 特性 | Node2D | Control |
|---|---|---|
| 位置模型 | 世界空间中的 position(相对于父节点的像素坐标) | 相对于父节点矩形的锚点和偏移量 |
| 大小 | 无固有大小 | 具有 size、custom_minimum_size 和计算得出的最小尺寸(get_combined_minimum_size()) |
| 主题 | 无 | 继承并覆盖 Theme 资源 |
| 焦点 | 不适用 | 内置焦点系统(focus_mode、grab_focus()) |
| 鼠标事件 | 通过 _input 手动处理 | gui_input、mouse_entered、mouse_exited |
| 布局辅助项 | 无 | Container 子类会自动排列子节点 |
Control 作为基类
每个 UI 控件(Button、Label、LineEdit 等)都继承自 Control。Control 本身定义的关键属性包括:
anchor_left、anchor_top、anchor_right、anchor_bottom——相对于父节点矩形的比例值(0.0–1.0)offset_left、offset_top、offset_right、offset_bottom——锚点解析后应用的像素偏移量size_flags_horizontal、size_flags_vertical——节点参与Container布局的方式theme——Theme资源;查找时会从最近的祖先Control/Window开始,逐级检查拥有主题的节点,并在遇到第一个既不是Control也不是Window的父节点时停止(例如CanvasLayer或Node2D)focus_mode——节点是否可以接收键盘/游戏手柄焦点
将 UI 节点放在 CanvasLayer 中,使其渲染在 3D/2D 世界上方,并且不受 Camera2D 变换影响。场景根节点内置画布(第 0 层)上的控件会随 Camera2D 移动,因为摄像机会设置该画布的变换。
⚠️ Godot 4.7 中的变更:
Control.accessibility_live的类型从DisplayServer.AccessibilityLiveMode变为AccessibilityServer.AccessibilityLiveMode(默认值为LIVE_OFF = 0,另有LIVE_POLITE、LIVE_ASSERTIVE)——无障碍枚举/API 已移至新的AccessibilityServer单例。与 GDScript 兼容;会破坏 C# 二进制/源代码兼容性(需针对新枚举重新构建)。请参阅 4.7 迁移指南。
2. 常见容器节点
| 容器 | 用途 | 适用场景 |
|---|---|---|
VBoxContainer | 垂直排列子节点 | 列表、选项行、垂直菜单 |
HBoxContainer | 水平排列子节点 | 工具栏、状态行、水平导航 |
GridContainer | 将子节点排列成固定列数的网格 | 物品栏网格、按键绑定表 |
MarginContainer | 为单个子节点添加边距 | 包装任意节点,为其留出空间 |
PanelContainer | 绘制 StyleBox 背景,然后排列子节点 | 卡片 UI、对话框、HUD 面板 |
ScrollContainer | 使其单个子节点可滚动;裁剪溢出内容 | 长列表、日志、可滚动设置界面 |
TabContainer | 将子节点排列为带名称的选项卡;一次显示一个 | 设置界面、多分区面板 |
尺寸设置提示:
- 对需要填满可用空间的子节点,将
size_flags_horizontal = SIZE_EXPAND_FILL。 - 使用
custom_minimum_size防止子节点收缩到零。 MarginContainer从主题属性margin_*读取边距;可在运行时通过add_theme_constant_override("margin_left", 16)覆盖。
Godot 4.7+:
custom_maximum_size(Vector2(-1, -1))按轴限制尺寸,其优先级高于custom_minimum_size;propagate_maximum_size(默认值为false)使父节点的最大尺寸约束其 Control 子节点;_get_maximum_size()可从代码计算最大尺寸。
⚠️ Godot 4.7 中的变更:
TabContainer.all_tabs_in_front已弃用——现在不再起作用,因为选项卡始终位于前景。请移除设置该属性的代码。参见 GH-118623。
3. 锚点与边距
锚点预设的工作原理
锚点是父级矩形上的一个点,以分数表示(0 = 上边缘/左边缘,1 = 下边缘/右边缘)。Godot 按以下方式计算每条边的最终像素位置:
final_left = parent_width * anchor_left + offset_left
final_top = parent_height * anchor_top + offset_top
final_right = parent_width * anchor_right + offset_right
final_bottom = parent_height * anchor_bottom + offset_bottom
编辑器提供了内置预设:
| 预设 | 锚点值 | 用途 |
|---|---|---|
| 完整矩形 | L=0, T=0, R=1, B=1 | 覆盖/填充父级——根 UI 最常用 |
| 居中 | L=0.5, T=0.5, R=0.5, B=0.5 | 在父级中居中的固定尺寸组件 |
| 左上 | L=0, T=0, R=0, B=0 | 固定尺寸组件,固定在左上角 |
| 右上 | L=1, T=0, R=1, B=0 | 固定尺寸组件,固定在右上角 |
| 底部居中 | L=0.5, T=1, R=0.5, B=1 | 锚定在底部中央的 HUD 元素 |
在代码中设置锚点
每条边的锚点都按 parent_size * anchor + offset 计算,因此手动设置时需要设置 8 个属性。set_anchors_and_offsets_preset(Control.PRESET_*) 可以通过一次调用完成这些设置——使用该方法,然后调整 offset_* 设置边距(右侧/底部使用负值)。
锚点与偏移量的规则(将偏移量保持为 0,让锚点负责定位),以及完整的 GDScript + C# 示例——完整矩形填充、带 16 px 边距的右上 HUD、自定义半屏侧边面板:references/anchors-in-code.md
4. 主题系统
Theme 资源集中管理字体、颜色和 StyleBox。在根节点应用主题,让继承机制处理其余部分;仅在需要单独调整时使用 theme_override_*。StyleBoxFlat 可满足大多数扁平化设计需求(bg_color、border_color、corner_radius_*、border_width_*);纹理则使用 StyleBoxTexture。
完整的 Theme 资源创建指南、StyleBoxFlat 属性、字体覆盖、主题继承规则,以及各节点的
theme_override_*方法,请参见 references/theme-system.md。
Godot 4.7+:
GradientTexture2D的Fill枚举新增FILL_CONIC——颜色按圆锥(角度)模式插值;无需着色器即可制作径向进度/冷却指示器(C#:FillEnum.Conic)。
5. 焦点与导航
焦点模式(FOCUS_NONE、FOCUS_CLICK、FOCUS_ALL)控制键盘/游戏手柄导航。使用 focus_neighbor_top / _bottom / _left / _right 配置焦点链,或依靠自动空间检测。菜单打开时,对第一个可交互元素调用 grab_focus()。
焦点模式详情、
focus_neighbor焦点链示例、游戏手柄/键盘输入处理,以及grab_focus用法,请参阅 references/focus-and-navigation.md。
6. 常见 UI 模式
三种典型场景:主菜单(居中的 VBoxContainer,包含标题和按钮列表)、带标签页的设置界面(TabContainer,每个类别对应一个子面板),以及暂停菜单覆盖层(全矩形 ColorRect 背景加居中的选项面板,通过 get_tree().paused = true 暂停)。
每种模式的完整场景树片段和 GDScript 配置,请参阅 references/ui-patterns.md。
Godot 4.7+:
offset_transform_*— 仅影响视觉效果的 UI 动效变换(抖动/脉冲),不会重新触发容器布局;_get_cursor_shape(at_position)— 按位置设置光标形状;PopupMenu搜索栏(search_bar_enabled,默认使用模糊搜索)以及用于重新排序的set_item_index();TextureRect的STRETCH_TILE现在支持平铺AtlasTexture(仅不支持非零margin)。代码见:references/ui-patterns.md。
⚠️ Godot 4.7 中的变更:
RichTextLabel.add_image()/update_image()的尺寸设置已重做 —width/height现在是float;width_in_percent/height_in_percent布尔值改为width_unit/height_unit,并使用新的ImageUnit枚举(IMAGE_UNIT_PIXEL、IMAGE_UNIT_PERCENT、IMAGE_UNIT_EM— em 随字体大小缩放)。ImageUpdateMask.UPDATE_WIDTH_IN_PERCENT已重命名为UPDATE_WIDTH_UNIT,使用旧名称的 GDScript 将无法运行。请参阅 4.7 迁移指南。
7. 信号
点击使用 Button.pressed,节点上的原始事件使用 Control.gui_input,悬停使用 Control.mouse_entered / mouse_exited。在 _ready() 中连接,或通过检查器的 Node 面板连接。
完整的信号目录和信号驱动的 UI 更新模式,请参阅 references/signals.md。
8. FoldableContainer(Godot 4.5+)
FoldableContainer 是 Godot 4.5 新增的内置手风琴式 Container — 包含一个切换标题和可折叠的子项,可取代以往将 Button 连接到显示/隐藏 VBoxContainer 的繁琐写法。设置 title,设置 folded 作为初始状态,照常添加子项,并监听 folding_changed(is_folded)。
完整的 GDScript + C# 构建示例、关键属性表和切换信号:references/foldable-container.md
9. 叠加式标签效果(Godot 4.5+)
Godot 4.5 允许 Label 通过其 LabelSettings 资源叠加多个轮廓和阴影 — 例如,使用不同宽度/颜色的两个轮廓,再加上柔和的投影。叠加效果配置在 LabelSettings 上(按索引设置),而非主题覆盖中;RichTextLabel 没有对应功能。此前,要叠加多个轮廓,必须复制并手动分层放置 Label 节点。
# Stacked effects live on LabelSettings and are configured per index.
func apply_stacked_outlines(label: Label) -> void:
var settings := LabelSettings.new()
settings.outline_size = 4 # base (inner) outline
settings.outline_color = Color.BLACK
settings.add_stacked_outline() # stacked outline 0, drawn outside the base one
settings.set_stacked_outline_size(0, 8)
settings.set_stacked_outline_color(0, Color.GOLD)
settings.add_stacked_shadow() # stacked shadow 0
settings.set_stacked_shadow_offset(0, Vector2(3, 3))
settings.set_stacked_shadow_color(0, Color(0.0, 0.0, 0.0, 0.5))
settings.set_stacked_shadow_outline_size(0, 2)
label.label_settings = settings # takes priority over theme properties
public void ApplyStackedOutlines(Label label)
{
var settings = new LabelSettings { OutlineSize = 4, OutlineColor = Colors.Black };
settings.AddStackedOutline();
settings.SetStackedOutlineSize(0, 8);
settings.SetStackedOutlineColor(0, Colors.Gold);
settings.AddStackedShadow();
settings.SetStackedShadowOffset(0, new Vector2(3, 3));
settings.SetStackedShadowColor(0, new Color(0f, 0f, 0f, 0.5f));
settings.SetStackedShadowOutlineSize(0, 2);
label.LabelSettings = settings;
}
RichTextLabel 无法叠加效果;它通过 BBCode 为每段文本设置一个轮廓:[outline_size=4][outline_color=#000000]Level Up![/outline_color][/outline_size]。
编辑器工作流: 在 Label 的 Label Settings 属性中创建
LabelSettings资源,并在其叠加轮廓和叠加阴影列表中添加条目。上面的按索引调用适用于动态场景。
10. 检查清单
- 根 UI
Control的锚点预设为 Full Rect(或适合布局的预设) - 所有交互式控件(
Button、LineEdit、Slider)均设置了focus_mode = FOCUS_ALL - 装饰性节点(
Label、TextureRect)均设置了focus_mode = FOCUS_NONE - 为非线性布局设置焦点邻居,确保手柄导航能够正确循环
- 每个屏幕都在
_ready()中对第一个交互式控件调用grab_focus() - 暂停菜单的根
Control设置了process_mode = PROCESS_MODE_ALWAYS - 在屏幕根节点上指定一个
Theme资源,而不是在每个子节点上重复指定 - 简单的纯色面板使用
StyleBoxFlat,而非图像资源 - 单个节点的覆盖项使用
add_theme_*_override(),而非指定一个全新的Theme - 使用容器(
VBoxContainer、HBoxContainer等)进行布局,而非手动设置position值 - 为不得缩小为零的控件设置
custom_minimum_size - 滑块和音量代码使用
linear_to_db/db_to_linear,而非将原始线性值映射到音频总线 - 在
_ready()中(或通过编辑器)连接信号;不要在_process中轮询 UI 状态 -
TabContainer中的标签页顺序与逻辑阅读/导航顺序一致 - 手风琴式可折叠面板使用
FoldableContainer,而非手动连接Button和VBoxContainer(Godot 4.5+) -
Label上的多层轮廓/阴影使用LabelSettings堆叠轮廓/阴影,而非重复创建节点(Godot 4.5+)