09 · 平衡工作流:从建模到版本迭代
09 · 平衡工作流:从建模到版本迭代
1. 八步流程
① 定常数表 → ② 参数外置建模 → ③ 解析+蒙特卡洛 → ④ 机器人跑测
→ ⑤ 内部试玩 → ⑥ 外部试玩+埋点 → ⑦ 三表诊断 → ⑧ 小步迭代
| # | 步骤 | 具体做法 | 产出物 | 门槛 |
|---|---|---|---|---|
| 1 | 定常数表 | 写死体验指标:TTK 区间、单局时长、通关率目标、使用率上限 | 常数表一页纸 | 全部是数字 |
| 2 | 参数外置建模 | 单一数据源,公式与硬编码分离 | 可一键改参重算的模型 | 改数值不编译 |
| 3 | 解析 + 蒙特卡洛 | 先算 EV/闭式解,再跑 10⁴–10⁶ 次看尾部 | TTK 分布、资源曲线、掉落表 | 输出 P5/P50/P95 |
| 4 | 机器人跑测 | AI 按最优/次优策略自动玩 N 局 | 胜率矩阵、出场率矩阵、支配标记 | 无 build 从不出场 |
| 5 | 内部试玩 | 每次只改 1 个变量,记录"卡/烦/爽" | 假设→验证记录 | 主观感受已翻译成数值假设 |
| 6 | 外部试玩 + 埋点 | 关卡开始/结束/死亡点/耗时/资源快照/购买 | 漏斗、死亡热力图、时长分布 | N ≥ 30(定量) |
| 7 | 三表诊断 | 使用率表、通过率表、资源存量曲线 | 问题定位 | 先判"数值问题 or 认知问题" |
| 8 | 小步迭代 | 单次 ≤10%,优先 buff | 版本 patch note | 上线后 2–4 周一次小幅漂移 |
2. 三张诊断表
表 A:使用率表(多样性健康)
| 选项 | 使用率 | 胜率 | 判读 | 处置 |
|---|---|---|---|---|
| > 60% 且胜率领先 | 支配策略 | 见 §3 | ||
| < 5% | 废卡 | buff 或重做(优先给它一个专属情境) | ||
| 5–60% | 健康 | — |
目标:没有废卡 + 没有无敌卡。
表 B:通过率表(难度健康)
| 关卡/波次 | 首次通过率 | 平均尝试次数 | 判读 |
|---|---|---|---|
| < 20% | 难度悬崖 | 检查是数值还是认知问题 | |
| 20–60% | 健康挑战 | — | |
| > 90% | 无挑战 | 加张力 |
骤降点 = 难度悬崖,定位后看是"数值跳变"还是"机制没教"。
表 C:资源存量曲线(经济健康)
- 单调上升 → 通胀
- 某段持平且无进展 → 沙漠
- 锯齿剧烈 → 节奏不稳
3. 支配策略处理顺序(不要一上来就砍)
- 加机会成本(槽位/前置/时间)
- 加硬克制(给对手工具,而非砍它)
- 加条件性(只在 X 时强)
- 正交化(改成"不同"而非"更强")
- 小幅 nerf(≤10%,且 nerf 组合而非单卡)
- 抬水位(buff 其他选项)
4. Buff > Nerf 原则
为什么:nerf 会让玩家的投入被否定,引发"我的 build 白练了"的流失;buff 让所有人变强,水位整体抬高。
| 情况 | 处理 |
|---|---|
| 某项过弱 | buff 它(首选) |
| 某项略强 | buff 其他,抬水位 |
| 某项破坏性 combo(胜率 90%+) | 才 nerf,且只 nerf 组合的关键环节 |
| 通胀 | 加 sink,不砍产出 |
例外:当某项让其他所有选项都不可玩时,nerf 是唯一解,但要配补偿(返还资源、保留玩家已投入的进度)。
5. 埋点清单(最小集)
Demo 阶段就要埋,10 个外部玩家的数据胜过 100 小时内部试玩。
| 类别 | 事件 | 用途 |
|---|---|---|
| 漏斗 | 启动 → 进入首局 → 首次成功 → 首局结束 → 开启第二局 | FTUE 转化 |
| 关卡 | 关卡开始 / 结束 / 放弃 | 通过率与流失点 |
| 战斗 | 死亡点(坐标+原因)/ 重试次数 | 难度悬崖 |
| 经济 | 资源快照(定时)/ 购买行为 / 持有量 | 通胀与沙漠 |
| 构筑 | 选中项 / 出场率 / 组合 | 支配策略 |
| 时长 | 单局时长 / 单关时长 / 总时长 | 节奏校验 |
注意:死亡点必须带原因标签(死于什么、当时状态如何),否则不可归因。
6. 版本节奏
| 阶段 | 节奏 | 幅度 |
|---|---|---|
| 内部迭代 | 每周 | 不限(未面向玩家) |
| EA / 公开测试 | 4–8 周一次实质更新 | 中(低于此频率社区判定"已死") |
| 正式版 | 2–4 周一次小幅 Meta 漂移 | 小(≤10%) |
| 大版本 | 季度 | 可引入新维度 |
长期静止也是问题:Meta 长期不变会让社区停止讨论。小幅持续漂移比"半年一次大改"健康。
7. 数据 vs 直觉的边界
| 数据擅长回答 | 直觉必须保留 |
|---|---|
| 多少(数值、通过率、使用率) | 要不要做 |
| 哪里(流失点、难度悬崖) | 好不好玩 |
| 何时(节奏、时长) | 像不像我们(美学、作者性) |
| 定价、转化 | 叙事与主题取舍 |
铁律:乐趣无法用留存率证明。 漏斗掉点用数据,核心乐趣用观察(表情、重玩意愿、think aloud)。
8. 社区作为平衡基础设施
成功案例(StS、Hades、Deep Rock Galactic)的共同做法:
| 做法 | 说明 |
|---|---|
| 公开 patch note | 让玩家看到你在听 |
| 公开开发路线 | 但只写"下两个更新",宁可低承诺高交付 |
| 给可参与的决策面 | 优先级排序、命名、小系统 —— 不是"许愿池" |
| 保留最终裁决权 | 社区是测试基础设施,不是设计委员会 |
| 分层管理反馈 | 核心玩家小组(决策参与)/ 公开频道(情绪温度计)/ 埋点(真相) |
禁止:"玩家说要什么就加什么"。要追问背后的问题,只修重复出现 ≥3 次的问题。
9. 平衡验收清单(出货前)
- 常数表所有指标达标或有意偏离并记录原因
- 三张诊断表无红项
- 无使用率 >60% 的支配项,无 <5% 的废卡
- 100 小时经济模拟无崩溃,|B| < 5%
- 各 tier Payback 基本恒定
- TTK 落在体验窗口
- 尾部 P5 无灾难性倒霉
- 机器人跑测:至少 3 个可行 build,胜率差 < 15%
- 埋点在线且可查
- 参数可热更(无需重新编译)
10. 反模式
| 症状 | 修法 |
|---|---|
| 靠手感调平衡 | 先建模型 |
| 一次改 5 个数值 | 一次一个,留快照 |
| 只看均值 | 输出 P5/P50/P95 |
| 连续 nerf 引发流失 | 改 buff,抬水位 |
| 只测团队成员 | 外部招募,画像匹配 |
| 埋点在出货前才做 | Demo 阶段就埋 |
| 平衡到所有选项一样强 | 允许 5–10% 差异,目标是"没废卡+没无敌卡" |
| 无版本节奏,长期静止 | 2–4 周小幅漂移 |
| 玩家说什么就做什么 | 追问背后问题,只修重复 ≥3 次 |
| Meta 被少数人垄断(话语权) | 埋点才是真相,论坛是情绪 |
11. 脚本操作手册(一次完整平衡迭代的 SOP)
对应
tools/里的四个脚本。目标:让"平衡问题"在被人发现之前被机器发现。
阶段 0 · 前置条件(不做这步,后面全是空谈)
- 常数表已定(见
templates/03) - 数值参数外置(改数值不重新编译)
- 随机使用固定种子
- 埋点已上线(见 §5 清单)
阶段 1 · 解析求解(5 分钟)
python tools/ttk-calculator.py --dmg 25 --as 1.2 --cc 0.3 --cd 2.0 --hp 300 --armor 100 --k 100
看三件事:
- TTK 是否落在体验窗口(小怪 1–3s / 精英 5–10s / Boss 60–180s)
- 减伤曲线是否符合预期(EHP 是否线性 —— 见
systems/08§11.3) - 乘算堆叠是否爆炸(相对基础 >5× 就要警惕)
阶段 2 · 蒙特卡洛(10 分钟)
python tools/monte-carlo.py --runs 100000 --seed 42
看 P5 与 P95:
- P5 灾难性倒霉 → 加 PRD / 保底
- P95 无聊碾压 → 收窄上限
- CV > 0.6 → 方差过高
阶段 3 · 经济模拟(5 分钟)
python tools/economy-sim.py --hours 100 --csv my_tiers.csv
看两件事:
- 各 tier 的 Payback 比值是否都 <2.0×(否则是沙漠)
- |B| 是否都 <5%(否则通胀/通缩)
阶段 4 · 真实数据扫描(每周)
python tools/balance-scanner.py --dir ./telemetry
看红项数量。红项进 backlog,按 §3 的处置顺序处理。
阶段 5 · 诊断与处置
| 红项 | 先判断 | 处置顺序(不要一上来就砍) |
|---|---|---|
| 支配策略 | 绝对超模 or 缺硬克制? | 机会成本 → 硬克制 → 条件性 → 正交化 → nerf ≤10% → 抬水位 |
| 废卡 | 数值太低 or 缺专属情境? | 先给它一个"只有它能解决"的情境 |
| 难度悬崖 | 数值问题 or 认知问题? | 认知 → 改教学;数值 → 改数值 |
| 通胀 | sink 不足 or faucet 过高? | sink 随 faucet 同阶缩放(不要先砍产出) |
阶段 6 · 回归验证
改动后重跑阶段 1–4,并与上次的黄金数据对比:
| 差异 | 处置 |
|---|---|
| <5% | 通过 |
| 5–15% | 警告,人工确认是否符合预期 |
| >15% | 失败,必须解释原因,不能"失败就更新基准" |
12. 一次完整迭代的实录
用来说明"处置顺序"为什么不能跳过前面几步。
背景
上线 3 周,遥测(balance-scanner.py)输出:
【表 A】使用率诊断
火焰剑 72.0% 78.0% 支配策略
冰霜杖 31.0% 55.0% 健康
...
木棍 2.0% 28.0% 废卡
平均胜率 48.0%
❌ 错误的第一反应
"火焰剑太强了,砍 20% 伤害。"
为什么错:
- nerf 让已投入的玩家感到"白练了" → 流失
- 没诊断"为什么强" —— 可能是缺少克制,而不是数值超模
- 砍 20% 远超"单次 ≤10%"的纪律
✅ 正确的处置流程
步骤 1 · 诊断
| 问 | 答 |
|---|---|
| 是绝对超模吗? | 否 —— 它的 DPS 只比冰霜杖高 12% |
| 是缺少硬克制吗? | 是 —— 没有敌人对火焰伤害有抗性 |
| 是机会成本太低吗? | 是 —— 它不占用额外槽位 |
结论:不是数值问题,是缺少克制 + 机会成本不足。
步骤 2 · 按顺序处置(前两步就解决了)
| 顺序 | 手段 | 具体做法 |
|---|---|---|
| 1 | 加机会成本 | 火焰剑改为占用 2 个槽位(而非 1 个) |
| 2 | 加硬克制 | 新增一类"耐火"敌人(而不是削弱火焰剑) |
| 3–6 | 暂不使用 | — |
关键:给对手加工具,而不是削弱玩家最爱的东西。
步骤 3 · 验证
# 解析层:确认没有引入新的数值问题
python tools/ttk-calculator.py --dmg 25 --as 1.2 --cc 0.3 --cd 2.0
# 分布层:确认方差没有变大
python tools/monte-carlo.py --runs 100000 --seed 42
# 真实数据:上线 2 周后复查
python tools/balance-scanner.py --dir ./telemetry
步骤 4 · 结果(2 周后)
| 指标 | 改动前 | 改动后 |
|---|---|---|
| 火焰剑使用率 | 72% | 48% |
| 冰霜杖使用率 | 31% | 39% |
| 平均胜率 | 48% | 47% |
| 玩家反馈 | "火焰剑无敌" | 无明显抱怨 |
注意:平均胜率几乎没变 —— 这是抬水位的效果,而不是"削弱"。
三条可迁移的经验
- 先诊断再动手 —— "为什么强"决定了怎么改
- 优先给对手加工具(硬克制 > nerf)
- 改完必须重跑全量验证 —— 否则会引入新的问题
13. 参考
- GDC《Math for Game Programmers: Balancing》
- Slay the Spire / Hades 的公开 patch note 实践
- GameDiscoverCo:社区驱动开发的节奏数据
tools/README.md—— 本流程用到的四个脚本