UE5多人MOBA+GAS 番外篇:同时造成多种类型伤害,以各种属性值的百分比来应用伤害(版本二)

发布于:2025-08-02 ⋅ 阅读:(19) ⋅ 点赞:(0)


前言

该版本是基于一版本(版本一没有删掉,因为也是我辛苦的结果有感情,在此之前还有个版本就给删了,最开始的ECC并不太理想),再次结合aura的实践方式来进行修改,但是我个人感觉不是很理想,来点路过的大佬教教

添加更多的Tag

添加如此之多的Tag主要是用来传递需要增加的额外攻击

	// 伤害类型
	// 物理伤害
	CRUNCH_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(DamageType_AttackDamage)
	// 魔法伤害
	CRUNCH_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(DamageType_MagicDamage)
	// 真实伤害
	CRUNCH_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(DamageType_TrueDamage)

	// 属性基础
	// 最大生命值
	CRUNCH_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(Attribute_MaxHealth)
	// 当前生命值
	CRUNCH_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(Attribute_Health)
	// 最大魔法值
	CRUNCH_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(Attribute_MaxMana)
	// 当前魔法值
	CRUNCH_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(Attribute_Mana)
	// 攻击力
	CRUNCH_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(Attribute_AttackPower)
	// 魔法强度
	CRUNCH_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(Attribute_MagicPower)
	// 物抗
	CRUNCH_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(Attribute_Armor)
	// 魔抗
	CRUNCH_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(Attribute_MagicResistance)
	// 移动速度
	CRUNCH_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(Attribute_MoveSpeed)
	// 伤害类型
	UE_DEFINE_GAMEPLAY_TAG_COMMENT(DamageType_AttackDamage, "DamageType.AttackDamage", "物理伤害")
	UE_DEFINE_GAMEPLAY_TAG_COMMENT(DamageType_MagicDamage, "DamageType.MagicDamage", "魔法伤害")
	UE_DEFINE_GAMEPLAY_TAG_COMMENT(DamageType_TrueDamage, "DamageType.TrueDamage", "真实伤害")
	UE_DEFINE_GAMEPLAY_TAG_COMMENT(Attribute_MaxHealth, "Attribute.MaxHealth", "最大生命值")
	UE_DEFINE_GAMEPLAY_TAG_COMMENT(Attribute_Health, "Attribute.Health", "生命值")
	UE_DEFINE_GAMEPLAY_TAG_COMMENT(Attribute_MaxMana, "Attribute.MaxMana", "最大法术值")
	UE_DEFINE_GAMEPLAY_TAG_COMMENT(Attribute_Mana, "Attribute.Mana", "法术值")
	UE_DEFINE_GAMEPLAY_TAG_COMMENT(Attribute_AttackPower, "Attribute.AttackPower", "攻击力")
	UE_DEFINE_GAMEPLAY_TAG_COMMENT(Attribute_MagicPower, "Attribute.MagicPower", "魔法强度")
	UE_DEFINE_GAMEPLAY_TAG_COMMENT(Attribute_Armor, "Attribute.Armor", "护甲")
	UE_DEFINE_GAMEPLAY_TAG_COMMENT(Attribute_MagicResistance, "Attribute.MagicResistance", "魔法抗性")
	UE_DEFINE_GAMEPLAY_TAG_COMMENT(Attribute_MoveSpeed, "Attribute.MoveSpeed", "移动速度")

进行全面采用GameplayTag

USTRUCT(BlueprintType)
struct FDamageDefinition
{
	GENERATED_BODY()
public:
	FDamageDefinition();
	// 基础伤害
	UPROPERTY(EditAnywhere)
	FScalableFloat BaseDamage;
	// 属性的百分比伤害加成
	UPROPERTY(EditAnywhere, meta = (Categories = "Attribute"))
	TMap<FGameplayTag, float> AttributeDamageModifiers;
};
// 伤害效果定义
USTRUCT(BlueprintType)
struct FGenericDamageEffectDef
{
	GENERATED_BODY()
public:
	FGenericDamageEffectDef();

	// 伤害类型
	UPROPERTY(EditAnywhere)
	TSubclassOf<UGameplayEffect> DamageEffect;
	
