Files
pixelheros/assets/script/game/common/config/英雄配置UI设计方案.md
panFD ca7642b36e docs(hero-config): add hero configuration UI design documentation
新增英雄配置UI的完整设计方案文档,包含架构、数据流、JSON存储规范、生成器逻辑、UI布局与交互细节,以及实施步骤和校验规则。
2026-08-18 22:45:20 +08:00

16 KiB
Raw Blame History

英雄配置 UI 设计方案

为编辑器扩展 extensions/hero_setup 新增「英雄配置」功能的设计文档。 目标:以 SkillSet.ts / BuffSet.ts / FieldSkillSet 为只读底座,通过 UI 配置英雄(新增 + 编辑现有),落地 英雄设计方案.md英雄设计指引.md 的能力池范式。

已确认决策

  • lv 档位按文档完整支持 lv2/3/5/7/9(数据先行),超过运行时 HERO_MAX_LV=6 的档给黄色警告不阻止
  • 落地方式 JSON 外部化JSON 为 source of truth单向生成 heroSet.ts 数据段
  • 功能范围:新增英雄 + 编辑现有英雄(不做删除)
  • 校验uuid 存在性 + 段位规则 + lv 升序 + t_num≥1 + 形态硬约束
  • 生成器边界:标记注释定界(分歧裁定 1
  • 怪物段:全量迁移进 JSON、UI 只读(分歧裁定 2round-trip 门保真)

一、总体架构与数据流

heroSet.data.jsonsource of truthgit 跟踪)
        │ ① 扩展保存时生成(单向 JSON→TS
        ▼
heroSet.ts 数据段HeroInfo 表 + HeroList = 生成产物,其余 ~500 行类型/函数原样保留)
        │ ② 下游零改动
        ▼
CardPoolList 自动派生  eval-heroes 强度评估  游戏运行时
面板Vue3同面板双 tab强度评估英雄配置
   │ Editor.Message.request('hero_setup', ...)
   ▼
主进程 methods ──spawn──► scripts/heroes-cli.ts复用 tsx + tsconfig.eval.json + mock-cc 链路)
   │                        --cmd=query-base | export | validate
   ├─ 读 JSON / 校验
   └─ save备份 → 写 TS → 语法自检 → round-trip 比对 → 写 JSON → refresh-asset

