Axıs
技能目录

08 · 数值公式库与建模

08 · 数值公式库与建模

用法:先定体验指标(常数表),再选公式,再调参,最后蒙特卡洛验证。 不要反过来。

1. 递减收益族(防堆叠)

公式 形式 特点 调参直觉 适用
双曲型 y = A·x/(x+k) 无硬上限,渐进趋近 A k = 拐点:x=k 时收益半衰;k 越小越早塌陷 暴击率、吸血、减伤、产量
指数趋近 y = A·(1−e^(−x/k)) 平滑,天然硬上限 A A 定终值,k 定前期陡峭度 冷却缩减、闪避、命中
对数型 y = k·ln(1+x/k) 无上限但增长极慢 允许硬核无限投入但不破坏平衡 后期主属性、声望

选择依据:必须有天花板 → 指数趋近;希望保留微小增长 → 双曲/对数。

2. 战斗核心族

公式 形式 用途
减伤 DR = A/(A+K) K = 半效点(A=K 时减伤 50%)
EHP EHP = HP/(1−DR) = HP·(1+A/K) EHP 对护甲是线性的,所以护甲不边际递减;递减的是减伤百分比
期望 DPS eDPS = dmg × 攻速 × (1 + 暴击率 × (暴击倍率−1)) 暴击/攻速/暴伤三者乘算 → 三次曲线,这是 ARPG 数值爆炸的数学根因
TTK / TTD TTK = 敌EHP/我eDPS,TTD = 我EHP/敌eDPS 对称战斗平衡判据:TTK ≈ TTD
战力指数 Power ≈ DPS × EHP 把多维属性压成可比标量;兰彻斯特平方律:有效战力 ∝ 属性²×数量²

TTK 体验窗口(PVE):

对象 目标 TTK
小怪 1–3 秒
精英 5–10 秒
Boss 60–180 秒

超出窗口 = "打不动"或"秒了",都是体验事故。

组队修正:4 人完美配合 ≈ 16 倍而非 4 倍,组队/Boss 平衡需引入协作系数 α 折减(Power_team = ΣPower × α,α ≈ 0.6–0.8)。

3. 随机性族

公式 形式 用途
期望值 EV = Σpᵢvᵢ 平衡的基础
方差 Var = Σpᵢ(vᵢ−EV)² 方差才是挫败来源,不是 EV
变异系数 CV = σ/EV 低风险场景 < 0.2;赌博场景可 > 1
伪随机 PRD P(N) = C·N,N = 连续未触发次数 25% → C≈8.5%;50% → C≈30%。压缩连续不中/连续中都发生,长期频率不变
硬保底 P(至少一次) = 1−(1−p)ⁿ 抽卡
软保底 p(n) = p₀ + β·max(0, n−n₀) 优于硬保底:运气曲线平滑,EV 提升控制在 +10~20%

PRD 适用场景:暴击、闪避、掉落。凡是"连续 5 次不触发"会引发愤怒的地方,都该用 PRD。

4. 成长族

公式 形式 适用
线性 a + b·n 短流程
多项式 a·n^k(k=1.5~2) 通用
指数 a·(1+r)^n,r ≤ 0.15 放置类
经验需求 XP(n) = c·n^1.5~2 与战力曲线同阶
S 曲线 y = L/(1+e^(−k(n−n₀))) 熟练度、留存养成;把起飞点 n₀ 放在玩家已投入 3–5 小时处最利于留存

5. 难度族

公式 形式 说明
心流目标 D(t) ≈ S(t) × 1.05–1.15 上偏焦虑,下偏无聊
隐形 DDA ΔD = λ·(胜率 − 0.5) λ 小步,且只向下补偿(帮弱者),不惩罚强者
财富缩放 威胁 = f(玩家实力指标) Rimworld AI Storyteller:按殖民地财富缩放 + 紧张/喘息节律
Elo/TrueSkill Elo' = Elo + K·(实际 − 期望) PVP;新手 K=32,老手 K=16

6. 经济族

公式 形式 用途
净值 ΔM = ΣSources − ΣSinks 经济健康
通胀指数 B = ΔM/M流通量,|B|>5% 预警 监控
回本时间 Payback = 成本/边际产出增量 跨层级应恒定
定价锚点 EV(抽数) = 目标价值 → 反推 p 与保底阈值 抽卡/商店

7. 建模工作流(五步)

步骤 1:参数外置(最高优先级)

所有数值集中在单一数据源(Excel / Google Sheet / JSON),游戏启动时读取。 改数值不重新编译 —— 这一条能把迭代速度提升一个量级。