	// 伤害类型
	UPROPERTY(EditAnywhere, meta = (Categories = "DamageType"))
	TMap<FGameplayTag,FDamageDefinition> DamageTypeDefinitions;

	// 力的大小
	UPROPERTY(EditAnywhere)
	FVector PushVelocity;
};
FDamageDefinition::FDamageDefinition()
	: BaseDamage{0.f}
{
}

FGenericDamageEffectDef::FGenericDamageEffectDef()
	:DamageEffect{nullptr},
	PushVelocity{0.f}
{
}

应用伤害处也需要进行调整

因为多种伤害的缘故,每个的值又是独立的,再不拆解ECC的情况下,进行多次应用

void UCGameplayAbility::ApplyDamage(AActor* TargetActor,const FGenericDamageEffectDef& Damage, int Level)
{
	const UAbilitySystemComponent* ASC = GetAbilitySystemComponentFromActorInfo();
	AActor* AvatarActor				   = GetAvatarActorFromActorInfo();
	// 创建效果上下文, 设置能力 、源对象 和 施加者
	FGameplayEffectContextHandle ContextHandle = ASC->MakeEffectContext();
	ContextHandle.SetAbility(this);
	ContextHandle.AddSourceObject(AvatarActor);
	ContextHandle.AddInstigator(AvatarActor, AvatarActor);

	// 传属性,应用伤害
	for (const auto& TypePair : Damage.DamageTypeDefinitions)
	{
		// 创建效果Spec句柄,指定效果类、能力等级和上下文
		FGameplayEffectSpecHandle EffectSpecHandle = ASC->MakeOutgoingSpec(Damage.DamageEffect, Level, ContextHandle);
		float TotalModifier = TypePair.Value.BaseDamage.GetValueAtLevel(Level);
		for (const auto& Modifier : TypePair.Value.AttributeDamageModifiers)
		{
			UAbilitySystemBlueprintLibrary::AssignTagSetByCallerMagnitude(EffectSpecHandle, Modifier.Key, Modifier.Value);
		}
		UAbilitySystemBlueprintLibrary::AssignTagSetByCallerMagnitude(EffectSpecHandle, TypePair.Key, TotalModifier);
		// 在目标上应用游戏效果规范
		ApplyGameplayEffectSpecToTarget(GetCurrentAbilitySpecHandle(),
										GetCurrentActorInfo(),
										GetCurrentActivationInfo(),
										EffectSpecHandle,
										UAbilitySystemBlueprintLibrary::AbilityTargetDataFromActor(TargetActor));
	}
}

最后ECC的修改

在ECC下,将获取的值创建了两个结构体,一个是受击方,一个是攻击方,属性的加成可能会有自己的物抗和魔抗来增加伤害,因此创建了两个结构体来操作

// 幻雨喜欢小猫咪


#include "GAS/Executions/ECC_AttackDamage.h"

#include "GAS/Core/CAttributeSet.h"
#include "GAS/Core/CHeroAttributeSet.h"
struct FSourceDamageStatics
{
	// 最大生命值
	DECLARE_ATTRIBUTE_CAPTUREDEF(MaxHealth);
	// 当前生命值
	DECLARE_ATTRIBUTE_CAPTUREDEF(Health);
	// 最大魔法值
	DECLARE_ATTRIBUTE_CAPTUREDEF(MaxMana);
	// 当前魔法值
	DECLARE_ATTRIBUTE_CAPTUREDEF(Mana);
	// 攻击力
	DECLARE_ATTRIBUTE_CAPTUREDEF(AttackPower);
	// 魔法强度
	DECLARE_ATTRIBUTE_CAPTUREDEF(MagicPower);
	// 自己护甲
	DECLARE_ATTRIBUTE_CAPTUREDEF(Armor);
	// 自己魔抗
	DECLARE_ATTRIBUTE_CAPTUREDEF(MagicResistance);
	// 移动速度
	DECLARE_ATTRIBUTE_CAPTUREDEF(MoveSpeed);

	// 护甲穿透
	DECLARE_ATTRIBUTE_CAPTUREDEF(ArmorPenetration);
	// 护甲穿透百分比
	DECLARE_ATTRIBUTE_CAPTUREDEF(ArmorPenetrationPercent);

