Modifier 的进阶:MMC 与 ExecutionCalculation
固定数字与曲线能满足 80% 需求,"伤害 = 攻击力 × 技能倍率 - 护甲 × (1-穿甲)"这类公式需要代码参与。GAS 提供两个入口。
Modifier Magnitude Calculation(MMC)
针对单个 Modifier 的计算类:
UCLASS()
class UMMC_Damage : public UGameplayModifierMagnitudeCalculation
{
GENERATED_BODY()
public:
UMMC_Damage();
float CalculateBaseMagnitude_Implementation(const FGameplayEffectSpec& Spec) const override;
};
float UMMC_Damage::CalculateBaseMagnitude_Implementation(const FGameplayEffectSpec& Spec) const
{
// 取自己的攻击力
float Attack = 0.f;
UMyAttributeSet* SrcSet = Spec.GetContext().GetSourceASC()->GetSet<UMyAttributeSet>();
if (SrcSet) Attack = SrcSet->GetAttack();
return DamageBase * Attack; // 基础伤害 × 施法者攻击力
}
GE 的 Modifier 处选 Attribute-Based → Calculation Class,即可调用这个 MMC。它轻量、可缓存(GAS 会缓存计算结果)。
什么时候用 MMC:单个属性的简单派生计算(如"伤害随攻击力走")。
Execution Calculation(EC)
针对整个 GE 的自定义执行——不受 Modifier 列表约束,可一次改多个属性、做复杂逻辑:
UCLASS()
class UEC_Damage : public UGameplayEffectExecutionCalculation
{
GENERATED_BODY()
public:
void Execute_Implementation(const FGameplayEffectCustomExecutionParameters& Params,
FGameplayEffectCustomExecutionOutput& OutExecutionOutput) const override;
};
void UEC_Damage::Execute_Implementation(...)
{
// 取来源与目标属性
const UMyAttributeSet* Src = Params.GetSourceAttributeSet();
const UMyAttributeSet* Dst = Params.GetTargetAttributeSet();
float Damage = Src->GetAttack() * SkillMultiplier - Dst->GetDefense() * (1 - Src->GetArmorPen());
FGameplayModifierEvaluatedData EvalData(UMyAttributeSet::GetHealthAttribute(), EModOp::Add, -Damage);
OutExecutionOutput.AddOutput(EvalData);
}
什么时候用 EC:完整伤害公式(暴击、抗性、穿甲、最终减伤)、一次结算多个属性、需要 TargetData 参与的结算。
MMC vs EC 选型
| MMC | Execution Calculation | |
|---|---|---|
| 粒度 | 单个 Modifier | 整个 GE |
| 缓存 | 有(缓存计算结果) | 无 |
| 改多属性 | 否(只返回一个值) | 是 |
| TargetData | 可读 | 可读 |
| 典型 | 派生数值 | 完整伤害公式 |
一个工程化建议:伤害公式做成数据驱动的"字段配置"
公式再复杂,也建议把倍率、抗性系数、穿甲系数做成 GE 的曲线或 Set-By-Caller 参数:
Spec.Data->SetSetByCallerMagnitude(FGameplayTag::RequestGameplayTag("Data.SkillMultiplier"), 1.5f);
这样"技能倍率"由技能代码传进来,"抗性系数"由 GE 配置——策划能调的部分仍然在资产里。
本章小结
- MMC:单 Modifier 派生计算(轻量、有缓存)。
- EC:整 GE 自定义执行(多属性修改、完整公式)。
- 公式的可配部分用 Set-By-Caller 参数传入,保持"策划可调"。