禁止:代码里写死 damage = 100 * level
要求:damage = Config.GetValue("player.damage.base") * curve.Eval(level)

步骤 2:解析求解

先算闭式解(EV、EHP、TTK),建立直觉。 产出:常数表 + 关键公式的闭式结果表。

步骤 3:蒙特卡洛

跑 10⁴–10⁶ 次,看分布尾部而非均值。

必须输出三条线:P5 / P50 / P95
关注:P5 是否"灾难性倒霉"(玩家会愤怒),P95 是否"无聊地碾压"

只看均值是头号错误 —— EV 平衡了但体验两极。

步骤 4:机器人跑通全程

写脚本让 AI 按最优/次优策略自动玩 N 局,输出:

  • 资源曲线(是否有沙漠/崩溃点)
  • 通过率曲线(是否有难度悬崖)
  • build 出场率矩阵(哪个 build 从不出场 → 废卡)

步骤 5:小步迭代

每次只改 1 个变量,保留版本快照。多变量同时改 = 丢失因果。 单次调整幅度 ≤ 10%。

8. 工具链选择(独立游戏版)

工具 适用 成本
Excel / Google Sheet 90% 的独立项目够用 0
Python + numpy(1000 行内) 蒙特卡洛、分布可视化 低
Machinations 复杂经济系统的可视化 + 一键蒙特卡洛 中
引擎内 debug 面板 实时改参、可视化调试层 低,必要
自建模拟器 卡牌/自走棋类必须 中高

投入控制:工具投入不超过总工时 5%。多数独立项目一张表 + 一个模拟脚本够用。

9. 调参直觉速查

你想... 调什么
让前期更爽 降低递减收益的 k(更早接近上限)或提高线性项 b
让后期不失控 降低指数 r,或换递减收益
让堆叠无效 加递减收益
让某个属性有天花板 指数趋近(硬上限 A)
减少玩家愤怒 用 PRD 替代真随机;降低高赌注时刻的方差
让战斗更长/更短 调 EHP 或 eDPS,不要同时调
让某 tier 不再像沙漠 缩短该段或插入过渡奖励
让 build 更分散 加正交维度,而非 nerf 头部

10. 反模式

症状 修法
数值硬编码在代码里 参数外置,启动读取
只算 EV 不算方差 输出 P5/P50/P95 三条线
多变量同时改 一次一个,留快照
靠手感调平衡 先建模型,手感只用于微调
工具投入过大 控制在 5% 工时内
指数成长 r > 0.15 降 r 或换曲线
三个乘算属性同时堆叠 用递减收益约束至少一个
忽视尾部灾难 蒙特卡洛必看 P5

11. 曲线族详解与调参案例

前一节给的是"用什么公式",本节给的是"为什么是这个公式"以及"参数怎么定"。

11.1 递减收益(双曲型):从上限反推 k

y = A · x / (x + k)

性质:
  x → ∞ 时  y → A            (A 是硬上限,永远不会到达)
  x = k  时  y = A / 2       (k 是半效点)
  导数 y' = A·k / (x+k)²     (收益随 x 增大而下降 —— 这才是"递减"的来源)

调参两步法(顺序不能反):

  1. 先定上限 A —— 你想要这个属性的理论最大值是多少?
  2. 再定半效点 k —— 你希望玩家堆到多少点时拿到一半收益?

完整案例:暴击率

需求:暴击率上限 60%;玩家在 100 点暴击属性时应该达到 30%
求解:0.6 · 100/(100+k) = 0.3
     → 100/(100+k) = 0.5
     → 100 + k = 200
     → k = 100
结果:crit(x) = 0.6 · x / (x + 100)

失败案例:k 设得太小(如 k=10)。 玩家堆到 30 点就已经拿到 45% 暴击,再堆 30 点只多 6% → "堆暴击没意义"。 症状:玩家反馈"后期加属性没感觉"。修法:增大 k。

失败案例 2:k 设得太大(如 k=1000)。 玩家堆到 500 点才拿到 20% 暴击 → "暴击根本堆不起来"。 修法:减小 k,或提高 A。

11.2 指数趋近型:更平滑的无拐点版本

y = A · (1 − e^(−x/k))

性质:
  x = k 时  y ≈ 0.632A       (注意不是 0.5,和双曲型不同)
  无拐点,曲线处处平滑
  天然带硬上限 A

选择依据:

你想要 用哪个
明确的"半效点"(便于和玩家沟通) 双曲型
更平滑的手感、不想要明显拐点 指数趋近型
前期就要有明显收益 指数趋近型(前段更陡)
保留"永远还有一点点提升" 双曲型或对数型