关键原则:

  • 运行时零改动游戏代码、CardSet 派生链、eval-heroes、下游 49 个 import 方均不感知本功能存在
  • 同步方向单向JSON → heroSet.tsTS 数据段永远为生成产物;不一致时弹冲突对话框(含 diff提供一次性「以 TS 反向导入」通道,禁止静默覆盖
  • CardPoolList 无需手动同步:新英雄写入 HeroInfo + HeroList 后CardSet 模块加载期自动生成卡池条目

二、JSON 存储

2.1 位置

assets/script/game/common/config/heroSet.data.json

候选 结论 理由
assets/script/.../heroSet.data.json 采用 与 heroSet.ts 同目录、随 git 入库
assets/resources/ 下 否决 resources 目录全量打包进游戏
extensions/hero_setup/ 内 否决 .gitignore 整体忽略 extensions/*source of truth 会丢版本历史
项目根 config/ 备选 零 asset-db 干扰,但离代码远、易被误删

JSON 不被任何运行时代码 importCocos 构建不会打包它asset-db 会为其生成 .meta代价可接受。

2.2 Schema 要点

interface HeroConfigFile {
    schema_version: 1;                  // 结构性变更时递增,读取端按版本迁移
    generated_at: string;               // ISO 时间(人读)
    gen_hash: string;                   // 上次生成 TS 数据段指纹,用于漂移检测
    heroes: Record<number, HeroJson>;   // 英雄5001~5499 段)
    monsters: Record<number, HeroJson>; // 怪物6001~6199 段UI 只读)
}

heroInfo 接口逐字段对齐,仅三处转换:

转换 JSON 存储 生成还原
枚举 语义字符串 "type": "Melee" HType.Melee(生成端持名称→成员映射表)
基准属性(英雄) { ref: "HERO_ROLE_BASE", role: "Tank", delta: 1200 } HERO_ROLE_BASE[HRole.Tank].hp + 1200delta 0 省略 + 0
基准属性(怪物) 绝对值 hp: 3000 直接数值
攻速 cd atk_speed: "Slow" AtkSpeedSet[AtkSpeedLv.Slow].cd

设计理由:

  • 枚举存字符串diff 友好、手改安全、枚举成员重排不破坏数据
  • 属性存「基准引用+增量」:保住 HERO_ROLE_BASE 模板调参全局传播语义heroSet.ts L145 注释意图);禁止 JSON 出现已求值裸数值,杜绝基准值改动后历史英雄静默漂移
  • UI 端用底座数据实时计算绝对值预览(基准+增量双输入)

三、heroSet.ts 生成器(核心)

3.1 边界定位:标记注释定界

  • 首次迁移(--cmd=export)时在 export const HeroInfo 前插入 // @hero-setup:region-begin,在 HeroList 数组 ]; 后插入 // @hero-setup:region-end
  • 此后每次生成:读全文 → 定位两标记 → 前缀 + 生成段 + 后缀 拼接
  • 双保险
    • 标记被手删 → 拒绝生成并提示走「重新导入」流程,绝不退化为全文件重写
    • 保存前重算当前 TS 数据段指纹与 JSON 的 gen_hash 比对,不一致 → 弹冲突对话框(展示 diff二选一以 TS 反向导入一次 / 以 JSON 覆盖)

3.2 自研序列化器(非 JSON.stringify

格式保真清单与现文件逐项对齐round-trip 门验证):

不变量 依赖方
4 空格缩进、双引号、行尾无分号风格跟随原文件 全部 diff 工具
条目头字段单行紧凑(uuid, name, path, fac, card_lv, lv, type, grow_type, role, hp, ap, def 一行),触发块换行展开 现有阅读习惯
按 uuid 段位插入注释块(// ===== card_lv=55401-5499===== 段位规则
档位数组 lv 严格升序lv_entries / LvTriggerEntry[] / field / revive / ap_bonus / hp_bonus HeroSkillDesc.ts:384filter(e=>e.lv<=lv).pop()
数字键无引号、保持插入序 Record 索引
ccd: 0 占位字段不丢HSkillInfo 必填) Hero.ts 加载
字段顺序稳定skills → atked/atking → dead → fstart → field → revive → info 减少 diff 噪音
HeroList 按 card_lv 分组升序 CardSet 卡池派生顺序
info: "" 收尾、path/icon/info 字符串原样不转义变换 文本保真
文件头 BOM 原样保留(读 utf-8 后首字符检测写回) 避免整文件 diff

3.3 Round-trip 门

每次保存后执行「重新生成 → 与落盘 TS 逐字节比对」,不等则回滚并报错。初始迁移同样以此门作为验收标准。

四、扩展模块与消息协议

4.1 新增文件

文件 职责
scripts/heroes-cli.ts Node 子进程脚本,承载 --cmd=query-base / export / validate 三命令;复用 tsconfig.eval.jsonpaths: cc → mock-cc.ts直接 import SkillSet/BuffList/FieldSkillSet/heroSet
source/heroes/generator.ts(主进程侧) JSON→TS 序列化器 + round-trip 校验(可被 heroes-cli 复用)
source/panels/default/components/HeroConfig.ts + static/template/vue/hero-config.html 配置 UI 组件

4.2 消息协议

消息 方向 入参 出参
query-base 面板→主进程 底座快照SkillSet/BuffList/FieldSkillSet 元数据 + 枚举名表;按文件 mtime 缓存)
read-config 面板→主进程 { file: HeroConfigFile, drift?: boolean }JSON 不存在则先跑 --cmd=export
validate 面板→主进程 HeroConfigFile 校验报告error[] / warning[]
save-config 面板→主进程 HeroConfigFile { ok, report }
config-saved 主进程→面板广播 强度评估 tab 重算,形成「改→看」闭环

package.jsoncontributions.messages 补齐上述映射。

4.3 保存流水线(顺序固定)

校验通过 → 备份当前 heroSet.ts → 生成 TS 文本 → ts 语法自检createSourceFile 取 syntactic diagnostics
→ 写 TS临时文件 + rename 原子写)→ round-trip 逐字节比对 → 通过才写 JSON → asset-db refresh-asset

任一步失败:从备份恢复 TS、JSON 保持未写状态、返回错误报告。

五、校验规则分级

5.1 Error阻止保存

规则 说明
uuid 段位匹配 新增时5001-5099=card1 / 5101-5199=card2 / 5201-5299=card3 / 5301-5399=card4 / 5401-5499=card5且不与现有重复编辑现有英雄 uuid 不可改)
skills/触发组 s_uuid 存在 必须在 SkillSet否则运行时静默不出手
timed_buff_id 存在 必须在 BuffList 7001-7024 段
field uuid 存在 必须在 FieldSkillSet 7001-7020 段(与 BuffList 同号段但互不相通)
t_num ≥ 1 0 会导致 % 0 = NaN 永不触发
档位 lv 升序不重复 保存时序列化器强制排序,重复档报错
形态硬约束 tank/warrior→近战组普攻 6004、大招 61036106/6108assassin/射手→中距组60016003/60066008support/mage→远程组60096019、大招 6101/6102/6107/6109~6111辅助技能 6301/6302/6412/6501 不限形态
必填缺失 name / path / type / role

5.2 Warning确认后可存

规则 说明
lv > 6 档位 HERO_MAX_LV=6 封顶lv7/9 档当前永不生效(数据先行,运行时扩展上限后自动生效)
card_lv 1/2/3 配了 field 应改走 ap_bonus/hp_bonus30/40/50% 补偿)
card_lv 4/5 的 lv9 未配 field 按设计指引应有驻场光环
infos 条数与实际档位不匹配 面板逐条展示依赖

六、UI 设计

6.1 布局

同面板default1024×600 dockable顶部 ui-tab:「强度评估|英雄配置」。三栏:

┌ [强度评估 | 英雄配置●] ────────────────────────── ●=有未保存改动 ┐
├────────────┬──────────────────────────────┬─────────┤
│ 🔍搜索     │ 锚点导航: 基础|技能|触发|光环|复活|加成|说明 │ 校验抽屉 │
│ ▾LV5       │ ①基础: uuid/name/path/card_lv/role/type     │  ✕2 ⚠1 │
│  ●5401 刀刀│   hp/ap/def 基准+增量双输入(显示合计)      │  点击   │
│ ▾LV4 …     │ ②技能: [普攻|大招] SkillPicker + 底座只读条  │  定位   │
│ [+新建]   │   + OverridesEditor + 档位矩阵               │ [保存]  │
└────────────┴──────────────────────────────┴─────────┘

6.2 组件清单

组件 职责 数据源 校验
HeroListView card_lv 分组、搜索、dirty 圆点、新建入口 heroSet.data.json
BaseForm 基础字段hp/ap/def 基准+增量双输入 HERO_ROLE_BASE uuid 段位/重复role→type 联动锁定
SkillPicker 自制搜索下拉选 SkillSet显示 6101 火球 · 远程 · AOE SkillSet 普攻限 6001~6019 按 IType 过滤;大招按形态过滤;辅助技能放行
SkillBasePanel 底座关键参数只读展示ap/cd/hit/IType/RType/DTType SkillSet
OverridesEditor 分组编辑 overrides数值 ap/hit_count/num概率 crt/frz/stun击退 bckbuff 注入 timed_buff_id→联动 buff_value/buff_duration永久 buff_type召唤 call_hero BuffList timed_buff_id 存在性
LvMatrix lv 档位矩阵(技能 lv_entries / 触发档 / field / revive 复用变体):行=lv1/2/3/5/7/9、列=参数,可整行复制加档;lv7/9 行黄色边框+⚠「运行时 HERO_MAX_LV=6 暂不生效」 当前英雄 lv 升序不重复t_num≥1
TriggerGroupEditor s_uuid 卡片嵌套档位行(外层技能组、内层档位),保存时统一升序 SkillSet s_uuid 存在性
InfosEditor 9 档分级说明文本 当前英雄 条数与档位对照提示
BonusEditor ap_bonus/hp_bonus 档位lv+value 当前英雄 仅 card_lv1/2/3 提示使用
ValidationPanel 错误/警告列表(区域·字段·消息),点击 scrollIntoView + 字段红框高亮;保存按钮 error>0 时禁用 校验器输出

6.3 关键交互

  • ui- 组件与 Vue 混用isCustomElement 已配置ui- 元素 v-model 不生效,须 :value + @change/@confirm 手动双向;属性用 kebab-case
  • 自制组件ui- 缺失):档位矩阵表格、可搜索 SkillPicker、BuffList 分组下拉、校验列表、确认 modal
  • 新建向导:单屏 modal——选 card_lv → role →(形态按映射自动锁定为只读徽章)→ 模板预填uuid 取段位内最小空位、职业基准属性(增量 0、按指引 2.6 能力组合范式推荐技能tank→6004+6301、support→6009+6302 等、lv3/5/7 空档骨架;提供「空白模板」选项
  • 状态管理dirty 深度 watch加载时存 snapshot 对比),列表项与 tab 标题打点;切换英雄/切 tab 弹确认(放弃/留下);底座加载沿用 spawn 异步 + loading 态
  • 保存流程error>0 → 保存禁用tooltip 显示错误数);仅 warning → 自制 modal 确认后执行保存流水线

七、失败恢复与安全

方案
备份 local/hero_setup/backup/heroSet.<HHmmss>.tslocal/ 已被 git 忽略),滚动保留 5 份;不用 git stash不污染用户暂存区
原子写 同目录临时文件 + renameWindows EPERM编辑器占用时 200ms 退避重试 3 次
语法自检 ts.createSourceFile 取 syntactic diagnosticstypescript 已在依赖);语义级检查提示用户跑 npx tsc --noEmit,不阻塞
回滚 自检/round-trip 失败 → 从备份恢复原文件 → 返回错误报告JSON 保持未写
asset-db 刷新 写后 Editor.Message.request('asset-db', 'refresh-asset', 'db://assets/script/game/common/config/heroSet.ts');禁止「删文件+建新文件」式写法(触发 meta 重建)
并发 面板内保存互斥in-flight promise 复用)+ 串行队列

八、初始迁移(一次性)

  1. --cmd=exporttsx import 现 heroSet.ts → 导出 heroSet.data.json26 英雄 + 14 怪物全量,怪物标记只读)
  2. 从 JSON 重新生成 TS → round-trip 逐字节比对必须通过(迁移门)
  3. 迁移门失败的处理:修序列化器直至通过(一次性成本);确实无法保真的字段(如怪物特有表达式)再评估局部文本透传回退
  4. 迁移完成后 heroSet.ts 数据段即为生成产物,此后手改走「以 TS 反向导入」通道

九、实施阶段

阶段 内容 验收
1. 脚本核心 heroes-cli.ts + JSON schema + 导入器 + 序列化生成器 + round-trip 门(纯 Node 可单测) 迁移门逐字节通过
2. 主进程 methods + 消息协议 + 备份/原子写/自检/刷新 手工消息调用保存成功、编辑器感知刷新
3. 面板骨架 tab + 英雄列表 + 基础表单 + SkillPicker/OverridesEditor 可加载、可编辑基础字段
4. 完整表单 触发组/光环/复活/infos/bonus + 校验抽屉 + 新建向导 校验规则全覆盖、按设计指引录入新英雄走通
5. 联调冒烟 eval-heroes 验证加载链、形态约束用例、按指引落地 1 个 P0 英雄(紫电魔女 5301 强度评估 tab 正常评分

十、遗留事项

  • heroSet.ts:297 注释「怪物5200段」与实际 6001/6101 段不符(幽灵注释),迁移时顺带修正
  • UI 支持 lv7/9 档而 HERO_MAX_LV=6HeroSkillDesc.ts:321-331 会向玩家展示永远无法解锁的 Lv7/Lv9 文案——超 6 档仅预录入,运行时/文案侧需按 HERO_MAX_LV 裁剪(独立任务,不在本功能范围)
  • 未来扩展 HERO_MAX_LV 至 9 时,需同步升级碎片表 HERO_UPGRADE_NEED_FRAGMENTSGameSet.ts:70