	// 法术穿透
	DECLARE_ATTRIBUTE_CAPTUREDEF(MagicPenetration);
	// 法术穿透百分比
	DECLARE_ATTRIBUTE_CAPTUREDEF(MagicPenetrationPercent);
	
	// 伤害加深
	DECLARE_ATTRIBUTE_CAPTUREDEF(DamageAmplification);

	FSourceDamageStatics()
	{
		// 参数:1.属性集 2.属性名 3.目标还是自身 4.是否设置快照(true为创建时获取,false为应用时获取)
		DEFINE_ATTRIBUTE_CAPTUREDEF(UCAttributeSet, MaxHealth, Source, false);
		DEFINE_ATTRIBUTE_CAPTUREDEF(UCAttributeSet, Health, Source, false);
		DEFINE_ATTRIBUTE_CAPTUREDEF(UCAttributeSet, MaxMana, Source, false);
		DEFINE_ATTRIBUTE_CAPTUREDEF(UCAttributeSet, Mana, Source, false);
		DEFINE_ATTRIBUTE_CAPTUREDEF(UCAttributeSet, AttackPower, Source, false);
		DEFINE_ATTRIBUTE_CAPTUREDEF(UCAttributeSet, MagicPower, Source, false);
		DEFINE_ATTRIBUTE_CAPTUREDEF(UCAttributeSet, Armor, Source, false);
		DEFINE_ATTRIBUTE_CAPTUREDEF(UCAttributeSet, MagicResistance, Source, false);
		DEFINE_ATTRIBUTE_CAPTUREDEF(UCAttributeSet, MoveSpeed, Source, false);
		
		DEFINE_ATTRIBUTE_CAPTUREDEF(UCHeroAttributeSet, ArmorPenetration, Source, false);
		DEFINE_ATTRIBUTE_CAPTUREDEF(UCHeroAttributeSet, ArmorPenetrationPercent, Source, false);
		DEFINE_ATTRIBUTE_CAPTUREDEF(UCHeroAttributeSet, MagicPenetration, Source, false);
		DEFINE_ATTRIBUTE_CAPTUREDEF(UCHeroAttributeSet, MagicPenetrationPercent, Source, false);

		DEFINE_ATTRIBUTE_CAPTUREDEF(UCHeroAttributeSet, DamageAmplification, Source, false);
	}
};

// 静态数据访问函数(单例模式)
static FSourceDamageStatics& SourceDamageStatics()
{
	static FSourceDamageStatics Statics;
	return Statics;
}
struct FTargetDamageStatics
{
	// 敌方的物理防御
	DECLARE_ATTRIBUTE_CAPTUREDEF(Armor);
	// 敌方的法术抗性
	DECLARE_ATTRIBUTE_CAPTUREDEF(MagicResistance);
	// 伤害减免
	DECLARE_ATTRIBUTE_CAPTUREDEF(DamageReduction);

	FTargetDamageStatics()
	{
	 	// 参数:1.属性集 2.属性名 3.目标还是自身 4.是否设置快照(true为创建时获取,false为应用时获取)
		DEFINE_ATTRIBUTE_CAPTUREDEF(UCAttributeSet, Armor, Target, false);
		DEFINE_ATTRIBUTE_CAPTUREDEF(UCAttributeSet, MagicResistance, Target, false);
		DEFINE_ATTRIBUTE_CAPTUREDEF(UCHeroAttributeSet, DamageReduction, Target, false);
	 }
};


// 静态数据访问函数(单例模式)
static FTargetDamageStatics& TargetDamageStatics()
{
	static FTargetDamageStatics Statics;
	return Statics;
}