11.3 减伤与 EHP 的反直觉(最常被搞错的一条)

DR = A / (A + K)          →  DR 百分比递减
EHP = HP / (1 − DR) = HP · (1 + A/K)   →  EHP 对 A 是线性的!

这意味着:护甲在 EHP 意义上并不递减。 很多设计师以为"护甲会递减",于是给护甲加了额外的递减 —— 结果是护甲变成废属性。

推导:

EHP(A) = HP · (1 + A/K) = HP + (HP/K)·A
                        ↑ 这是关于 A 的一次函数(直线)

验证(见 tools/ttk-calculator.py 的减伤曲线输出):

护甲 DR EHP 倍率 每点护甲的 EHP 增量
0 0% 1.00× —
25 20% 1.25× 恒定
50 33.3% 1.50× 恒定
100 50% 2.00× 恒定
200 66.7% 3.00× 恒定

失败案例:用 DR = A/(A+K) 却以为护甲递减,于是没做任何约束。 玩家很快发现"无脑堆护甲最优" → 支配策略(见 principles/03 §3)。

修法二选一:

  1. 改用 DR = 1 − e^(−A/K) —— 这时 EHP 才真正递减
  2. 保留线性 EHP,但用其他机制约束(护甲占用装备槽、有重量、有上限)

11.4 期望 DPS 的三次曲线(数值爆炸的数学根因)

eDPS = 基础伤害 × 攻速 × (1 + 暴击率 × (暴击倍率 − 1))
       └── 因子1 ──┘ └因子2┘ └──────── 因子3 ────────┘

三个因子相乘 → 同时堆叠时是立方级增长。

tools/ttk-calculator.py 的实测演示:

阶段 DPS 相对基础
基础 30.0 1.00×
+攻速 50% 45.0 1.50×
+暴击率 50% 67.5 2.25×
+暴伤 到 3.0 90.0 3.00×
+基础伤害 100% 180.0 6.00×

修法:对至少一个乘数使用递减收益。 常见做法:暴击率用递减收益,攻速设硬上限,暴伤作为稀有属性。

11.5 成长曲线选择矩阵

曲线 形式 前期手感 后期风险 适用
线性 a + b·n 平稳 平淡 短流程、叙事
多项式 a·n^k (k=1.5–2) 爽 k>2 时失控 通用 RPG
指数 a·(1+r)^n 极爽 r>0.15 时 30 级后失控 放置类
对数 k·ln(1+n/k) 无感 无 硬核后期投入
递减收益 A·n/(n+k) 快 无 防堆叠属性

选择顺序:先问"我希望玩家在第 10 小时感觉变强了多少?" → 再选曲线 → 再定参数。

经验需求对齐:XP(n) = c·n^1.5~2 必须与战力曲线 n^k 同阶。 不同阶 → 出现"某几级特别慢"(资源沙漠)。


12. 工具链对接

本节的公式已全部实现为可运行脚本,见 tools/。

你要验证什么 跑哪个脚本 输出
TTK 是否落在体验窗口 tools/ttk-calculator.py TTK + 窗口判定
减伤曲线是否符合预期 tools/ttk-calculator.py DR / EHP 倍率表
暴击堆叠会不会爆炸 tools/ttk-calculator.py 乘算堆叠对比
PRD 的尾部压缩效果 tools/ttk-calculator.py 真随机 vs PRD 对比
分布尾部(P5/P95) tools/monte-carlo.py 五档分位 + CV
经济通胀与回本时间 tools/economy-sim.py 回本表 + 存量曲线
支配策略与废卡 tools/balance-scanner.py 三张表红项

使用纪律(三条,缺一则工具白做):

  1. 参数外置 —— 数值必须从外部数据源读取,否则脚本无法接入
  2. 固定种子 —— 版本对比必须可复现
  3. 每次只改一个变量 —— 多变量同时改会丢失因果

投入控制:工具总投入不超过总工时 5%。 多数独立项目:一张表 + 一个模拟脚本就够了,不要自研通用框架。

PRD 的 C 值必须反查(tools/ttk-calculator.py 内置 PRD_C_TABLE): 目标 25% → C≈0.0847,不是 0.302(那是 50% 的常数)。 用错 C 值会让实际触发频率翻倍,而长期均值看起来"正常"。


13. 参考

  • GDC《Math for Game Programmers》系列(Balancing / Juicing)
  • machinations.io —— 可视化经济建模
  • Liquipedia PRD 表 —— 完整 C 值常数表
  • Adams & Dormans《Game Mechanics: Advanced Game Design》—— Machinations 方法论
  • tools/README.md —— 本节公式的可运行实现