mcpField
S
scenario-godot-ui

scenario-godot-ui

github.com/scenario-labs设计与 UI1.2k162 次安装1 天前更新
代码仓库

关于 scenario-godot-ui

面向 Godot 4.7.2 的 UI 开发技能,帮助开发者构建适配不同屏幕、语言和输入方式的界面。它结合布局矩阵、图像检查、焦点导航和本地化测试来验证界面。

主要功能

  1. 01设置拉伸与屏幕适配
  2. 02用代码构建统一主题
  3. 03生成场景与 UI 结构
  4. 04运行多尺寸布局矩阵
  5. 05检查焦点与输入导航
  6. 06验证本地化和伪本地化

适用场景

  1. 01检查手机与桌面分辨率下的布局
  2. 02验证安全区域内的控件位置
  3. 03测试键盘与手柄焦点导航
  4. 04查找多语言文本溢出与缺失

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/scenario-labs/skills --skill scenario-godot-ui

安装后在 Claude Code 中输入/scenario-godot-ui确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
critique.md
expert-notes.md
gui-paths.md
procedures.md
sources.md
scripts/
gd_ui.py
scripts/agentkit/ui/
hud_bar.gd
menu_stack.gd
safe_area.gd
ui_audit.gd
ui_capture.gd
ui_focus.gd
ui_layout.gd
ui_rebind.gd
ui_selftest.gd
ui_settings.gd
ui_stretch.gd
ui_theme.gd
scripts/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)。

立场(专家级差异)

  1. 基准尺寸应针对极端情况选择,而不是针对 1080p。 720x720 的正方形基准尺寸搭配 canvas_items + expand 和 Handheld Orientation sensor,可让竖屏和横屏使用同一缩放比例(文档,Multiple resolutions)。实测:1080x2400 的手机上两种方向均为 1.5x,4K 上为 3x。1152x648 的基准尺寸在同一手机上会产生 0.9375x 的画布和三个尺寸不足的按钮 [新增,实测]。Godotneers 的 1920x1080 基准尺寸(1_OFJLyqlXI)只适用于桌面端。
  2. 容器负责布局,锚点负责固定位置。 尺寸调整是一种协商:最小尺寸是底线,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]。
  3. 外观统一由一个用代码构建的 Theme 资源管理, 使用类型变体,而非逐节点覆盖(文档,Theme type variations)。StyleBox 是共享资源:在两个节点上重复使用一个覆盖项,会同时改变两个节点(Karto 00:19:00)。
  4. 焦点必须明确设置。 场景启动时没有任何元素获得焦点,因此在某个元素调用 grab_focus() 之前,ui_down 不会执行任何操作(文档,Controller navigation;实测)。维护菜单堆栈,禁用被遮盖的面板,并在关闭菜单时将焦点还给打开它的元素(Mostly Mad Productions ecJZipjUj6k 00:08:57)。
  5. 当前选中项应是屏幕上对比度最高的元素, 优先保证正文可读,字体最多用两三种,结尾动画应快于开场动画(Rawb Herb,GodotCon 2025, sjmAD1ZLBcE 00:31:42、00:21:34、00:55:38)。
  6. 文本必须使用键,而非字面值。 使用命名占位符和 format(),复数形式使用 tr_n(),相同英文使用上下文区分,动态文本禁用自动翻译(文档,Internationalizing games)。字体应添加回退字体,而非重新映射。
  7. HUD 应保持被动,并由信号驱动。 根节点和包装节点忽略鼠标;值通过信号改变,而不是在 _process 中更新(综合 1_OFJLyqlXI、Yuw7CK5H8eA、f90ieBOoIYQ)。新字符串会触发布局调整(200 个标签:每帧 CPU 耗时从 1.1 增至 1.5 ms);赋入相同字符串会提前退出,因此成本来自文本变化,而不是赋值 [新增,实测]。原地修改数组不会调用 setter(调用 append 后为 0 次,重新赋值后为 1 次),因此状态数组应自行发出信号(NoBSGodot Yuw7CK5H8eA 00:05:06,实测)。
  8. 先在无头模式下按设备尺寸验证,再查看效果。 在无头模式下,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 msCPU 每帧耗时,无头模式下的 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_SIZE512 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_*、stretch 2d、process_custom_fx)均已移除。

参考资料

评论

支持 Markdown