news 2026/6/15 15:52:36

49. UE5 GAS RPG 利用Execution Calculations实现动态伤害公式与暴击机制

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
49. UE5 GAS RPG 利用Execution Calculations实现动态伤害公式与暴击机制

1. Execution Calculations基础概念

在UE5的Gameplay Ability System(GAS)中,Execution Calculations(执行计算)是一个强大的工具,它允许开发者在Gameplay Effect执行期间进行复杂的自定义计算。想象一下你正在设计一个RPG游戏的战斗系统,每次攻击造成的伤害不仅取决于攻击力,还要考虑目标的防御、暴击概率、护甲穿透等多项因素 - 这正是Execution Calculations大显身手的地方。

与ModifierMagnitudeCalculation(MMC)不同,Execution Calculations可以同时修改多个属性。比如在一次攻击中,你不仅可以计算伤害值,还能同时触发暴击效果、减少目标护甲值、施加debuff状态等。这种灵活性让复杂的战斗公式变得容易实现。

我在实际项目中发现,Execution Calculations特别适合处理以下场景:

  • 需要同时考虑攻击方和防御方多个属性的伤害计算
  • 带有随机判定的战斗机制(如暴击、格挡)
  • 需要动态调整计算系数的成长系统
  • 涉及多个属性联动的特殊效果

2. 创建基础伤害计算类

2.1 类结构与属性捕获

让我们从创建一个基础的伤害计算类开始。首先在C++中新建一个继承自UGameplayEffectExecutionCalculation的类:

// ExecCalc_Damage.h #pragma once #include "CoreMinimal.h" #include "GameplayEffectExecutionCalculation.h" #include "ExecCalc_Damage.generated.h" UCLASS() class YOURPROJECT_API UExecCalc_Damage : public UGameplayEffectExecutionCalculation { GENERATED_BODY() public: UExecCalc_Damage(); virtual void Execute_Implementation(const FGameplayEffectCustomExecutionParameters& ExecutionParams, FGameplayEffectCustomExecutionOutput& OutExecutionOutput) const override; };

属性捕获是Execution Calculations的核心机制。我们可以定义一个内部结构体来管理需要捕获的属性:

// 内部结构体,不需要外部访问 struct FDamageStatics { DECLARE_ATTRIBUTE_CAPTUREDEF(Armor); // 护甲属性 DECLARE_ATTRIBUTE_CAPTUREDEF(AttackPower); // 攻击力 FDamageStatics() { // 捕获目标护甲属性 DEFINE_ATTRIBUTE_CAPTUREDEF(UYourAttributeSet, Armor, Target, false); // 捕获攻击方攻击力属性 DEFINE_ATTRIBUTE_CAPTUREDEF(UYourAttributeSet, AttackPower, Source, false); } }; static const FDamageStatics& DamageStatics() { static FDamageStatics DStatics; return DStatics; }

2.2 执行函数实现

Execute_Implementation是实际计算发生的地方。下面是一个基础实现框架:

