战斗公式建模师
输入「游戏类型+PVP占比+养成周期」,输出伤害公式+PRD暴击+TTK/DPS/EHP验算
combat-formula-modeler — 战斗公式建模 Skill
触发条件
当用户提到"战斗公式"、"伤害计算"、"数值建模"、"战斗数值"、"攻防公式"、"暴击系统"、"属性成长"、"TTK"、"DPS计算"、"数值验证"、"极端值压测"、"减伤建模"、"DPS平衡校验"时触发。 也适用于:用户说"帮我设计战斗公式"、"这个游戏用什么伤害公式好"、"做一下数值验证"、"成长曲线怎么设计"等场景。 当用户给出游戏类型并要求"搭数值框架"时,也应触发。
技能描述
帮助数值策划快速完成战斗数值体系搭建:输入游戏类型和基本需求,输出公式选型方案、参数建议、成长曲线、验证代码。融入微分方程建模方法论。
一、伤害公式选型引擎
决策流程
graph TD
A[游戏类型?] --> B{PVP比重}
B -->|重PVP/竞技| C{需要数值公平?}
C -->|是| D[除法公式 — 收益递减]
C -->|否| E[乘法多层公式]
B -->|重PVE/RPG| F{数值膨胀周期}
F -->|短周期 赛季制| G[减法公式 — 直观]
F -->|长周期 永续| H{养成深度}
H -->|浅 3个月达满| D
H -->|深 6个月+| I[指数/幂函数公式]
B -->|PVP+PVE并重| J[除法公式 + 等级压制系数]
style D fill:#58a6ff22,stroke:#58a6ff
style G fill:#3fb95022,stroke:#3fb950
style I fill:#bc8cff22,stroke:#bc8cff
style E fill:#d2992222,stroke:#d29922
style J fill:#58a6ff22,stroke:#58a6ff
1.1 减法公式(线性防御)
公式:
Damage = max(ATK × SkillRatio - DEF × DefCoeff, ATK × MinDmgRate)
| 参数 | 含义 | 建议范围 |
|---|---|---|
| SkillRatio | 技能倍率 | 1.0~5.0 |
| DefCoeff | 防御系数 | 0.5~1.0 |
| MinDmgRate | 最低伤害比率 | 0.05~0.15 |
适用品类:回合制RPG、早期卡牌、休闲战斗 优点:玩家直观理解"攻击力-防御力=伤害" 缺点:后期易出现"零伤"或"破防"极端;防御边际收益恒定 头部参考:早期勇者斗恶龙、梦幻西游基础伤害层
1.2 除法公式(收益递减防御)⭐ 最通用
公式:
DamageReduction = DEF / (DEF + K)
Damage = ATK × SkillRatio × (1 - DamageReduction)
= ATK × SkillRatio × K / (K + DEF)
| 参数 | 含义 | 调节效果 |
|---|---|---|
| K(核心参数) | 防御基准常数 | K越大→防御越不值钱→偏攻击meta |
K值速查表:
| K值 | DEF=100减伤 | DEF=300减伤 | DEF=500减伤 | 适合的游戏风格 |
|---|---|---|---|---|
| 50 | 66.7% | 85.7% | 90.9% | 防御为王,坦克职业明显 |
| 100 | 50.0% | 75.0% | 83.3% | 平衡型(推荐起点) |
| 200 | 33.3% | 60.0% | 71.4% | 偏攻击,节奏较快 |
| 300 | 25.0% | 50.0% | 62.5% | 攻击主导,秒人快 |
| 500 | 16.7% | 37.5% | 50.0% | 极端攻击meta |
K值动态化(等级关联):
K = K_base + K_growth × Level
// 例:K = 100 + 5 × Level
// 随等级提升,防御的边际价值缓慢降低
适用品类:MOBA、ARPG、大部分现代手游 头部参考:英雄联盟(K≈100)、王者荣耀、原神防御层
1.3 乘法多层公式(独立叠乘)
公式:
FinalDamage = BaseDamage
× (1 - ArmorReduction) // 物理减伤层
× (1 - MagicResistReduction) // 法术抗性层
× (1 - DamageReduction) // 通用减伤层
× (1 + DamageBonus) // 增伤层
× ElementMultiplier // 属性克制
特点:各层独立计算,永远不会100%减伤 适用品类:暗黑like、POE、复杂养成ARPG 头部参考:暗黑破坏神系列、流放之路
1.4 指数/幂函数公式
公式:
Damage = ATK × (ATK / DEF) ^ n × SkillRatio
// 或
Damage = ATK × e^(-DEF / K)
| n值 | 效果 | 适用场景 |
|---|---|---|
| 0.3~0.5 | 温和的攻防差距影响 | 竞技类,不想拉大差距 |
| 0.5~0.7 | 中等差距影响 | RPG主流 |
| 0.7~1.0 | 强烈的等级碾压感 | 强调等级/装备压制 |
适用品类:强调等级压制的MMO、SLG 头部参考:DNF(攻防差明显影响输出)
二、暴击系统设计
2.1 暴击期望公式
E(Damage) = BaseDamage × (1 + CritRate × (CritDamage - 1))
最优配比法则:暴击率:暴击伤害获取成本 = 1:2 时,期望伤害最大化
- 引导方式:让暴击率装备和暴击伤害装备的属性密度满足这个比例
2.2 纯随机暴击
import random
def pure_random_crit(base_damage, crit_rate, crit_damage):
if random.random() < crit_rate:
return base_damage * crit_damage
return base_damage
问题:手感差,可能连续10次暴击或10次不暴击
2.3 PRD伪随机(推荐)⭐
DOTA2 风格伪随机分布,保持期望不变但减少极端情况:
class PRDCrit:
"""伪随机暴击系统 — 保底+防连击"""
# 名义暴击率 → PRD初始概率C的映射表
C_TABLE = {
0.05: 0.003802, 0.10: 0.014746, 0.15: 0.032221,
0.20: 0.055704, 0.25: 0.084744, 0.30: 0.118949,
0.35: 0.157983, 0.40: 0.201547, 0.45: 0.249306,
0.50: 0.302103, 0.55: 0.360397, 0.60: 0.422649,
0.65: 0.481523, 0.70: 0.571429, 0.75: 0.666667,
}
def __init__(self, nominal_rate: float):
self.nominal_rate = nominal_rate
self.c = self._get_c(nominal_rate)
self.fail_count = 0
def _get_c(self, rate):
"""插值获取C值"""
keys = sorted(self.C_TABLE.keys())
for i in range(len(keys) - 1):
if keys[i] <= rate <= keys[i+1]:
t = (rate - keys[i]) / (keys[i+1] - keys[i])
return self.C_TABLE[keys[i]] * (1-t) + self.C_TABLE[keys[i+1]] * t
return rate # fallback
def try_crit(self) -> bool:
"""尝试暴击,返回是否暴击"""
import random
self.fail_count += 1
prob = self.c * self.fail_count
if random.random() < prob:
self.fail_count = 0
return True
return False
# 使用示例
crit = PRDCrit(0.25) # 25%名义暴击率
results = [crit.try_crit() for _ in range(10000)]
print(f"实际暴击率: {sum(results)/len(results):.2%}") # ≈25%
2.4 暴击率计算方式
基于属性的暴击率(收益递减型):
CritRate = CritValue / (CritValue + K_crit)
// K_crit 决定暴击率的获取难度
// 例:K_crit=1000,CritValue=500 → 暴击率=33.3%
暴击率上限:建议设置 75%~85% 硬上限,避免暴击率100%
三、属性成长曲线
3.1 曲线类型选择器
| 曲线类型 | 公式 | 前期 | 中期 | 后期 | 适用 |
|---|---|---|---|---|---|
| 线性 | a × L + b | 匀速 | 匀速 | 匀速 | 简单系统 |
| 二次方 | a × L² + b | 慢 | 中 | 快 | 最常用·通用 |
| 三次方 | a × L³ + b | 很慢 | 中 | 很快 | 长线养成 |
| 指数 | a × r^L | 很慢 | 快 | 爆炸 | 赛季制/无限等级 |
| 对数 | a × ln(L) + b | 快 | 慢 | 极慢 | 快速到达体验 |
| S型 | L_max / (1+e^(-k(L-L0))) | 慢 | 快 | 慢 | 有上限的系统 |
| 分段(实战最优) | 各段独立公式 | 自定义 | 自定义 | 自定义 | 手游推荐 |
3.2 分段经验曲线模板
def exp_required(level: int) -> int:
"""分段经验需求 — 手游标准三段式"""
if level <= 30:
# 快速成长期:让玩家2周内到30级
return int(50 * level ** 1.5)
elif level <= 60:
# 稳定成长期:30→60需要约1.5个月
return int(200 * level ** 2)
else:
# 缓慢成长期:60→100需要3个月+
return int(500 * level ** 2.5)
# 打印经验表
for lv in [1,10,20,30,40,50,60,70,80,90,100]:
print(f"Lv.{lv:3d} → {exp_required(lv):>12,} EXP")
3.3 属性成长模板
def attribute_growth(base, growth, level, quality_mult=1.0):
"""
通用属性成长公式
base: 1级基础值
growth: 每级成长值
level: 当前等级
quality_mult: 品质系数 (B=0.8, A=1.0, S=1.2, SS=1.5, SSS=2.0)
"""
return int((base + growth * (level - 1)) * quality_mult)
# 品质差异化示例
qualities = {'B': 0.8, 'A': 1.0, 'S': 1.2, 'SS': 1.5, 'SSS': 2.0}
for q, mult in qualities.items():
atk = attribute_growth(base=100, growth=12, level=60, quality_mult=mult)
print(f"{q:>3s}级 Lv.60 ATK = {atk}")
四、战斗模拟验证
4.1 核心验证指标
| 指标 | 公式 | 健康范围 | 说明 |
|---|---|---|---|
| TTK (Time to Kill) | 目标HP ÷ DPS | PVP: 3 | 击杀时间 |
| DPS (每秒输出) | E(单次伤害) × 攻速 | — | 持续输出能力 |
| EHP (有效生命) | HP × (1 + DEF/K) | — | 考虑防御后的等效血量 |
| TTK比 | 最高TTK ÷ 最低TTK | < 3.0 | 职业间平衡度 |
| 输出差 | 最高DPS ÷ 最低DPS | < 2.5 | 同等级/装备下的差距 |
| 治疗压力 | 秒伤 ÷ 秒治疗 | 0.6~0.8 | 团队战斗节奏 |
4.2 Python 战斗模拟器
import random
from dataclasses import dataclass
@dataclass
class Fighter:
name: str
hp: int
atk: int
defense: int # 'def' is reserved
crit_rate: float = 0.2
crit_damage: float = 1.5
atk_speed: float = 1.0 # 攻击/秒
class BattleSimulator:
"""简易战斗模拟器 — 除法公式"""
def __init__(self, K=100):
self.K = K
def calc_damage(self, attacker: Fighter, defender: Fighter) -> float:
"""单次伤害计算"""
reduction = defender.defense / (defender.defense + self.K)
base_dmg = attacker.atk * (1 - reduction)
# 暴击判定
if random.random() < attacker.crit_rate:
base_dmg *= attacker.crit_damage
# 随机浮动 ±5%
base_dmg *= random.uniform(0.95, 1.05)
return max(base_dmg, 1)
def simulate_duel(self, a: Fighter, b: Fighter, rounds=1000):
"""模拟对战,返回统计结果"""
a_wins = 0
total_turns_list = []
for _ in range(rounds):
hp_a, hp_b = a.hp, b.hp
turns = 0
while hp_a > 0 and hp_b > 0:
turns += 1
# A 攻击 B
hp_b -= self.calc_damage(a, b)
if hp_b <= 0:
a_wins += 1
break
# B 攻击 A
hp_a -= self.calc_damage(b, a)
total_turns_list.append(turns)
avg_turns = sum(total_turns_list) / len(total_turns_list)
return {
'a_win_rate': a_wins / rounds,
'b_win_rate': 1 - a_wins / rounds,
'avg_turns': avg_turns,
'avg_ttk_seconds': avg_turns / max(a.atk_speed, b.atk_speed),
}
def calc_ehp(self, fighter: Fighter) -> float:
"""计算有效生命值"""
return fighter.hp * (1 + fighter.defense / self.K)
def calc_expected_dps(self, fighter: Fighter, target: Fighter) -> float:
"""计算期望DPS"""
reduction = target.defense / (target.defense + self.K)
base_dmg = fighter.atk * (1 - reduction)
crit_mult = 1 + fighter.crit_rate * (fighter.crit_damage - 1)
return base_dmg * crit_mult * fighter.atk_speed
# === 使用示例 ===
if __name__ == '__main__':
sim = BattleSimulator(K=100)
warrior = Fighter('战士', hp=5000, atk=300, defense=200, crit_rate=0.15, crit_damage=1.5)
mage = Fighter('法师', hp=3000, atk=500, defense=80, crit_rate=0.25, crit_damage=2.0)
tank = Fighter('坦克', hp=8000, atk=150, defense=400, crit_rate=0.05, crit_damage=1.5)
roles = [warrior, mage, tank]
print("=== 有效生命值(EHP) & 期望DPS ===")
for r in roles:
ehp = sim.calc_ehp(r)
for target in roles:
if target != r:
dps = sim.calc_expected_dps(r, target)
ttk = target.hp / dps if dps > 0 else float('inf')
print(f"{r.name} vs {target.name}: DPS={dps:.0f}, TTK={ttk:.1f}s")
print(f"{r.name} EHP={sim.calc_ehp(r):.0f}")
print()
print("=== 对战模拟 (1000回合) ===")
for i, a in enumerate(roles):
for b in roles[i+1:]:
result = sim.simulate_duel(a, b)
print(f"{a.name} vs {b.name}: "
f"胜率 {result['a_win_rate']:.1%} / {result['b_win_rate']:.1%}, "
f"平均回合 {result['avg_turns']:.1f}")
4.3 验证检查清单
- 同等级同装备的不同职业,TTK差异 < 3倍
- 高10级打低10级,TTK < 正常TTK的30%(等级压制明显但不秒杀)
- 纯堆防御的极端Build,仍然可以被击杀(EHP不超过正常的5倍)
- 纯堆攻击的极端Build,TTK > 2秒(不能秒杀)
- 暴击系统不会出现连续5次以上暴击(使用PRD)
- 治疗量 < 同等级DPS的80%(治疗不能完全抵消伤害)
- 等级×10的差距内,低等级仍有胜算(> 20%胜率)
五、微分方程建模方法论
核心思想来源于《游戏数学建模工程手册》:游戏的数值系统本质上是一个动态系统,可以用微分方程描述其状态随时间的变化。
5.1 核心建模范式
玩家战力成长 = 微分方程的解曲线
dP/dt = f(t, P, R)
P = 玩家战力 (Power)
t = 游戏时间 (天)
R = 资源投入速率 (每日获取资源量)
f = 成长函数 (由养成系统决定)
5.2 三种典型成长模型
模型A:线性成长(匀速养成)
dP/dt = c (常数)
P(t) = c × t + P₀
适合:休闲游戏、赛季初期
模型B:指数成长(加速养成)
dP/dt = k × P
P(t) = P₀ × e^(kt)
适合:SLG前期扩张、卡牌等级成长
模型C:逻辑斯谛成长(S型·有上限) ⭐推荐
dP/dt = r × P × (1 - P/P_max)
P(t) = P_max / (1 + ((P_max - P₀)/P₀) × e^(-rt))
适合:有明确战力天花板的游戏,中期成长最快,自然减速
5.3 经济系统的微分方程
资源存量动态:
dS/dt = Production(t) - Consumption(S, t)
S = 资源存量
Production = 产出速率(随等级/VIP提升)
Consumption = 消耗速率(随养成进度增加)
通胀判定:当 dS/dt > 0 持续超过 N 天,系统进入通胀状态 紧缩判定:当 dS/dt < 0 持续超过 N 天,玩家体验产出匮乏
5.4 实践应用:用ODE拟合验证数值表
from scipy.integrate import odeint
import numpy as np
def growth_model(P, t, r, P_max):
"""逻辑斯谛成长模型"""
return r * P * (1 - P / P_max)
# 参数
P0 = 100 # 初始战力
P_max = 50000 # 战力上限
r = 0.05 # 成长速率
t = np.linspace(0, 180, 181) # 180天
# 求解ODE
P = odeint(growth_model, P0, t, args=(r, P_max))
# 打印关键节点
for day in [7, 14, 30, 60, 90, 120, 150, 180]:
print(f"第{day:3d}天: 战力 = {P[day][0]:,.0f} ({P[day][0]/P_max*100:.1f}%)")
六、元素/属性克制系统
6.1 克制矩阵模板
三属性环(最简):
火 → 冰 → 雷 → 火
克制倍率:1.5x 被克倍率:0.67x 同属性:1.0x
五行环(仙侠/武侠):
金 → 木 → 土 → 水 → 火 → 金
克制倍率:1.3x 被克倍率:0.75x
多属性矩阵(复杂型,如宝可梦):
| 攻\防 | 火 | 水 | 草 | 电 | 冰 | 地 |
|---|---|---|---|---|---|---|
| 火 | 0.5 | 0.5 | 2.0 | 1.0 | 2.0 | 1.0 |
| 水 | 2.0 | 0.5 | 0.5 | 1.0 | 1.0 | 2.0 |
| 草 | 0.5 | 2.0 | 0.5 | 1.0 | 1.0 | 2.0 |
| 电 | 1.0 | 2.0 | 0.5 | 0.5 | 1.0 | 0.0 |
双属性防御时:倍率相乘(4x超效/0.25x抵抗/0x免疫均可能出现)
6.2 反应体系(原神风格)
增幅反应(蒸发/融化):
FinalDamage = BaseDamage × ReactionMult × (1 + EM_Bonus)
ReactionMult = 1.5(弱增幅)或 2.0(强增幅)
EM_Bonus = 2.78 × EM / (EM + 1400)
剧变反应(超载/感电/扩散):
FinalDamage = LevelBaseDamage × ReactionCoeff × (1 + EM_Bonus)
// 独立于攻击力,只与等级和精通有关
6.3 平衡性验证方法
def verify_element_balance(matrix):
"""验证克制矩阵是否存在绝对优势属性"""
n = len(matrix)
for i in range(n):
advantage_count = sum(1 for j in range(n) if matrix[i][j] > 1.0)
disadvantage_count = sum(1 for j in range(n) if matrix[i][j] < 1.0)
ratio = advantage_count / max(disadvantage_count, 1)
if ratio > 2.0:
print(f"⚠️ 属性{i}克制比过高({ratio:.1f}),可能存在优势属性")
print(f"属性{i}: 克制{advantage_count}个 / 被克{disadvantage_count}个, 比率={ratio:.1f}")
七、治疗/护盾/控制机制
7.1 治疗公式
基础治疗:
HealAmount = HealPower × SkillRatio + FlatHeal
暴击治疗(允许治疗暴击时):
if random() < CritRate:
HealAmount *= CritHealMult // 通常 1.25~1.5(低于伤害暴击倍率)
治疗衰减(防止无限续航):
// 超量治疗递减:同一回合内第N次治疗效果衰减
EffectiveHeal = HealAmount × 0.8^(N-1)
// 第1次100%、第2次80%、第3次64%...
7.2 护盾公式
ShieldValue = ShieldPower × SkillRatio + FlatShield
ShieldDuration = BaseDuration // 通常 5~10秒
护盾吸收:先扣护盾,护盾破碎后溢出伤害才扣血
EffectiveDamage = max(0, Damage - CurrentShield)
CurrentShield = max(0, CurrentShield - Damage)
护盾衰减(防止无限叠盾):
// 方案A:护盾不可叠加,新盾替换旧盾(取较大值)
// 方案B:护盾叠加但总量不超过MaxHP的50%
MaxShield = MaxHP × 0.5
7.3 控制机制公式
控制时长 = BaseControlDuration × (1 - Tenacity/100)
Tenacity = 韧性属性(0~75,75%为减控上限)
// 递减控制(MOBA常用):
// 短时间内连续受控时,后续控制时长递减
EffectiveDuration = BaseDuration × 0.7^(RecentControlCount)
7.4 治疗压力指标
| 指标 | 公式 | 健康范围 | 说明 |
|---|---|---|---|
| 治疗压力比 | TeamDPS ÷ TeamHPS | 1.2~1.8 | <1.0=治疗过强 >2.5=治疗无意义 |
| 续航回合数 | TeamHP ÷ (IncomingDPS - TeamHPS) | 8~15回合 | 团队在受攻击下能存活的回合数 |
八、等级压制系数
公式
LevelSuppression = clamp(1 - SuppRate × (DefLevel - AtkLevel), 0.1, 1.5)
SuppRate = 0.03~0.08(每级压制率)
- 0.03: 温和压制(竞技向,10级差=30%衰减)
- 0.05: 标准压制(RPG常用,10级差=50%衰减)
- 0.08: 强力压制(强PVE等级墙,10级差=80%衰减)
FinalDamage = BaseDamage × LevelSuppression
示例(SuppRate=0.05)
| 等级差(攻-防) | 压制系数 | 效果 |
|---|---|---|
| +10 | 1.50(上限) | 碾压,伤害×1.5 |
| +5 | 1.25 | 明显优势 |
| 0 | 1.00 | 公平对战 |
| -5 | 0.75 | 明显劣势 |
| -10 | 0.50 | 重度劣势 |
| -20 | 0.10(下限) | 几乎无法造成伤害 |
九、配表模板
角色属性表
| 角色ID | 角色名 | 品质 | 初始HP | HP成长 | 初始ATK | ATK成长 | 初始DEF | DEF成长 | 暴击率 | 暴击伤害 | 攻速 |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 1001 | 战士 | S | 1200 | 180 | 100 | 12 | 80 | 10 | 10% | 150% | 1.0 |
| 1002 | 法师 | S | 800 | 100 | 160 | 18 | 40 | 5 | 20% | 180% | 0.8 |
| 1003 | 坦克 | A | 1800 | 250 | 60 | 6 | 120 | 16 | 5% | 130% | 0.7 |
| 1004 | 刺客 | SS | 700 | 85 | 140 | 16 | 35 | 4 | 30% | 200% | 1.5 |
| 1005 | 治疗 | A | 900 | 120 | 80 | 8 | 60 | 8 | 8% | 140% | 1.0 |
等级经验表
| 等级 | 所需经验 | 累计经验 | 预计天数 | HP系数 | ATK系数 | DEF系数 |
|---|---|---|---|---|---|---|
| 1 | 0 | 0 | 0 | 1.00 | 1.00 | 1.00 |
| 10 | 1,581 | 8,500 | 2 | 1.45 | 1.45 | 1.45 |
| 20 | 4,472 | 42,000 | 5 | 1.90 | 1.90 | 1.90 |
| 30 | 8,216 | 110,000 | 10 | 2.35 | 2.35 | 2.35 |
⚡ 分段切换点:Lv.31起使用二次方公式 200×L²,经验需求大幅跃升 | ||||||
| 40 | 320,000 | 850,000 | 20 | 2.80 | 2.80 | 2.80 |
| 50 | 1,000,000 | 3,200,000 | 35 | 3.25 | 3.25 | 3.25 |
| 60 | 1,440,000 | 7,800,000 | 55 | 3.70 | 3.70 | 3.70 |
七、输出规范
使用本 Skill 时,按以下结构输出数值方案:
# [游戏名称] 战斗数值设计方案
## 1. 项目信息
- 游戏类型、战斗节奏、PVP/PVE比重、等级上限、养成周期
## 2. 伤害公式
- 选型依据
- 完整公式 + 各参数说明
- 公式曲线图(描述或Python绘制)
## 3. 暴击/命中/闪避系统
- 各系统公式 + 参数
- 是否使用PRD
## 4. 属性成长表
- 角色属性配表
- 等级经验表
- 成长曲线类型和参数
## 5. 战斗模拟验证
- TTK / DPS / EHP 指标表
- 职业对战胜率矩阵
- 等级压制验证
- Python验证代码
## 6. 验证结论
- 对照检查清单的逐项结果
- 需要调优的参数建议
## 7. 下游交接物
- 交付给UI拆解师:角色属性面板展示字段清单、战斗HUD数据接口(血条/蓝条/技能CD/伤害数字格式)、属性克制关系图
- 交付给架构师:战力计算公式、养成线数值区间、各系统战力占比
⚡ 一键安装
复制给智能体安装:
npx clawgamers install combat-formula-modeler把上面的命令丢给智能体 (Claude Code / Cursor / Codex 任一), ta 会装到当前工作目录的 skills/ 文件夹