UECC_AttackDamage::UECC_AttackDamage()
{
	// 将属性添加到捕获列表中
	// 添加源
	RelevantAttributesToCapture.Add(SourceDamageStatics().MaxHealthDef);
	RelevantAttributesToCapture.Add(SourceDamageStatics().HealthDef);
	RelevantAttributesToCapture.Add(SourceDamageStatics().MaxManaDef);
	RelevantAttributesToCapture.Add(SourceDamageStatics().ManaDef);
	RelevantAttributesToCapture.Add(SourceDamageStatics().AttackPowerDef);
	RelevantAttributesToCapture.Add(SourceDamageStatics().MagicPowerDef);
	
	RelevantAttributesToCapture.Add(SourceDamageStatics().ArmorDef);
	RelevantAttributesToCapture.Add(SourceDamageStatics().MagicResistanceDef);
	RelevantAttributesToCapture.Add(SourceDamageStatics().MoveSpeedDef);
	RelevantAttributesToCapture.Add(SourceDamageStatics().ArmorPenetrationDef);
	RelevantAttributesToCapture.Add(SourceDamageStatics().ArmorPenetrationPercentDef);
	RelevantAttributesToCapture.Add(SourceDamageStatics().MagicPenetrationDef);
	RelevantAttributesToCapture.Add(SourceDamageStatics().MagicPenetrationPercentDef);
	RelevantAttributesToCapture.Add(SourceDamageStatics().DamageAmplificationDef);

	// 添加目标
	RelevantAttributesToCapture.Add(TargetDamageStatics().ArmorDef);
	RelevantAttributesToCapture.Add(TargetDamageStatics().MagicResistanceDef);
	RelevantAttributesToCapture.Add(TargetDamageStatics().DamageReductionDef);
}

