关于 scenario-godot-ui
面向 Godot 4.7.2 的 UI 开发技能,帮助开发者构建适配不同屏幕、语言和输入方式的界面。它结合布局矩阵、图像检查、焦点导航和本地化测试来验证界面。
主要功能
- 01设置拉伸与屏幕适配
- 02用代码构建统一主题
- 03生成场景与 UI 结构
- 04运行多尺寸布局矩阵
- 05检查焦点与输入导航
- 06验证本地化和伪本地化
适用场景
- 01检查手机与桌面分辨率下的布局
- 02验证安全区域内的控件位置
- 03测试键盘与手柄焦点导航
- 04查找多语言文本溢出与缺失
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ scenario-labs/ skills --skill scenario-godot-ui安装后在 Claude Code 中输入/scenario-godot-ui确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/critique.mdexpert-notes.mdgui-paths.mdprocedures.mdsources.mdscripts/gd_ui.pyscripts/agentkit/ui/hud_bar.gdmenu_stack.gdsafe_area.gdui_audit.gdui_capture.gdui_focus.gdui_layout.gdui_rebind.gdui_selftest.gdui_settings.gdui_stretch.gdui_theme.gdscripts/agentkit/ui/examples/build_g7.gd详细介绍
Godot UI(UI 开发者)
目标:Godot 4.7.2.stable,macOS Apple Silicon。
这里的专家级意味着:用数据和图像验证一种布局,从 1080x2400 的竖屏手机到 3840x2160 的显示器,在所有语言中均适用,并支持鼠标、手柄和屏幕阅读器。拉伸变换负责缩放,容器负责布局,一个用代码构建的 Theme 负责样式;只有布局矩阵和联系表确认无误后,内容才可发布。如果此处提到的某项同级技能不在你可用的技能中,请用户安装(npx skills add scenario-labs/skills --skill <name>);若无法等待,请根据工具架构继续操作,并标记这一缺口。
必备背景: scenario-godot-expert(channels、review loop、6.3 traps)。
立场(专家级差异)
- 基准尺寸应针对极端情况选择,而不是针对 1080p。 720x720 的正方形基准尺寸搭配
canvas_items+expand和 Handheld Orientationsensor,可让竖屏和横屏使用同一缩放比例(文档,Multiple resolutions)。实测:1080x2400 的手机上两种方向均为 1.5x,4K 上为 3x。1152x648 的基准尺寸在同一手机上会产生 0.9375x 的画布和三个尺寸不足的按钮 [新增,实测]。Godotneers 的 1920x1080 基准尺寸(1_OFJLyqlXI)只适用于桌面端。 - 容器负责布局,锚点负责固定位置。 尺寸调整是一种协商:最小尺寸是底线,Expand 用于占据剩余空间,Fill 用于填满所占空间(Godotneers 1_OFJLyqlXI 00:35:00,Karto 5Hog6a0EYa0
00:14:39)。在 400 px 的 HBox 中实测:启用 Expand 而不启用 Fill,会留下已占据的空间并将同级元素推到 x 380;启用 Fill 或拉伸比例但不启用 Expand 则不会改变任何内容;比例会累加,1:3 会分得 386 px 中的 96 和 290 px(Karto 00:15:45)。锚点预设相对于父级;单独调用
set_anchors_preset()会保留旧偏移量(一个 50x50 的子节点在 FULL_RECT 上仍保持 50x50),因此应使用set_anchors_and_offsets_preset()(Karto 00:05:24,实测)。角落元素还需要设置其增长方向,否则较长文本会延伸到屏幕外 [新增,在 1152 px 画布上实测宽达 1462 px]。 - 外观统一由一个用代码构建的 Theme 资源管理, 使用类型变体,而非逐节点覆盖(文档,Theme type variations)。StyleBox 是共享资源:在两个节点上重复使用一个覆盖项,会同时改变两个节点(Karto 00:19:00)。
- 焦点必须明确设置。 场景启动时没有任何元素获得焦点,因此在某个元素调用
grab_focus()之前,ui_down不会执行任何操作(文档,Controller navigation;实测)。维护菜单堆栈,禁用被遮盖的面板,并在关闭菜单时将焦点还给打开它的元素(Mostly Mad Productions ecJZipjUj6k 00:08:57)。 - 当前选中项应是屏幕上对比度最高的元素, 优先保证正文可读,字体最多用两三种,结尾动画应快于开场动画(Rawb Herb,GodotCon 2025, sjmAD1ZLBcE 00:31:42、00:21:34、00:55:38)。
- 文本必须使用键,而非字面值。 使用命名占位符和
format(),复数形式使用tr_n(),相同英文使用上下文区分,动态文本禁用自动翻译(文档,Internationalizing games)。字体应添加回退字体,而非重新映射。 - HUD 应保持被动,并由信号驱动。 根节点和包装节点忽略鼠标;值通过信号改变,而不是在
_process中更新(综合 1_OFJLyqlXI、Yuw7CK5H8eA、f90ieBOoIYQ)。新字符串会触发布局调整(200 个标签:每帧 CPU 耗时从 1.1 增至 1.5 ms);赋入相同字符串会提前退出,因此成本来自文本变化,而不是赋值 [新增,实测]。原地修改数组不会调用 setter(调用append后为 0 次,重新赋值后为 1 次),因此状态数组应自行发出信号(NoBSGodot Yuw7CK5H8eA 00:05:06,实测)。 - 先在无头模式下按设备尺寸验证,再查看效果。 在无头模式下,
root.size可设置任意尺寸并应用项目拉伸,因此布局矩阵几秒内即可跑完;随后用窗口截图渲染每种设备,并绘制刘海 [新增,实测]。
先确定基础项
| 输入项 | 影响 | 未指定时的默认值 |
|---|---|---|
| 平台和屏幕方向 | 基础尺寸、屏幕方向、触控目标尺寸 | 手机竖屏 + 横屏,桌面端最高支持 4K:基础尺寸 720x720,canvas_items、expand,屏幕方向 6(传感器) |
| 美术风格 | 拉伸模式和缩放模式 | 矢量或高分辨率:canvas_items + 分数缩放;像素美术:viewport,基础尺寸 640x360,整数缩放,独占全屏(文档) |
| 输入设备 | 焦点处理、按键重绑定界面、触控尺寸 | 鼠标、键盘、手柄、触控 |
| 语言 | 字体、RTL、导出时的 Text Server Data | 英语,再加一种长文本语言(德语)、一种 CJK 语言(日语)、一种 RTL 语言(阿拉伯语)用于测试 |
| 无障碍基线 | 屏幕阅读器、UI 缩放滑块、对比度 | 正文文本符合 WCAG 4.5:1;通过 content_scale_factor 将 UI 缩放至 0.75 到 2.0 |
| 渲染器 | 设置中的升频器选择 | Forward+(保留 Jolt);Compatibility 会强制使用双线性 3D 缩放 |
工作流
1. 项目设置。 明确写出拉伸相关键值:手写的 project.godot 使用
disabled 和 keep(差值)。使用
gd_env.set_project_setting 设置
display/window/size/viewport_width/height、stretch/mode、stretch/aspect、
handheld/orientation、gui/theme/custom。检查 3d/physics_engine="Jolt Physics" 和
渲染器设置是否保留。门槛:对每个目标运行 gd_ui.stretch_math(window, base, ...),确保得到预期的
逻辑尺寸和缩放比例(224 个案例中,端口与引擎一致,包括原点和缩放比例)。
2. 用代码创建主题。 ui_theme.gd 中的 build(overrides) 返回一个
Theme:Button 各状态带有粗边强调色焦点框,以及 Label、面板、滑块、标签页、ProgressBar、
variations TitleLabel、HudLabel、HudValue、PrimaryButton、HudPanel、HealthBar、TrailBar。将其保存为
.tres,把默认字体设为带有 CJK 和阿拉伯语回退字体的 SystemFont,字体最多使用两到三种。以多种比例绘制的文本(如 3 倍大小的 HUD 数字)应使用 MSDF:
gui/theme/default_font_multichannel_signed_distance_field 或字体的
multichannel_signed_distance_field;这两项默认均为 false(Karto 5Hog6a0EYa0 00:20:50,实测)。
默认 Theme Scale 只读取一次:实测发现,运行时设置没有任何效果。在编辑器中,修改 Theme 后需要重新加载场景才能重绘(Godotneers 00:22:10),而覆盖项在勾选复选框前不会生效(Karto 00:17:25);在代码中,只有 add_theme_*_override 有效,运行时修改 Theme 会立即生效(实测)。门槛:contrast_report() 中正文文本配对的对比度均 >= 4.5:1(实测最低值 4.37,出现在禁用状态,允许);check_variations() 不得发现拼写错误的 variation。
3. 代码中的场景。 根节点使用 Control 并设为全矩形,接着是 safe_area.gd
MarginContainer,然后是各容器。在基准分辨率 720 下,按钮的逻辑高度为 88(手机上 1.5x 时为 132 px)。
设置行放在 TabContainer 内的 ScrollContainer 中。HUD 放在 CanvasLayer 上,根节点
MOUSE_FILTER_IGNORE,小地图使用 AspectRatioContainer;圆形小地图或人像框使用
clip_children 遮罩(在圆角 Panel 上选择 Clip Only),但具有不同 z_index 的子节点会逃出遮罩
(GDQuest W4j4tnQLcTA 00:03:47,实测),因此需将被遮罩的内容保持在 z 0,或使用 SubViewport。
切换项以文本显示“开启”/“关闭”(CoffeeCrow 9H_fN4OxyIE 00:08:11)。safe_area.gd 会在
size_changed 时重新计算(1.5x 时顶部边距为 104,2x 时为 82,实测)。examples/build_g7.gd 会构建整个
G7 集。GATE:ui_audit.gd 的 audit_tree() 不返回任何
hud_blocks_input、icon_keep_size、grows_offscreen_*、no_accessible_name、
shared_stylebox_override、unknown_variation。
4. 无头布局矩阵。
gd_ui.layout_matrix(P, scene, targets, min_touch_px=..., safe_insets=..., locale=..., pseudo=True)
针对 8 种目标进行检查(手机竖屏和横屏、4:3 平板、1366x768、1080p、21:9、4K、800x600)。GATE:
每个场景在 en、de 和扩展 0.4 倍的伪本地化下,均无画面外、超出安全区、触控目标过小、文本(裁切或溢出)、
重叠和折叠问题。
5. 窗口模式下的截图矩阵,然后检查。
gd_ui.capture_matrix(P, scene, targets, safe_insets=...) 会以每种目标的物理尺寸渲染场景,
添加黑边和红色刘海区域,并生成联系表。打开联系表。GATE:
image_checks 无任何标记;目视检查:选中状态清晰可见,无字形裁切(CJK、阿拉伯文),刘海区域只覆盖背景,
黑边和边框完好。切勿通过带有 content_scale_* 的嵌入式 Window 截图:它会按未缩放状态绘制(P13,实测)。
6. 焦点和输入。 gd_ui.focus_walk(P, scene, steps) 通过
push_input 推送 ui_* 操作并记录焦点所有者;ui_focus.graph() 会列出无法到达的可聚焦控件。菜单
堆栈:打开、取消,将焦点返回打开菜单的控件。GATE:从默认焦点可到达所有可聚焦控件;
没有焦点时的第一次按键会将焦点设为默认项;被遮挡的面板不可到达。
7. 重新绑定。 ui_rebind.gd:接受输入(无回显、非 Escape、
摇杆保持超过 0.5),规范化(物理键码、设备 -1、轴符号),报告冲突,交换或拒绝,保存为 ConfigFile,
从项目设置重置。使用 DisplayServer.keyboard_get_label_from_physical() 显示按键(仅窗口模式):
法语键盘布局下,物理按键 Q 显示为“A”(实测)。手动添加手柄按钮:在 4.7.2 中,ui_accept 和
ui_cancel 仅包含键盘按键(Enter、Kp Enter、Space;Escape),因此需添加 Joypad Button 0 和 1
(Mostly Mad ecJZipjUj6k 00:12:00,实测)。GATE:保存并加载一轮后,键盘和任意手柄上的绑定均正常。
8. 本地化。 使用带有 ?plural 列的 CSV,通过离线 gd_ui.check_csv 检查,再使用 --import,
然后调用 gd_ui.register_translations。运行 en、fr、de、ja、ar 和伪本地化;expansion_ratio
默认值为 0.0,因此将其设为 0.3 至 0.4,并调用 reload_pseudolocalization()(实测)。
--language fr 是非持久化测试。动画文本使用 RichTextEffect:包含 bbcode 变量和
_process_custom_fx(char_fx),选项来自 char_fx.env(Cashew OldDew KMqYeRae6rM 00:14:01;
实测 [lift px=6] 读取到 6.0),通过 install_effect() 安装。GATE:每种语言均无缺失键;阿拉伯文镜像正确(锚点和 HBox 顺序);
en 和 fr 的复数形式正确;布局矩阵无问题。
9. 设置和开销。 ui_settings.gd 自动加载并应用
窗口模式、vsync、渲染比例和升频器、画质、UI 比例、总线音量及语言区域;并负责保存和重新加载。GATE:
保存并加载一轮正常;ui_scale 为 1.5 时,1280x720 画布会变为 853x480。
数值
| 数值 | 相对于 | 来源 |
|---|---|---|
基础尺寸 720x720、canvas_items、expand、方向传感器 | 手机竖屏和横屏,以及桌面端 | 文档:多种分辨率 |
| 1080x2400 和 2400x1080 时缩放 1.5,3840x2160 时缩放 3.0,1366x768 时缩放 1.0672 | 基础尺寸 720x720 | 实测 [新增] |
2400x1080 手机上基础尺寸 720x1280:expand 为 2844x1280,缩放 0.844x(UI 缩小);keep_width 留出 897 px 侧边栏;1080x2400 上的 keep_height 留出 240 px 边栏 | 方形基础尺寸为何优于选择纵横比 | 实测 [新增] |
像素艺术 640x360 使用 viewport 整数缩放;viewport 使用小数缩放 1.0672(1366x768)时会重新采样并模糊文字 | 720p 到 4K | 文档、实测 |
| 4K 基础尺寸的默认主题缩放为 2.0 到 3.0;移动端 1080p 基础尺寸为 1.5 到 2.0;只读取一次(运行时设置:不变) | 基础尺寸 | 文档、实测 |
| 触控目标:手机 126 px,平板 96 px(48 dp,约 420 和 320 dpi) | 物理像素 | [新增] |
| 720 基础尺寸下,按钮为 88 个逻辑像素 | 手机上为 132 px | [新增,实测] |
| WCAG:正文 4.5:1,大号文字 3:1 | 文字与其背景的对比度 | WCAG 2 [新增] |
| 伤害轨迹:单次计时器 0.4 s,每次受击时重新启动;治疗即时生效 | 生命值变化 | DashNothing f90ieBOoIYQ 00:01:26 |
| 文本服务器数据约 4 MB | 导出大小,适用于无空格的脚本 | 文档 |
| 200 个标签:每帧生成新文本耗时 1.1 到 1.5 ms,每帧处理 10 个耗时 0.17 到 0.23 ms,相同文本(空闲状态)耗时低于 0.1 ms | CPU 每帧耗时,无头模式下的 M5 Max | 实测 [新增] |
质量门槛
可衡量项:test_ui_live.py 的 U1 到 U15 均通过(编译、拉伸一致性、CSV、布局矩阵、捕获、焦点、重新绑定、HUD、本地化、引擎信息、主题和设置、开销、嵌入式 Window、第 2 轮布局和主题信息、剪裁蒙版和文字效果);每个场景和区域设置的布局矩阵均无问题;审计通过;正文文本对比度 >= 4.5:1;保存和加载往返测试通过。视觉检查:每个场景和区域设置各有一张联系表(菜单、HUD、设置 ja、菜单 ar、设置伪本地化),并已打开检查:焦点清晰可见、字形完整、凹口下方无内容、按预期显示黑边、灰度下仍能看见选中项(Rawb Herb)。
常见错误
| 错误 | 表现 | 修复 |
|---|---|---|
| 手机游戏使用 1920x1080 或 1152x648 作为基础分辨率 | 竖屏下按钮很小(1080x2400 时缩放比例为 0.9375) | 使用 720x720 的正方形基础尺寸 + 扩展 |
| Agent 编写的 project.godot 遗漏拉伸键 | UI 固定大小,在 4K 屏幕上出现黑边 | 明确设置模式和宽高比 |
| 覆盖游戏的全矩形 Control 使用默认 STOP 过滤器 | 点击无法传递到 _unhandled_input(0 次,共 1 次) | 在 HUD 根节点和包装节点上设置 MOUSE_FILTER_IGNORE |
| 使用角落预设但未设置扩展方向 | 分数文本超出右侧边缘 | grow_horizontal = GROW_DIRECTION_BEGIN |
打开时未调用 grab_focus() | 手柄无法操作 | 菜单栈在首次导航事件时聚焦默认项 |
容器中的 TextureRect 保持 KEEP_SIZE | 512 px 图标使 64 px 高的行变为 614x512;IGNORE_SIZE 未设置最小尺寸会导致宽度缩为 0 | 使用 EXPAND_FIT_WIDTH_PROPORTIONAL(测量值为 64x64),或忽略尺寸并设置最小尺寸,Stretch Keep Aspect Centered(Godotneers 1_OFJLyqlXI 00:10:28) |
| OptionButton 项目使用英文直写 | 日语界面显示“Windowed” | 使用键作为项目(OPT_WINDOWED) |
| 标签页保留主题默认设置 | 标签页太小,难以触控 | 为标签页设置带内容边距的样式盒;矩阵会检查 TabBar |
| 从合成事件保存的按键绑定使用设备 0 | 手柄 2 或真实键盘(设备 16)无法触发 | 将设备规范化为 -1 |
| 开启伪本地化,但未设置扩展或重新加载 | 没有填充(默认比例为 0.0) | 设置 expansion_ratio,并调用 TranslationServer.reload_pseudolocalization() |
| 旧教程中认为 POT 生成可处理自定义节点 | 字符串缺失(4.2 的问题) | 已在 4.3 中修复(Cashew OldDew v0tJPsNNOM8 00:08:00,未重新运行);使用 CSV 键可避免 POT 问题 |
| 在项目设置中设置 Locale Test | 发布时使用法语 | 清除该设置;使用 --language fr |
为实现效果而设置 visible = false 隐藏容器子项 | 同级项会跳动(重新布局) | 使用 modulate.a = 0 或 offset_transform_scale(MrElipteach pK2vI2-jCH4 00:02:54) |
| 期望鼠标点击后出现焦点环 | 只有下次按键或按下手柄时才出现焦点环 | 这是设计如此:gui/common/show_focus_state_on_pointer_event 为 1(仅文本输入) |
交接
- 输入:状态自动加载和信号(scenario-godot-architecture)、输入操作和数值 (scenario-godot-gameplay)、总线名称 Master、Music、SFX(scenario-godot-audio)、图标、面板、 字体(scenario-* skills;九宫格边距在代码中设置)。
- 输出:渲染缩放和升频器约定(scenario-godot-rendering-lighting);Text Server Data、
真实设备安全区域和触控(scenario-godot-performance-export);片头和片尾曲目、
offset_transform动画(scenario-godot-animation);用于 CI 的test_ui_live.py(scenario-godot-pipeline-automation)。
Godot 4.7 说明
offset_transform_*(4.7)可在不重新布局的情况下移动容器子项;offset_transform_visual_only默认为 true,因此点击命中布局矩形(实测)。pivot_offset_ratio(4.7)用于中心轴心;grab_focus(hide_focus)(4.6)。AccessibilityServer(4.7)、accessibility_name、FOCUS_ACCESSIBILITY(RichTextLabel 默认值);accessibility_support设为 0 Auto 时,仅在辅助应用处于活动状态时运行。auto_translate_mode取代了auto_translate;FoldableContainer(4.5)、VirtualJoystick、PopupMenu.allow_search(4.7);[img]接受width_unit/height_unit。升频器:FSR2=2、 MetalFX 空间升频=3,时间升频=4。push_input(event, true)接受逻辑坐标。Godot 3 中的名称(rect_size、add_color_override、margin_*、stretch2d、process_custom_fx)均已移除。
参考资料
references/procedures.md:P1 至 P15,包含完整代码路径、实时测试 ID 和结果。references/expert-notes.md:每个来源的内容说明及 时间戳。references/critique.md:用于评估 UI 构建及其 截图的评分标准。references/gui-paths.md:供计算机操作 Agent 使用的编辑器内 相同步骤。references/sources.md:所有来源、凭据、URL 和最佳 时间戳。scripts/gd_ui.py、scripts/agentkit/ui/*.gd、scripts/agentkit/ui/examples/build_g7.gd。