Godot UI / Control 节点(4.x)
使用 Control 锚点和 Container 节点布置响应式 UI,使用 Theme 设置样式,并使其可通过键盘和手柄导航。目标版本为 Godot 4.7。
何时使用
- 使用
Control派生节点构建 HUD、菜单、物品栏、对话框或设置界面;布置适配窗口大小的 UI;设置主题;或为手柄/键盘连接焦点导航时使用。
何时不要使用: 世界内 2D 节点(Node2D/精灵)→ godot-nodes-scenes;动画化 UI 过渡 → godot-animation(Tween);卡牌手牌等类型 UI → card-game/visual-novel。完整输入重绑定 → input-systems。
核心工作流
- UI 使用
Control节点,而不是Node2D。Control 具有矩形(位置 + 尺寸)、锚点,并参与焦点/主题设置。 - 使用锚点实现响应式。 锚点是 Control 边缘吸附到的父节点矩形的比例(0–1)。使用编辑器的 Layout 预设(Top-Left、Full Rect、Center 等),而不是手动放置像素。
- 让 Container 定位子节点。 将子节点放入
VBoxContainer、HBoxContainer、GridContainer、MarginContainer等容器 — 容器设置它们的位置/尺寸;你通过size_flags控制流。不要在容器内设置子节点锚点(这会覆盖它们)。 - 使用
Theme设置样式。 在顶层 Control 上分配一个Theme资源;子节点会继承它。仅在必要时使用主题覆盖覆盖单个节点。 - 连接焦点,使手柄/键盘可以在按钮之间移动;设置默认聚焦控件,并定义邻居或依赖自动邻居。
- 连接信号(
pressed、toggled、text_submitted、value_changed)。
模式
1. 使用锚点进行响应式布局(代码形式)
extends Control
func _ready() -> void:
# Stretch this panel to fill its parent (equivalent to the "Full Rect" preset).
anchors_preset = Control.PRESET_FULL_RECT
# Or set anchors manually: all four edges at the parent's far corners.
# anchor_left = 0; anchor_top = 0; anchor_right = 1; anchor_bottom = 1
2. 由容器 + 按钮信号构建的菜单
extends VBoxContainer # children stack vertically, auto-sized
func _ready() -> void:
for child in get_children():
if child is Button:
child.pressed.connect(_on_button_pressed.bind(child.name))
# Give the first button focus so a gamepad can navigate immediately.
if get_child_count() > 0:
(get_child(0) as Control).grab_focus()
func _on_button_pressed(which: StringName) -> void:
match which:
"PlayButton": get_tree().change_scene_to_file("res://game.tscn")
"QuitButton": get_tree().quit()
3. size_flags:让一个子节点扩展以填充剩余空间
# In a HBoxContainer: a label on the left, a spacer that eats remaining width.
func _ready() -> void:
$Label.size_flags_horizontal = Control.SIZE_SHRINK_BEGIN
$Spacer.size_flags_horizontal = Control.SIZE_EXPAND_FILL # grows to fill
4. 单个节点的 Theme 覆盖(不使用完整 Theme 资源)
func _ready() -> void:
# Per-node overrides: use add_theme_* (type-specific setters).
$Title.add_theme_font_size_override("font_size", 32)
$Title.add_theme_color_override("font_color", Color.GOLD)
$Panel.add_theme_stylebox_override("panel", preload("res://ui/panel.stylebox.tres"))
常见陷阱
- 在 Container 中混用手动位置。
Container的子节点不能设置自己的位置/锚点 — 容器拥有布局。要自由放置,请将节点移出容器,或使用普通Control/PanelContainer包装器。 - 锚点与偏移。 锚点是父节点矩形的比例;偏移是相对于锚定点的像素增量。通过预设设置锚点,然后使用偏移微调。如果锚点保持为 0,只设置位置会导致 UI 不随窗口缩放。
- 使用
Node2D处理 UI。 父节点为Node2D的按钮/标签不会正确应用主题或获取焦点。将 UI 放在CanvasLayer/Control子树下。 - 手柄失去焦点。 如果没有控件获得焦点,方向输入不会起作用。在初始控件上调用
grab_focus(),并确保focus_mode不是FOCUS_NONE。 - Theme 与主题覆盖。
Theme资源为整个子树设置样式;add_theme_*覆盖单个节点。过度使用单节点覆盖会破坏集中式主题管理。 - **
rect_*属性已重命名。** Godot 3 的rect_size/rect_position/rect_min_size在 4.x 中现在是size/position/custom_minimum_size。 mouse_filter在全矩形 Control 上可能会吞掉本应发给其下方节点的点击;在纯装饰性面板上设置MOUSE_FILTER_IGNORE。
参考资料
- 有关锚点/偏移计算、每种 Container 类型、构建/扩展 Theme 和 StyleBox 资源、焦点邻居连接,以及用于 HUD 的
CanvasLayer,请阅读references/layout-and-theming.md。
相关技能
game-ui-ux— 跨引擎 UI/UX:响应式缩放、安全区域、焦点导航、屏幕流程。godot-animation— 基于 Tween 的 UI 过渡与效果增强。godot-signals-groups— 将 UI 事件连接到游戏逻辑。input-systems— 可重绑定输入和多设备焦点。card-game/visual-novel— 以 UI 为主的游戏类型模板。