void UExecCalc_Damage::Execute_Implementation( const FGameplayEffectCustomExecutionParameters& ExecutionParams, FGameplayEffectCustomExecutionOutput& OutExecutionOutput) const { // 获取源和目标ASC const UAbilitySystemComponent* SourceASC = ExecutionParams.GetSourceAbilitySystemComponent(); const UAbilitySystemComponent* TargetASC = ExecutionParams.GetTargetAbilitySystemComponent(); // 获取角色实例 AActor* SourceActor = SourceASC ? SourceASC->GetAvatarActor() : nullptr; AActor* TargetActor = TargetASC ? TargetASC->GetAvatarActor() : nullptr; // 获取GameplayEffectSpec const FGameplayEffectSpec& Spec = ExecutionParams.GetOwningSpec(); // 设置评估参数 FAggregatorEvaluateParameters EvaluationParameters; EvaluationParameters.SourceTags = Spec.CapturedSourceTags.GetAggregatedTags(); EvaluationParameters.TargetTags = Spec.CapturedTargetTags.GetAggregatedTags(); // 获取基础伤害值(通过SetByCaller传入) float Damage = Spec.GetSetByCallerMagnitude(FGameplayTag::RequestGameplayTag(FName("Data.Damage"))); // 获取护甲和攻击力属性 float TargetArmor = 0.f; ExecutionParams.AttemptCalculateCapturedAttributeMagnitude(DamageStatics().ArmorDef, EvaluationParameters, TargetArmor); TargetArmor = FMath::Max(0.f, TargetArmor); float SourceAttackPower = 0.f; ExecutionParams.AttemptCalculateCapturedAttributeMagnitude(DamageStatics().AttackPowerDef, EvaluationParameters, SourceAttackPower); SourceAttackPower = FMath::Max(0.f, SourceAttackPower); // 基础伤害计算 Damage += SourceAttackPower * 0.5f; // 攻击力贡献 Damage *= (100.f - TargetArmor * 0.3f) / 100.f; // 护甲减伤 // 输出计算结果 const FGameplayModifierEvaluatedData EvaluatedData(UYourAttributeSet::GetIncomingDamageAttribute(), EGameplayModOp::Additive, Damage); OutExecutionOutput.AddOutputModifier(EvaluatedData); }

3. 实现暴击与格挡机制

3.1 暴击系统实现

暴击是RPG游戏的核心机制之一。我们需要在结构体中添加暴击相关属性:

struct FDamageStatics { // ...已有属性... DECLARE_ATTRIBUTE_CAPTUREDEF(CritChance); // 暴击率 DECLARE_ATTRIBUTE_CAPTUREDEF(CritDamage); // 暴击伤害 DECLARE_ATTRIBUTE_CAPTUREDEF(CritResist); // 暴击抵抗 FDamageStatics() { // ...已有捕获... DEFINE_ATTRIBUTE_CAPTUREDEF(UYourAttributeSet, CritChance, Source, false); DEFINE_ATTRIBUTE_CAPTUREDEF(UYourAttributeSet, CritDamage, Source, false); DEFINE_ATTRIBUTE_CAPTUREDEF(UYourAttributeSet, CritResist, Target, false); } };

然后在Execute_Implementation中添加暴击计算逻辑:

// 获取暴击相关属性 float CritChance = 0.f, CritDamage = 0.f, CritResist = 0.f; ExecutionParams.AttemptCalculateCapturedAttributeMagnitude(DamageStatics().CritChanceDef, EvaluationParameters, CritChance); ExecutionParams.AttemptCalculateCapturedAttributeMagnitude(DamageStatics().CritDamageDef, EvaluationParameters, CritDamage); ExecutionParams.AttemptCalculateCapturedAttributeMagnitude(DamageStatics().CritResistDef, EvaluationParameters, CritResist); // 计算实际暴击率 float EffectiveCritChance = FMath::Clamp(CritChance - CritResist * 0.5f, 0.f, 100.f); bool bCriticalHit = FMath::RandRange(1, 100) <= EffectiveCritChance; // 应用暴击伤害 if(bCriticalHit) { float CritMultiplier = 2.0f + CritDamage / 100.f; // 基础2倍+额外暴击伤害 Damage *= CritMultiplier; // 可以在这里触发暴击特效或音效 // ... }

3.2 格挡机制实现

格挡是另一个常见的防御机制。添加格挡相关属性:

struct FDamageStatics { // ...已有属性... DECLARE_ATTRIBUTE_CAPTUREDEF(BlockChance); // 格挡率 DECLARE_ATTRIBUTE_CAPTUREDEF(BlockEffectiveness); // 格挡效果 FDamageStatics() { // ...已有捕获... DEFINE_ATTRIBUTE_CAPTUREDEF(UYourAttributeSet, BlockChance, Target, false); DEFINE_ATTRIBUTE_CAPTUREDEF(UYourAttributeSet, BlockEffectiveness, Target, false); } };

格挡计算逻辑:

// 获取格挡属性 float BlockChance = 0.f, BlockEffectiveness = 0.f; ExecutionParams.AttemptCalculateCapturedAttributeMagnitude(DamageStatics().BlockChanceDef, EvaluationParameters, BlockChance); ExecutionParams.AttemptCalculateCapturedAttributeMagnitude(DamageStatics().BlockEffectivenessDef, EvaluationParameters, BlockEffectiveness); // 判断是否触发格挡 bool bBlocked = FMath::RandRange(1, 100) <= BlockChance; if(bBlocked) { // 格挡效果通常在50%-100%之间 float BlockPercent = 0.5f + BlockEffectiveness * 0.005f; Damage *= (1.f - FMath::Clamp(BlockPercent, 0.f, 1.f)); // 触发格挡特效或音效 // ... }

4. 高级伤害公式与动态系数

4.1 护甲穿透系统

护甲穿透让攻击者能够部分忽略目标的护甲值。添加相关属性:

struct FDamageStatics { // ...已有属性... DECLARE_ATTRIBUTE_CAPTUREDEF(ArmorPenetration); // 护甲穿透 FDamageStatics() { // ...已有捕获... DEFINE_ATTRIBUTE_CAPTUREDEF(UYourAttributeSet, ArmorPenetration, Source, false); } };

护甲穿透计算逻辑:

// 获取护甲穿透 float ArmorPenetration = 0.f; ExecutionParams.AttemptCalculateCapturedAttributeMagnitude(DamageStatics().ArmorPenetrationDef, EvaluationParameters, ArmorPenetration); ArmorPenetration = FMath::Max(0.f, ArmorPenetration); // 计算实际护甲值 float EffectiveArmor = TargetArmor * (100.f - ArmorPenetration) / 100.f; EffectiveArmor = FMath::Max(0.f, EffectiveArmor); // 使用EffectiveArmor代替原始护甲值计算减伤 Damage *= (100.f - EffectiveArmor * 0.3f) / 100.f;

4.2 使用曲线表动态调整系数

为了让游戏数值随等级平衡,我们可以使用曲线表动态调整各种系数:

// 获取角色等级 IYourLevelInterface* SourceLevelInterface = Cast<IYourLevelInterface>(SourceActor); IYourLevelInterface* TargetLevelInterface = Cast<IYourLevelInterface>(TargetActor); int32 SourceLevel = SourceLevelInterface ? SourceLevelInterface->GetCharacterLevel() : 1; int32 TargetLevel = TargetLevelInterface ? TargetLevelInterface->GetCharacterLevel() : 1; // 从曲线表获取动态系数 UDataTable* CoefficientTable = // 获取你的系数表; static const FString ContextString(TEXT("Damage Coefficient Context")); FArmorPenetrationCoefficient* PenetrationCoeff = CoefficientTable->FindRow<FArmorPenetrationCoefficient>(FName(*FString::FromInt(SourceLevel)), ContextString); FArmorCoefficient* ArmorCoeff = CoefficientTable->FindRow<FArmorCoefficient>(FName(*FString::FromInt(TargetLevel)), ContextString); // 应用动态系数 float EffectiveArmor = TargetArmor * (100.f - ArmorPenetration * PenetrationCoeff->Value) / 100.f; Damage *= (100.f - EffectiveArmor * ArmorCoeff->Value) / 100.f;

5. 实战技巧与优化建议

5.1 性能优化

Execution Calculations在服务器上运行,因此性能很重要:

  1. 最小化属性捕获:只捕获真正需要的属性,减少内存访问
  2. 避免复杂计算:将复杂计算预先计算并存储在曲线表中
  3. 使用静态函数:像DamageStatics()这样的辅助函数只初始化一次
  4. 减少动态分配:避免在Execute函数中创建临时对象

5.2 调试技巧

调试伤害计算可能会很棘手,我常用的方法包括:

// 添加调试输出 if(GEngine) { GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Green, FString::Printf(TEXT("Damage: %.1f, Crit: %s, Block: %s"), Damage, bCriticalHit ? TEXT("Yes") : TEXT("No"), bBlocked ? TEXT("Yes") : TEXT("No"))); } // 使用UE_LOG UE_LOG(LogTemp, Log, TEXT("Final Damage: %.2f (Base: %.2f, ArmorReduction: %.2f%%)"), Damage, BaseDamage, EffectiveArmor * 0.3f);

5.3 扩展思路

Execution Calculations非常灵活,你还可以实现:

  1. 元素抗性系统:根据不同伤害类型应用不同抗性
  2. 连击加成:基于连续命中次数增加伤害
  3. 背刺/弱点攻击:基于攻击角度增加伤害
  4. 环境加成:考虑地形、天气等因素

我在一个项目中曾实现过基于时间段的伤害加成系统 - 夜晚增加暗影伤害,白天增加光系伤害,只需要在计算时获取游戏世界时间即可。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/15 12:22:53

【Docker 27量子计算适配白皮书】:27项关键兼容性验证、3大量子SDK实测数据与生产环境部署 checklist

第一章&#xff1a;Docker 27量子计算适配白皮书概览Docker 27 是首个原生支持量子计算工作负载容器化部署的运行时版本&#xff0c;通过深度集成 Qiskit Runtime、Cirq SDK 及 OpenQASM 3.0 编译器链&#xff0c;在容器层实现了量子电路编译、模拟器调度与真实量子设备桥接能力…

作者头像 李华
网站建设 2026/6/15 15:32:39

DataSyncPro:企业数据孤岛整合的智能桥梁

DataSyncPro&#xff1a;企业数据孤岛整合的智能桥梁 【免费下载链接】PythonWin7 Python 3.9 installers that support Windows 7 SP1 and Windows Server 2008 R2 项目地址: https://gitcode.com/gh_mirrors/py/PythonWin7 让数据管理者告别信息碎片化的5大策略 您是…

作者头像 李华
网站建设 2026/6/10 12:24:13

如何高效解析通达信数据?Mootdx实用指南让金融数据分析提速80%

如何高效解析通达信数据&#xff1f;Mootdx实用指南让金融数据分析提速80% 【免费下载链接】mootdx 通达信数据读取的一个简便使用封装 项目地址: https://gitcode.com/GitHub_Trending/mo/mootdx Mootdx是一款专为通达信数据解析设计的Python工具包&#xff0c;能直接读…

作者头像 李华
网站建设 2026/5/25 22:20:01

云盘优化工具:提升123云盘使用体验的3个实用技巧

云盘优化工具&#xff1a;提升123云盘使用体验的3个实用技巧 【免费下载链接】123pan_unlock 基于油猴的123云盘解锁脚本&#xff0c;支持解锁123云盘下载功能 项目地址: https://gitcode.com/gh_mirrors/12/123pan_unlock 在数字化时代&#xff0c;云盘已成为存储和管理…

作者头像 李华
网站建设 2026/6/15 15:33:42

老旧Mac重生:使用OpenCore Legacy Patcher实现macOS升级

老旧Mac重生&#xff1a;使用OpenCore Legacy Patcher实现macOS升级 【免费下载链接】OpenCore-Legacy-Patcher 体验与之前一样的macOS 项目地址: https://gitcode.com/GitHub_Trending/op/OpenCore-Legacy-Patcher 拥有一台老旧Mac&#xff0c;却想体验最新macOS系统的…

作者头像 李华
网站建设 2026/6/5 14:17:33

老旧Mac系统升级与性能优化指南:让你的旧Mac重获新生

老旧Mac系统升级与性能优化指南&#xff1a;让你的旧Mac重获新生 【免费下载链接】OpenCore-Legacy-Patcher 体验与之前一样的macOS 项目地址: https://gitcode.com/GitHub_Trending/op/OpenCore-Legacy-Patcher 拥有一台老旧Mac却渴望体验最新macOS功能&#xff1f;别让…

作者头像 李华