常见坑:负血、属性上限与 Clamp

GE 走通后,四个数值边界问题几乎必然出现。

坑一:血量变成负数

Instant GE 扣 100 血,角色只有 30 血 → CurrentValue = -70。GAS 不会自动 clamp。

解法:在 AttributeSet 的 PostGameplayEffectExecute 里守门:

void UMyAttributeSet::PostGameplayEffectExecute(const FGameplayEffectModCallbackData& Data)
{
    Super::PostGameplayEffectExecute(Data);
    if (Data.EvaluatedData.Attribute == GetHealthAttribute())
        SetHealth(FMath::Clamp(GetHealth(), 0.f, GetMaxHealth()));
}

为什么用 PostGameplayEffectExecute 而不是 PreAttributeChange:Pre 在"修改前"被调用(可取消),Post 在修改完成后——clamp 放 Post 最直接,且能广播 UI。

官方推荐:PreAttributeChange 用于"在修改前 clamp 输入值"(如回血不超上限),PostGameplayEffectExecute 用于"clamp 结果并做副作用"(如死亡判定、UI 通知)。

坑二:上限改变了但当前值没跟上

MaxHealth 从 100 → 150(升级),Health 还是 100。

解法:升级 GE 的 Modifier 配 Attribute Based:当 MaxHealth 变化时,Health 也加差值(配一个 Derived Attribute,或在 Post 同步处理)。常见做法是升级时同时应用一个"回满血" GE,UX 上也合理。

坑三:Buff/Debuff 与装备属性混在一起

装备给的 +30 攻击是 Infinite GE,中毒的 -20 是 Duration GE,驱散时会不会一起被清掉?

解法:靠标签严格区分来源: - 装备 GE:Effect.Source.Gear; - Buff/Debuff:Effect.Buff / Effect.Debuff; - 驱散只查 Effect.Debuff,装备属性毫发无损。

坑四:UE 属性变化的"消息顺序"

同一帧多个 GE 应用(范围伤害 10 个目标),变化通知的顺序不保证。UI 刷新逻辑不要依赖"先扣血死后扣"这种顺序,做最终状态刷新(订阅时同步一次当前值)。

一个排查工具

GE 体系"静默失败"时: 1. ability.showdebug ability → 看 Active Effects 页签,确认 GE 是否在、剩多久; 2. log GameplaySystem VeryVerbose → 看应用被拒绝的原因(Blocked Tags / 权限); 3. 检查 GE 的 Application Conditions 与标签需求。

本章小结

  • 数值 clamp 放 AttributeSet 的 Pre/Post 回调:Pre 管输入、Post 管结果与副作用。
  • 属性上限变化时用 Derived Attribute 或"补差/回满" GE 对齐当前值。
  • 装备/Buff/Debuff 靠标签分源,驱散按标签精确移除。