void UECC_AttackDamage::Execute_Implementation(const FGameplayEffectCustomExecutionParameters& ExecutionParams,
	FGameplayEffectCustomExecutionOutput& OutExecutionOutput) const
{
	//存储标签和属性快照对应的Map
	TMap<FGameplayTag, FGameplayEffectAttributeCaptureDefinition> TagsToCaptureDefs;
	// TODO:添加新的需要修改的属性值,添加新的标签和值
	//添加标签和属性快照对应的数据
	TagsToCaptureDefs.Add(TGameplayTags::Attribute_MaxHealth, SourceDamageStatics().MaxHealthDef);
	TagsToCaptureDefs.Add(TGameplayTags::Attribute_Health, SourceDamageStatics().HealthDef);
	TagsToCaptureDefs.Add(TGameplayTags::Attribute_MaxMana, SourceDamageStatics().MaxManaDef);
	TagsToCaptureDefs.Add(TGameplayTags::Attribute_Mana, SourceDamageStatics().ManaDef);
	TagsToCaptureDefs.Add(TGameplayTags::Attribute_AttackPower, SourceDamageStatics().AttackPowerDef);
	TagsToCaptureDefs.Add(TGameplayTags::Attribute_MagicPower, SourceDamageStatics().MagicPowerDef);
	TagsToCaptureDefs.Add(TGameplayTags::Attribute_Armor, SourceDamageStatics().ArmorDef);
	TagsToCaptureDefs.Add(TGameplayTags::Attribute_MagicResistance, SourceDamageStatics().MagicResistanceDef);
	TagsToCaptureDefs.Add(TGameplayTags::Attribute_MoveSpeed, SourceDamageStatics().MoveSpeedDef);
	
	// 获取游戏效果规范和上下文
	const FGameplayEffectSpec& Spec = ExecutionParams.GetOwningSpec();
	FGameplayEffectContextHandle EffectContextHandle = Spec.GetContext();

	// 获取来源和目标标签
	const FGameplayTagContainer* SourceTags = Spec.CapturedSourceTags.GetAggregatedTags();
	const FGameplayTagContainer* TargetTags = Spec.CapturedTargetTags.GetAggregatedTags();

	// 初始化评估参数
	FAggregatorEvaluateParameters EvaluateParameters;
	EvaluateParameters.SourceTags = SourceTags;
	EvaluateParameters.TargetTags = TargetTags;

	float DamageAdd = 0.0f;
	for (auto& TagToCaptureDef : TagsToCaptureDefs)
	{
		const float Coefficient = Spec.GetSetByCallerMagnitude(TagToCaptureDef.Key, false, -1);
		if (Coefficient <= 0.0f) continue;
		float AttributeValue = 0.0f;
		ExecutionParams.AttemptCalculateCapturedAttributeMagnitude(TagToCaptureDef.Value, EvaluateParameters, AttributeValue);
		DamageAdd += AttributeValue * Coefficient / 100.0f;
	}
	
	// 获取伤害加深
	float DamageAmp = 0.0f;
	ExecutionParams.AttemptCalculateCapturedAttributeMagnitude(SourceDamageStatics().DamageAmplificationDef, EvaluateParameters, DamageAmp);
	// 获取敌方的伤害减免
	float DamageReduction = 0.0f;
	ExecutionParams.AttemptCalculateCapturedAttributeMagnitude(TargetDamageStatics().DamageReductionDef, EvaluateParameters, DamageReduction);

	// 获取基础攻击伤害
	float BaseAttackDamage = Spec.GetSetByCallerMagnitude(TGameplayTags::DamageType_AttackDamage, false, -1);
	// 物理伤害的处理
	if (BaseAttackDamage > 0.0f)
	{
		BaseAttackDamage += DamageAdd;
		// 获取护甲穿透百分比
		float ArmorPenetrationPercent = 0.0f;
		ExecutionParams.AttemptCalculateCapturedAttributeMagnitude(SourceDamageStatics().ArmorPenetrationPercentDef, EvaluateParameters, ArmorPenetrationPercent);
		// 获取护甲穿透
		float ArmorPenetration = 0.0f;
		ExecutionParams.AttemptCalculateCapturedAttributeMagnitude(SourceDamageStatics().ArmorPenetrationDef, EvaluateParameters, ArmorPenetration);
		// 获取目标护甲
		float TargetArmor = 0.0f;
		ExecutionParams.AttemptCalculateCapturedAttributeMagnitude(TargetDamageStatics().ArmorDef, EvaluateParameters, TargetArmor);
		// 1. 处理固定护甲穿透
		TargetArmor = FMath::Max(0.0f, TargetArmor - ArmorPenetration);
		// 2. 处理百分比护甲穿透
		TargetArmor = FMath::Max(0.0f, TargetArmor * (1.0f - FMath::Min(ArmorPenetrationPercent, 100.0f) / 100.0f));
		// 3. 计算护甲减免(计算出来的是免伤率)
		float ArmorReduction = TargetArmor / (TargetArmor + 100.0f);
		BaseAttackDamage *= (1.0f - FMath::Min(ArmorReduction / 100.0f + DamageReduction/100.0f, 1.0f));
		// 4. 应用伤害加深(百分比提升)
		BaseAttackDamage *= (1.0f + DamageAmp / 100.0f);
		// 5. 输出到AttackDamage属性
		if (BaseAttackDamage > 0.0f)
		{
			// 添加输出修饰符
			OutExecutionOutput.AddOutputModifier(
				FGameplayModifierEvaluatedData(
				UCAttributeSet::GetAttackDamageAttribute(), //获取到伤害属性
				EGameplayModOp::Override, 
				BaseAttackDamage	//伤害
				));
		}
	}

	// 计算基础法术伤害值
	float BaseMagicDamage = Spec.GetSetByCallerMagnitude(TGameplayTags::DamageType_MagicDamage, false, -1.f);
	if (BaseMagicDamage > 0)
	{
		BaseMagicDamage += DamageAdd;
		// 获取法术穿透百分比
		float MagicPenetrationPercent = 0.0f;
		ExecutionParams.AttemptCalculateCapturedAttributeMagnitude(
			SourceDamageStatics().MagicPenetrationPercentDef,
			EvaluateParameters, MagicPenetrationPercent);
		// 获取法术穿透
		float MagicPenetration = 0.0f;
		ExecutionParams.AttemptCalculateCapturedAttributeMagnitude(
			SourceDamageStatics().MagicPenetrationDef,
			EvaluateParameters, MagicPenetration);
		// 获取目标法抗
		float TargetMagicResistance = 0.0f;
		ExecutionParams.AttemptCalculateCapturedAttributeMagnitude(
			TargetDamageStatics().MagicResistanceDef, EvaluateParameters, TargetMagicResistance);
		// 1. 处理固定法术穿透
		TargetMagicResistance = FMath::Max(0.0f, TargetMagicResistance - MagicPenetration);
		// 2. 处理百分比法术穿透
		TargetMagicResistance = FMath::Max(0.0f, TargetMagicResistance * (1.0f - FMath::Min(MagicPenetrationPercent, 100.0f) / 100.0f));
		// 3. 计算法抗减免(计算出来的是免伤率)
		float MagicResistanceReduction = TargetMagicResistance / (TargetMagicResistance + 100.0f);
		BaseMagicDamage *= (1.0f - FMath::Min(MagicResistanceReduction / 100.0f + DamageReduction/100.0f, 1.0f));
		// 4. 应用伤害加深(百分比提升)
		BaseMagicDamage *= (1.0f + DamageAmp / 100.0f);
		OutExecutionOutput.AddOutputModifier(
			FGameplayModifierEvaluatedData(
			UCAttributeSet::GetMagicDamageAttribute(), //获取到伤害属性
			EGameplayModOp::Override, 
			BaseMagicDamage	//伤害
			));
	}
	
	// 计算基础真实伤害值
	float BaseTrueDamage = Spec.GetSetByCallerMagnitude(TGameplayTags::DamageType_TrueDamage, false, -1.f);
	if (BaseTrueDamage > 0.0f)
	{
		BaseTrueDamage += DamageAdd;
		// 计算伤害减免
		BaseTrueDamage *= (1.0f - FMath::Min(DamageReduction/100.0f, 1.0f));
		// 应用伤害加深(百分比提升)
		BaseTrueDamage *= (1.0f + DamageAmp / 100.0f);
		
		OutExecutionOutput.AddOutputModifier(
			FGameplayModifierEvaluatedData(
			UCAttributeSet::GetTrueDamageAttribute(), //获取到伤害属性
			EGameplayModOp::Override, 
			BaseTrueDamage	//伤害
			));
	}
}

