From d95ed67e6330b4e11779867181454a6947e08941 Mon Sep 17 00:00:00 2001 From: Joywayer Date: Wed, 22 Jul 2026 10:39:52 +0800 Subject: [PATCH] =?UTF-8?q?docs(designer):=20UI=20=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E8=AE=BE=E8=AE=A1=EF=BC=88=E5=B8=83=E5=B1=80=E6=92=91=E6=BB=A1?= =?UTF-8?q?=20+=20=E5=85=83=E7=B4=A0=E5=A4=8D=E9=80=89=E6=A1=86=20+=20?= =?UTF-8?q?=E5=8F=8C=E8=AF=AD=E6=A0=87=E7=AD=BE=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../2026-07-22-designer-ui-optimize-design.md | 147 ++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 docs_dev/specs/2026-07-22-designer-ui-optimize-design.md diff --git a/docs_dev/specs/2026-07-22-designer-ui-optimize-design.md b/docs_dev/specs/2026-07-22-designer-ui-optimize-design.md new file mode 100644 index 0000000..bcb9581 --- /dev/null +++ b/docs_dev/specs/2026-07-22-designer-ui-optimize-design.md @@ -0,0 +1,147 @@ +# 游戏设计器 UI 优化(布局撑满 + 元素复选框 + 双语标签)— 设计 + +- 日期:2026-07-22 +- 状态:设计已确认,待实现 +- 范围:编辑器工具层 `addons/game_designer/`,**游戏运行时代码与数据文件格式零改动** + +--- + +## 1. 背景与问题 + +用户反馈游戏设计器三点待优化: + +1. **输入框无法完整显示内容** —— `designer_ui.gd` 的 `line()`/`opt()`/`spin()` 只设固定最小宽度、无 `SIZE_EXPAND_FILL`,控件不随面板拉伸,长文本(显示名/描述/VFX/JSON/长中文选项)被截断。 +2. **法术元素标签用逗号文本易错** —— 应改可视化控件。元素标签是**多值**(如 `plasma_storm` = `["tag:water","tag:lightning"]`)。 +3. **部分显示仍为纯英文** —— `spell_tab.TYPE_NAMES`/`LOGIC_OPS`、`wave_tab.TYPE_NAMES`、`resonance_tab.MATCH` 等为纯英文。要求统一**双语(中文 English)**显示,含 spell_tab(其 `DMG_LABELS`/`ST_LABELS` 现为纯中文,也改双语)。 + +### 词表事实 + +- 元素标签词表(全数据仅这 5 个):`tag:fire 火` / `tag:ice 冰` / `tag:lightning 雷` / `tag:water 水` / `tag:poison 毒`。 +- 枚举整数来源:`DamageType`(0物理/1火/2冰/3雷/4毒/5奥术)、`StatusID`(0无/1燃烧/2冻结/3中毒/4潮湿/5沾油/6眩晕/7连击/8易伤)。 + +--- + +## 2. 布局修复(全 7 页,中央改动) + +`addons/game_designer/designer_ui.gd`:`line()` / `opt()` / `spin()` 三个工厂各追加: +```gdscript +ctrl.size_flags_horizontal = Control.SIZE_EXPAND_FILL +``` +效果:行内 `cell_label`(70px,autosize,不变)之后,输入控件吃掉剩余宽度;表格页(敌人/波次)各列随之填满面板宽度。零数据改动,全 7 页受益。 + +--- + +## 3. 共享元素词表(`designer_ui.gd` 新增常量) + +```gdscript +const ELEM_LABELS := ["火 Fire", "冰 Ice", "雷 Lightning", "水 Water", "毒 Poison"] # 显示(双语) +const ELEM_TAGS := ["tag:fire", "tag:ice", "tag:lightning", "tag:water", "tag:poison"] # 存储,index 对齐 +``` +spell_tab(复选框)与 resonance_tab(元素下拉)共用,单一事实源。通过 `UI.ELEM_LABELS` / `UI.ELEM_TAGS` 访问(`const UI = preload(designer_ui.gd)`,常量可跨脚本访问)。 + +--- + +## 4. spell_tab —— 元素复选框 + 双语标签 + +### 4.1 元素标签复选框(替代 `_tags` 单行文本) +- UI:一行「元素标签」标签 + 5 个 CheckBox(文本取 `UI.ELEM_LABELS`);下方一行「自定义标签」+ 小 LineEdit(收纳非元素 tag,防丢)。 +- 新增成员:`var _elem_checks: Array = []`(5 个 CheckBox)、`var _custom_tags: LineEdit`。 +- 加载(`_on_select`): + ```gdscript + var etags: Array = d.get("element_tags", []) + for i in _elem_checks.size(): + _elem_checks[i].button_pressed = UI.ELEM_TAGS[i] in etags + var custom := [] + for t in etags: + if not (t in UI.ELEM_TAGS): custom.append(String(t)) + _custom_tags.text = ",".join(custom) + ``` +- 应用(`_on_apply`,替换原 `_tags` 解析块): + ```gdscript + var tags: Array = [] + for i in _elem_checks.size(): + if _elem_checks[i].button_pressed: tags.append(UI.ELEM_TAGS[i]) + for t in _custom_tags.text.split(",", false): + var s := t.strip_edges() + if s != "" and not (s in tags): tags.append(s) + ``` +- ⚠️ 多元素法术会被规整为**固定元素顺序**(火冰雷水毒),`element_tags` 语义为集合、顺序无意义——属预期简化(回读比较按集合)。 + +### 4.2 双语标签(仅显示;存储 index/key 不变) +```gdscript +const TYPE_NAMES := ["动作 ACTION", "修饰 MODIFIER", "触发 TRIGGER", "逻辑 LOGIC"] +const ACTION_KINDS := ["弹道 Projectile", "毒池 Zone", "召唤 Summon"] +const LOGIC_OPS := ["every_n_shots", "if_hp_below", "if_enemy_nearby", "loop"] # 存储 key,不变 +const LOGIC_OP_LABELS := ["每 N 次 every_n_shots", "生命低于 if_hp_below", "附近有敌 if_enemy_nearby", "循环 loop"] # 新增,供下拉显示 +const DMG_LABELS := ["物理 Physical", "火 Fire", "冰 Ice", "雷 Lightning", "毒 Poison", "奥术 Arcane"] +const ST_LABELS := ["无 None", "燃烧 Burn", "冻结 Freeze", "中毒 Poison", "潮湿 Wet", "沾油 Oily", "眩晕 Stun", "连击 Combo", "易伤 Vuln"] +``` +- `_lop` 下拉改用 `UI.opt(LOGIC_OP_LABELS, 0)`;`_read_meta` 仍 `meta["logic_op"] = LOGIC_OPS[_lop.selected]`,`_on_select` 仍 `_lop.selected = LOGIC_OPS.find(...)`(index↔key 逻辑不变,只换显示数组)。 +- 列表前缀 `"[%s] %s" % [TYPE_NAMES[...], sid]` 变为 `"[动作 ACTION] action_spark_bolt"`(可接受)。 + +--- + +## 5. wave_tab —— 双语标签 + +```gdscript +const TYPE_NAMES = ["杂兵 Basic", "快速 Fast", "护甲 Armored", "精英 Elite", "首领 MiniBoss", "终焉 Boss"] +const BOSS_NAMES = ["无 None", "首领 MiniBoss", "终焉 Boss"] # 存储走 BOSS_VALS,不变 +``` +(存储均为 index / BOSS_VALS,改标签零数据影响。) + +--- + +## 6. resonance_tab —— 双语标签 + 元素下拉 + +- 匹配方式:`MATCH`(存储 key `adjacent`/`anywhere_in_deck`)不变;新增 `const MATCH_LABELS = ["相邻 adjacent", "卡组内任意 anywhere_in_deck"]` 供下拉显示。`_match = _row("匹配方式", UI.opt(MATCH_LABELS, 0))`;`_on_apply` 仍 `"match": MATCH[_match.selected]`;`_on_select` 仍 `_match.selected = max(0, MATCH.find(...))`。 +- 元素 A / B:`_p0`/`_p1` 由 LineEdit → `UI.opt(UI.ELEM_LABELS, 0)`。 + - 加载:`_p0.selected = max(0, UI.ELEM_TAGS.find(String(p0)))`(非元素值回退第 0 项)。 + - 应用:`"pattern": [UI.ELEM_TAGS[_p0.selected], UI.ELEM_TAGS[_p1.selected]]`。 + - 列表显示 `_refresh` 用 pattern 原值(tag 串),不变。 + - ⚠️ 若某配方 pattern 含非元素值(现数据无),会被下拉回退丢失——现 `resonance.json` 全为元素,风险为零;如未来需要非元素 pattern 再扩展。 + +--- + +## 7. 已双语的页(enemy / core / status) + +`enemy_tab.NAMES`("杂兵 Basic")、`core_tab.TOPO/FEAT`("MATRIX 矩阵")、`status_tab.STACK`("REFRESH 刷新")已是双语,**本次不改文案**(其中 enemy `name` 是持久化字段,改动会写入 enemies.json),仅受益于第 2 点布局撑满。 + +> 注:core/status 现为「英文 中文」序,新加的为「中文 英文」序,序不统一但均双语、均含中文,本次不做归一化以免无谓改动持久化/工作正常的部分。 + +--- + +## 8. 组件边界与改动清单 + +| 文件 | 改动 | +|---|---| +| `designer_ui.gd` | line/opt/spin 加 `SIZE_EXPAND_FILL`;新增 `ELEM_LABELS`/`ELEM_TAGS` 常量 | +| `spell_tab.gd` | 元素复选框 + 自定义框替换 `_tags`;`TYPE_NAMES`/`ACTION_KINDS`/`DMG_LABELS`/`ST_LABELS` 改双语;新增 `LOGIC_OP_LABELS` 并用于 `_lop` 下拉 | +| `wave_tab.gd` | `TYPE_NAMES`/`BOSS_NAMES` 改双语 | +| `resonance_tab.gd` | `MATCH_LABELS` 新增用于下拉;元素 A/B 改元素下拉 | + +其它运行时脚本、数据文件、其它 tab 逻辑不动。 + +--- + +## 9. 验证 + +1. `validate_script` 四个改动文件全绿;`reload_project` + `get_editor_errors` 无报错。 +2. 回读往返测试(`execute_editor_script`): + - **spell**:逐条 `_on_select`→`_read_meta` meta 一致(同上一特性);`element_tags` 作为**集合**与原一致;含非元素自定义 tag 的情形自定义框保留。 + - **resonance**:逐条 `_on_select`→ 重建 record,`pattern`(两元素)与 `match` 与原一致。 +3. `get_editor_screenshot` 目测:各页输入框撑满面板宽、下拉显示双语、法术页元素为复选框。 + +## 10. 范围外(YAGNI) + +- 不改游戏运行时代码 / 数据文件格式 / 数据内容。 +- 不归一化 enemy/core/status 既有双语文案。 +- 不做元素标签之外的 tag 下拉词表(自定义框已覆盖)。 +- resonance pattern 仍限两元素(现结构),不扩展多元素配方。 + +## 11. 验收标准 + +1. 打开游戏设计器,各页输入框/下拉框随面板宽度撑满,长文本不再截断。 +2. 法术页「元素标签」为 5 个元素复选框 + 自定义框;`plasma_storm` 正确勾选 水+雷;保存后 `element_tags` 集合不变。 +3. 法术页 类型/动作种类/logic_op/伤害类型/施加状态 均双语显示,保存的 `type`/`logic_op`/`damage_type` 等值不变。 +4. 波次页 类型/Boss、共鸣页 匹配方式 均双语;共鸣页 元素 A/B 为元素下拉,`resonance.json` 回读往返一致。 +5. `validate_script`/`reload_project` 无报错;spell 与 resonance 回读往返测试 FAILS=0。