伤害的获取方面依然是在属性中获取

void UCAttributeSet::PostGameplayEffectExecute(const FGameplayEffectModCallbackData& Data)
{
	FEffectProperties Props;
	SetEffectProperties(Data, Props);
	if (Data.EvaluatedData.Attribute == GetHealthAttribute())
	{
		SetHealth(FMath::Clamp(GetHealth(), 0, GetMaxHealth()));
		SetCachedHealthPercent(GetHealth()/GetMaxHealth());
	}
	if (Data.EvaluatedData.Attribute == GetManaAttribute())
	{
		SetMana(FMath::Clamp(GetMana(), 0, GetMaxMana()));
		SetCachedManaPercent(GetMana()/GetMaxMana());
	}
	
	// 物理伤害
	if (Data.EvaluatedData.Attribute == GetAttackDamageAttribute())
	{
		float NewDamage = GetAttackDamage();
		SetAttackDamage(0.f);
		if (NewDamage > 0.f)
		{
			UE_LOG(LogTemp, Warning, TEXT("物理: %f"), NewDamage)
			Damage(Props, TGameplayTags::DamageType_AttackDamage, NewDamage);
		}
	}
	
	// 魔法伤害
	if (Data.EvaluatedData.Attribute == GetMagicDamageAttribute())
	{
		float NewDamage = GetMagicDamage();
		SetMagicDamage(0.f);
		if (NewDamage > 0.f)
		{
			UE_LOG(LogTemp, Warning, TEXT("魔法伤害: %f"), NewDamage)
			Damage(Props,TGameplayTags::DamageType_MagicDamage, NewDamage);
		}
	}
	
	// 真实伤害
	if (Data.EvaluatedData.Attribute == GetTrueDamageAttribute())
	{
		float NewDamage = GetTrueDamage();
		SetTrueDamage(0.f);
		if (NewDamage > 0.f)
		{
			UE_LOG(LogTemp, Warning, TEXT("真实伤害: %f"), NewDamage)
			Damage(Props,TGameplayTags::DamageType_TrueDamage, NewDamage);
		}
	}
}

在这里插入图片描述
在这里插入图片描述
创建一个GE放入ECC
在这里插入图片描述
回顾一下这个是ECC,伤害的计算都在这里Execute_Implementation

#pragma once

#include "CoreMinimal.h"
#include "GameplayEffectExecutionCalculation.h"
#include "ECC_AttackDamage.generated.h"

/**
 * 
 */
UCLASS()
class UECC_AttackDamage : public UGameplayEffectExecutionCalculation
{
	GENERATED_BODY()
public:
	UECC_AttackDamage();
	
	virtual void Execute_Implementation(const FGameplayEffectCustomExecutionParameters& ExecutionParams, FGameplayEffectCustomExecutionOutput& OutExecutionOutput) const override;
};

如果有更好的方案,请允许让我copy一下嘻嘻嘻