UE5多人MOBA+GAS 番外篇:使用ECC(UGameplayEffectExecutionCalculation)制作伤害计算的流程
本文介绍了在Unreal Engine中使用Gameplay Ability System (GAS)实现伤害计算系统的过程。主要包含以下内容: 定义了伤害计算所需的各种属性,包括基础伤害、攻击力、护甲穿透、伤害加深等攻击方属性,以及护甲、伤害减免等防御方属性。 创建了自定义的GameplayEffectExecutionCalculation类UECC_AttackDamage,用于执行伤害计算
文章目录
定义一些属性用于作为伤害基础还有获取要打出去的伤害
伤害的传递位置和接收位置
创建一个ECC(里面执行伤害的计算)
伤害的计算
// 幻雨喜欢小猫咪
#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;
};
在DEFINE_ATTRIBUTE_CAPTUREDEF
中第三个输入确定这个属性是来自与施法者还是目标挨打者
DEFINE_ATTRIBUTE_CAPTUREDEF(UCAttributeSet, BaseDamage, Source, false);
最后要在这里输出伤害
OutExecutionOutput.AddOutputModifier(
FGameplayModifierEvaluatedData(
UCAttributeSet::GetAttackDamageAttribute(), //获取到伤害属性
EGameplayModOp::Additive, //加法
BaseDamage //伤害
));
用到的属性都走struct FDamageStatics
的流程另外在构造函数的时候也要走RelevantAttributesToCapture.Add(DamageStatics().BaseDamageDef);
的流程。
// 幻雨喜欢小猫咪
#include "GAS/Executions/ECC_AttackDamage.h"
#include "GAS/Core/CAttributeSet.h"
#include "GAS/Core/CHeroAttributeSet.h"
struct FDamageStatics
{
// FGameplayEffectAttributeCaptureDefinition
// 基础伤害
DECLARE_ATTRIBUTE_CAPTUREDEF(BaseDamage);
// 攻击百分比
DECLARE_ATTRIBUTE_CAPTUREDEF(AttackPowerCoefficient);
// 物理攻击
DECLARE_ATTRIBUTE_CAPTUREDEF(AttackPower);
// 护甲穿透
DECLARE_ATTRIBUTE_CAPTUREDEF(ArmorPenetration);
// 护甲穿透百分比
DECLARE_ATTRIBUTE_CAPTUREDEF(ArmorPenetrationPercent);
// 伤害加深
DECLARE_ATTRIBUTE_CAPTUREDEF(DamageAmplification);
// 敌方的防御
DECLARE_ATTRIBUTE_CAPTUREDEF(Armor);
// 伤害减免
DECLARE_ATTRIBUTE_CAPTUREDEF(DamageReduction);
FDamageStatics()
{
// 参数:1.属性集 2.属性名 3.目标还是自身 4.是否设置快照(true为创建时获取,false为应用时获取)
DEFINE_ATTRIBUTE_CAPTUREDEF(UCAttributeSet, BaseDamage, Source, false);
DEFINE_ATTRIBUTE_CAPTUREDEF(UCAttributeSet, AttackPowerCoefficient, Source, false);
DEFINE_ATTRIBUTE_CAPTUREDEF(UCAttributeSet, AttackPower, Source, false);
DEFINE_ATTRIBUTE_CAPTUREDEF(UCHeroAttributeSet, ArmorPenetration, Source, false);
DEFINE_ATTRIBUTE_CAPTUREDEF(UCHeroAttributeSet, ArmorPenetrationPercent, Source, false);
DEFINE_ATTRIBUTE_CAPTUREDEF(UCHeroAttributeSet, DamageAmplification, Source, false);
DEFINE_ATTRIBUTE_CAPTUREDEF(UCAttributeSet, Armor, Target, false);
DEFINE_ATTRIBUTE_CAPTUREDEF(UCHeroAttributeSet, DamageReduction, Target, false);
}
};
// 静态数据访问函数(单例模式)
static FDamageStatics& DamageStatics()
{
static FDamageStatics Statics;
return Statics;
}
UECC_AttackDamage::UECC_AttackDamage()
{
// 将属性添加到捕获列表中
RelevantAttributesToCapture.Add(DamageStatics().BaseDamageDef);
RelevantAttributesToCapture.Add(DamageStatics().AttackPowerDef);
RelevantAttributesToCapture.Add(DamageStatics().AttackPowerCoefficientDef);
RelevantAttributesToCapture.Add(DamageStatics().ArmorPenetrationDef);
RelevantAttributesToCapture.Add(DamageStatics().ArmorPenetrationPercentDef);
RelevantAttributesToCapture.Add(DamageStatics().DamageAmplificationDef);
RelevantAttributesToCapture.Add(DamageStatics().ArmorDef);
RelevantAttributesToCapture.Add(DamageStatics().DamageReductionDef);
}
void UECC_AttackDamage::Execute_Implementation(const FGameplayEffectCustomExecutionParameters& ExecutionParams,
FGameplayEffectCustomExecutionOutput& OutExecutionOutput) const
{
// 获取游戏效果规范和上下文
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 BaseDamage = 0.0f;
ExecutionParams.AttemptCalculateCapturedAttributeMagnitude(
DamageStatics().BaseDamageDef,
EvaluateParameters,
BaseDamage
);
// 获取攻击力
float AttackPower = 0.0f;
ExecutionParams.AttemptCalculateCapturedAttributeMagnitude(DamageStatics().AttackPowerDef, EvaluateParameters, AttackPower);
// 获取护甲穿透百分比
float ArmorPenetrationPercent = 0.0f;
ExecutionParams.AttemptCalculateCapturedAttributeMagnitude(DamageStatics().ArmorPenetrationPercentDef, EvaluateParameters, ArmorPenetrationPercent);
// 获取护甲穿透
float ArmorPenetration = 0.0f;
ExecutionParams.AttemptCalculateCapturedAttributeMagnitude(DamageStatics().ArmorPenetrationDef, EvaluateParameters, ArmorPenetration);
// 获取目标护甲
float TargetArmor = 0.0f;
ExecutionParams.AttemptCalculateCapturedAttributeMagnitude(DamageStatics().ArmorDef, EvaluateParameters, TargetArmor);
// 获取伤害加深
float DamageAmp = 0.0f;
ExecutionParams.AttemptCalculateCapturedAttributeMagnitude(DamageStatics().DamageAmplificationDef, EvaluateParameters, DamageAmp);
// 获取敌方的伤害减免
float DamageReduction = 0.0f;
ExecutionParams.AttemptCalculateCapturedAttributeMagnitude(DamageStatics().DamageReductionDef, EvaluateParameters, DamageReduction);
// 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);
BaseDamage *= (1.0f - FMath::Min(ArmorReduction / 100.0f + DamageReduction/100.0f, 1.0f));
// 4. 应用伤害加深(百分比提升)
BaseDamage *= (1.0f + DamageAmp / 100.0f);
// 5. 输出到AttackDamage属性
if (BaseDamage > 0.0f)
{
// 添加输出修饰符
OutExecutionOutput.AddOutputModifier(
FGameplayModifierEvaluatedData(
UCAttributeSet::GetAttackDamageAttribute(), //获取到伤害属性
EGameplayModOp::Additive, //加法
BaseDamage //伤害
));
}
}
创建一个伤害GE,该GE只需要在执行里添加一个计算类就能调用了
在执行ECC的GE之前需要修改ECC需要调用的值,也可以不改直接计算
重新构建伤害效果结构体
// 伤害效果定义
USTRUCT(BlueprintType)
struct FGenericDamageEffectDef
{
GENERATED_BODY()
public:
FGenericDamageEffectDef();
// 伤害类型
UPROPERTY(EditAnywhere)
TSubclassOf<UGameplayEffect> DamageEffect;
// 基础伤害大小
UPROPERTY(EditAnywhere)
float BaseDamage;
// 属性的百分比伤害加成
UPROPERTY(EditAnywhere)
TMap<FGameplayTag, float> DamageTypes;
// 力的大小
UPROPERTY(EditAnywhere)
FVector PushVelocity;
};
伤害的应用,可以创建一个ApplyDamage。
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);
float NewDamage = Damage.BaseDamage;
// 通过属性的值来修改伤害值
for(auto& Pair : Damage.DamageTypes)
{
bool bFound ;
float AttributeValue = GetAbilitySystemComponentFromActorInfo()->GetGameplayAttributeValue(Pair.Key, bFound);
if (bFound)
{
NewDamage += AttributeValue * Pair.Value / 100.f;
}
}
// 修改一下基础伤害的值,供ECC调用
GetAbilitySystemComponentFromActorInfo()->SetNumericAttributeBase(UCAttributeSet::GetBaseDamageAttribute(), NewDamage);
// 创建效果Spec句柄,指定效果类、能力等级和上下文
FGameplayEffectSpecHandle EffectSpecHandle = ASC->MakeOutgoingSpec(Damage.DamageEffect, Level, ContextHandle);
// 在目标上应用游戏效果规范
ApplyGameplayEffectSpecToTarget(GetCurrentAbilitySpecHandle(),
GetCurrentActorInfo(),
GetCurrentActivationInfo(),
EffectSpecHandle,
UAbilitySystemBlueprintLibrary::AbilityTargetDataFromActor(TargetActor));
}
也可以创建一个Make函数,只修改一下伤害(至于Level为啥没用,我还在思考这个数值用怎么样的形式好)
void UCGameplayAbility::MakeDamage(const FGenericDamageEffectDef& Damage, int Level)
{
float NewDamage = Damage.BaseDamage;
//通过标签设置GE使用的配置
for(auto& Pair : Damage.DamageTypes)
{
bool bFound ;
float AttributeValue = GetAbilitySystemComponentFromActorInfo()->GetGameplayAttributeValue(Pair.Key, bFound);
if (bFound)
{
NewDamage += AttributeValue * Pair.Value / 100.f;
}
}
GetAbilitySystemComponentFromActorInfo()->SetNumericAttributeBase(UCAttributeSet::GetBaseDamageAttribute(), NewDamage);
}
使用轰炸的时候作为列子,依然保持调用这个蓝图的伤害赋值,只需要调用一下Make函数对基础伤害赋值一下就好了
void UGA_GroundBlast::TargetConfirmed(const FGameplayAbilityTargetDataHandle& TargetDataHandle)
{
if (!K2_CommitAbility())
{
K2_EndAbility();
return;
}
// 仅在服务器上执行伤害和击退
if (K2_HasAuthority())
{
MakeDamage(DamageEffectDef,GetAbilityLevel(CurrentSpecHandle, CurrentActorInfo));
// 对目标应用伤害效果
BP_ApplyGameplayEffectToTarget(TargetDataHandle, DamageEffectDef.DamageEffect, GetAbilityLevel(CurrentSpecHandle, CurrentActorInfo));
// 对目标施加推力
PushTargets(TargetDataHandle, DamageEffectDef.PushVelocity);
}
FGameplayCueParameters BlastingGameplayCueParameters;
// 设置特效的位置
BlastingGameplayCueParameters.Location = UAbilitySystemBlueprintLibrary::GetHitResultFromTargetData(TargetDataHandle, 1).ImpactPoint;
// 设置特效的大小
BlastingGameplayCueParameters.RawMagnitude = TargetAreaRadius;
// 播放冲击特效和摄像机震动
GetAbilitySystemComponentFromActorInfo()->ExecuteGameplayCue(BlastGameplayCueTag, BlastingGameplayCueParameters);
GetAbilitySystemComponentFromActorInfo()->ExecuteGameplayCue(UCAbilitySystemStatics::GetCameraShakeGameplayCueTag(), BlastingGameplayCueParameters);
// 播放释放动画
UAnimInstance* OwnerAnimInst = GetOwnerAnimInstance();
if (OwnerAnimInst)
{
OwnerAnimInst->Montage_Play(CastMontage);
}
UE_LOG(LogTemp, Warning, TEXT("技能发射"));
K2_EndAbility();
}
如果不调用这个蓝图的赋值Ge的函数的话,可以根据Combo的伤害赋值的方式,换一个赋值伤害的函数
void UGA_GroundBlast::TargetConfirmed(const FGameplayAbilityTargetDataHandle& TargetDataHandle)
{
if (!K2_CommitAbility())
{
K2_EndAbility();
return;
}
// 仅在服务器上执行伤害和击退
if (K2_HasAuthority())
{
// 对目标应用伤害效果
// BP_ApplyGameplayEffectToTarget(TargetDataHandle, DamageEffectDef.DamageEffect, GetAbilityLevel(CurrentSpecHandle, CurrentActorInfo));
// 获取命中目标的数量
TArray<AActor*> HitActors = UAbilitySystemBlueprintLibrary::GetAllActorsFromTargetData(TargetDataHandle);
for (int32 i = 0; i < HitActors.Num(); ++i)
{
AActor* HitActor = HitActors[i];
// 检查 HitResult 是否有效
if (HitActor)
{
UE_LOG(LogTemp, Warning, TEXT("命中Actor: %s"), *HitActor->GetName());
ApplyDamage(HitActor, DamageEffectDef, GetAbilityLevel(CurrentSpecHandle, CurrentActorInfo));
}
}
// ApplyDamage
// 对目标施加推力
PushTargets(TargetDataHandle, DamageEffectDef.PushVelocity);
}
FGameplayCueParameters BlastingGameplayCueParameters;
// 设置特效的位置
BlastingGameplayCueParameters.Location = UAbilitySystemBlueprintLibrary::GetHitResultFromTargetData(TargetDataHandle, 1).ImpactPoint;
// 设置特效的大小
BlastingGameplayCueParameters.RawMagnitude = TargetAreaRadius;
// 播放冲击特效和摄像机震动
GetAbilitySystemComponentFromActorInfo()->ExecuteGameplayCue(BlastGameplayCueTag, BlastingGameplayCueParameters);
GetAbilitySystemComponentFromActorInfo()->ExecuteGameplayCue(UCAbilitySystemStatics::GetCameraShakeGameplayCueTag(), BlastingGameplayCueParameters);
// 播放释放动画
UAnimInstance* OwnerAnimInst = GetOwnerAnimInstance();
if (OwnerAnimInst)
{
OwnerAnimInst->Montage_Play(CastMontage);
}
UE_LOG(LogTemp, Warning, TEXT("技能发射"));
K2_EndAbility();
}
在属性中监听ECC输出的那个值然后处理扣血
伤害的接收在属性的PostGameplayEffectExecute
函数里监听ECC最后输出的属性,然后扣血。(至于为什么我的暴击放在这里这么麻烦的计算呢,我想直接在这里计算出暴击然后调个GC,应该可以吧我还没写呢)
void UCAttributeSet::PostGameplayEffectExecute(const FGameplayEffectModCallbackData& Data)
{
// 伤害
if (Data.EvaluatedData.Attribute == GetAttackDamageAttribute())
{
float NewDamage = GetAttackDamage();
SetAttackDamage(0.f);
if (NewDamage > 0.f)
{
UAbilitySystemComponent* SourceASC = Data.EffectSpec.GetContext().GetOriginalInstigatorAbilitySystemComponent();
if (SourceASC)
{
bool bFound = false;
const float EffectiveCriticalHitChance = SourceASC->GetGameplayAttributeValue(UCHeroAttributeSet::GetCriticalStrikeChanceAttribute(), bFound);
if (bFound)
{
bFound = false;
if (const bool bCriticalHit = FMath::RandRange(1, 100) < EffectiveCriticalHitChance)
{
const float CriticalStrikeDamage = SourceASC->GetGameplayAttributeValue(UCHeroAttributeSet::GetCriticalStrikeDamageAttribute(), bFound);
if (bFound)
{
NewDamage *= (1.f + CriticalStrikeDamage / 100.f);
UE_LOG(LogTemp, Warning, TEXT("暴击"))
}
}
}
}
const float NewHealth = GetHealth() - NewDamage;
SetHealth(FMath::Clamp(NewHealth, 0.f, GetMaxHealth()));
UE_LOG(LogTemp, Warning, TEXT("NewDamage: %f"), NewDamage)
// Source是输出者,Target是挨打的
// UE_LOG(LogTemp, Warning, TEXT("SourceASCName: %s"), *Data.EffectSpec.GetContext().GetOriginalInstigatorAbilitySystemComponent()->GetName())
// UE_LOG(LogTemp, Warning, TEXT("TargetASCName: %s"), *UAbilitySystemBlueprintLibrary::GetAbilitySystemComponent(Data.Target.AbilityActorInfo->AvatarActor.Get())->GetName())
// UE_LOG(LogTemp, Warning, TEXT("SourceName: %s"), *Data.EffectSpec.GetContext().GetOriginalInstigatorAbilitySystemComponent()->AbilityActorInfo->AvatarActor.Get()->GetName())
// UE_LOG(LogTemp, Warning, TEXT("TargetName: %s"), *Data.Target.AbilityActorInfo->AvatarActor.Get()->GetName())
}
}
}
创建一个测试用的GE看看能不能行
打了几炮确实可行
在对小兵测试一下,确实是根据施法者的
我的属性值写的有点乱的说
// 幻雨喜欢小猫咪
#pragma once
#include "CoreMinimal.h"
#include "AbilitySystemComponent.h"
#include "AttributeSet.h"
#include "CAttributeSet.generated.h"
//宏的设置,编译时会默认给变量生成相应的Getter以及Setter函数,当前设置会生成四个函数,获取属性,获取值,设置值,以及初始化值。
#define ATTRIBUTE_ACCESSORS(ClassName, PropertyName) \
GAMEPLAYATTRIBUTE_PROPERTY_GETTER(ClassName, PropertyName) \
GAMEPLAYATTRIBUTE_VALUE_GETTER(PropertyName) \
GAMEPLAYATTRIBUTE_VALUE_SETTER(PropertyName) \
GAMEPLAYATTRIBUTE_VALUE_INITTER(PropertyName)
/**
*
*/
UCLASS()
class UCAttributeSet : public UAttributeSet
{
GENERATED_BODY()
public:
// 用于声明哪些属性需要在网络中进行复制
virtual void GetLifetimeReplicatedProps( TArray< class FLifetimeProperty > & OutLifetimeProps ) const override;
// 当Attribute的CurrentValue被改变之前调用
virtual void PreAttributeChange(const FGameplayAttribute& Attribute, float& NewValue) override;
// 仅在instant Gameplay Effect使Attribute的BaseValue改变时触发
virtual void PostGameplayEffectExecute(const FGameplayEffectModCallbackData & Data) override;
//virtual bool PreGameplayEffectExecute(FGameplayEffectModCallbackData& Data) override;
UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_Health)
FGameplayAttributeData Health;
ATTRIBUTE_ACCESSORS(UCAttributeSet, Health)
UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_MaxHealth)
FGameplayAttributeData MaxHealth;
ATTRIBUTE_ACCESSORS(UCAttributeSet, MaxHealth)
UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_Mana)
FGameplayAttributeData Mana;
ATTRIBUTE_ACCESSORS(UCAttributeSet, Mana)
UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_MaxMana)
FGameplayAttributeData MaxMana;
ATTRIBUTE_ACCESSORS(UCAttributeSet, MaxMana)
// 传值的基础伤害
UPROPERTY(ReplicatedUsing = OnRep_BaseDamage)
FGameplayAttributeData BaseDamage;
ATTRIBUTE_ACCESSORS(UCAttributeSet, BaseDamage)
// 攻击力系数
UPROPERTY(ReplicatedUsing = OnRep_AttackPowerCoefficient)
FGameplayAttributeData AttackPowerCoefficient;
ATTRIBUTE_ACCESSORS(UCAttributeSet, AttackPowerCoefficient)
// 物理伤害
UPROPERTY(ReplicatedUsing = OnRep_AttackDamage)
FGameplayAttributeData AttackDamage;
ATTRIBUTE_ACCESSORS(UCAttributeSet, AttackDamage)
// 法术伤害
UPROPERTY(ReplicatedUsing = OnRep_MagicDamage)
FGameplayAttributeData MagicDamage;
ATTRIBUTE_ACCESSORS(UCAttributeSet, MagicDamage)
// 真实伤害
UPROPERTY(ReplicatedUsing = OnRep_TrueDamage)
FGameplayAttributeData TrueDamage;
ATTRIBUTE_ACCESSORS(UCAttributeSet, TrueDamage)
/** 攻击力(物理攻击强度) */
UPROPERTY(ReplicatedUsing = OnRep_AttackPower)
FGameplayAttributeData AttackPower;
ATTRIBUTE_ACCESSORS(UCAttributeSet, AttackPower)
/** 法术强度(魔法攻击强度) */
UPROPERTY(ReplicatedUsing = OnRep_MagicPower)
FGameplayAttributeData MagicPower;
ATTRIBUTE_ACCESSORS(UCAttributeSet, MagicPower)
// 护甲值
UPROPERTY(ReplicatedUsing = OnRep_Armor)
FGameplayAttributeData Armor;
ATTRIBUTE_ACCESSORS(UCAttributeSet, Armor)
/** 法术抗性(减少受到的魔法伤害) */
UPROPERTY(ReplicatedUsing = OnRep_MagicResistance)
FGameplayAttributeData MagicResistance;
ATTRIBUTE_ACCESSORS(UCAttributeSet, MagicResistance)
// 移动速度
UPROPERTY(ReplicatedUsing = OnRep_MoveSpeed)
FGameplayAttributeData MoveSpeed;
ATTRIBUTE_ACCESSORS(UCAttributeSet, MoveSpeed)
// 移动加速度
UPROPERTY(ReplicatedUsing = OnRep_MoveAcceleration)
FGameplayAttributeData MoveAcceleration;
ATTRIBUTE_ACCESSORS(UCAttributeSet, MoveAcceleration)
UFUNCTION()
void OnRep_Health(const FGameplayAttributeData& OldHealth);
UFUNCTION()
void OnRep_MaxHealth(const FGameplayAttributeData& OldMaxHealth);
UFUNCTION()
void OnRep_Mana(const FGameplayAttributeData& OldMana);
UFUNCTION()
void OnRep_MaxMana(const FGameplayAttributeData& OldMaxMana);
UFUNCTION()
void OnRep_AttackDamage(const FGameplayAttributeData& OldAttackDamage);
UFUNCTION()
void OnRep_Armor(const FGameplayAttributeData& OldArmor);
UFUNCTION()
void OnRep_MoveSpeed(const FGameplayAttributeData& OldMoveSpeed);
UFUNCTION()
void OnRep_MoveAcceleration(const FGameplayAttributeData& OldMoveAcceleration);
UFUNCTION()
void OnRep_AttackPower(const FGameplayAttributeData& OldAttackPower);
UFUNCTION()
void OnRep_MagicPower(const FGameplayAttributeData& OldMagicPower);
UFUNCTION()
void OnRep_MagicResistance(const FGameplayAttributeData& OldMagicResistance);
UFUNCTION()
void OnRep_AttackPowerCoefficient(const FGameplayAttributeData& OldAttackPowerCoefficient);
UFUNCTION()
void OnRep_BaseDamage(const FGameplayAttributeData& OldBaseDamage);
UFUNCTION()
void OnRep_MagicDamage(const FGameplayAttributeData& OldMagicDamage);
UFUNCTION()
void OnRep_TrueDamage(const FGameplayAttributeData& OldTrueDamage);
};
// 幻雨喜欢小猫咪
#include "GAS/Core/CAttributeSet.h"
#include "GAS/Core/CHeroAttributeSet.h"
#include "AbilitySystemBlueprintLibrary.h"
#include "Net/UnrealNetwork.h"
#include "GameplayEffectExtension.h"
void UCAttributeSet::GetLifetimeReplicatedProps(TArray<class FLifetimeProperty>& OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
DOREPLIFETIME_CONDITION_NOTIFY(UCAttributeSet, Health, COND_None, REPNOTIFY_Always);
DOREPLIFETIME_CONDITION_NOTIFY(UCAttributeSet, MaxHealth, COND_None, REPNOTIFY_Always);
DOREPLIFETIME_CONDITION_NOTIFY(UCAttributeSet, Mana, COND_None, REPNOTIFY_Always);
DOREPLIFETIME_CONDITION_NOTIFY(UCAttributeSet, MaxMana, COND_None, REPNOTIFY_Always);
DOREPLIFETIME_CONDITION_NOTIFY(UCAttributeSet, BaseDamage, COND_None, REPNOTIFY_Always);
DOREPLIFETIME_CONDITION_NOTIFY(UCAttributeSet, AttackPowerCoefficient, COND_None, REPNOTIFY_Always);
DOREPLIFETIME_CONDITION_NOTIFY(UCAttributeSet, AttackDamage, COND_None, REPNOTIFY_Always);
DOREPLIFETIME_CONDITION_NOTIFY(UCAttributeSet, MagicDamage, COND_None, REPNOTIFY_Always);
DOREPLIFETIME_CONDITION_NOTIFY(UCAttributeSet, TrueDamage, COND_None, REPNOTIFY_Always);
DOREPLIFETIME_CONDITION_NOTIFY(UCAttributeSet, AttackPower, COND_None, REPNOTIFY_Always);
DOREPLIFETIME_CONDITION_NOTIFY(UCAttributeSet, MagicPower, COND_None, REPNOTIFY_Always);
DOREPLIFETIME_CONDITION_NOTIFY(UCAttributeSet, Armor, COND_None, REPNOTIFY_Always);
DOREPLIFETIME_CONDITION_NOTIFY(UCAttributeSet, MagicResistance, COND_None, REPNOTIFY_Always);
DOREPLIFETIME_CONDITION_NOTIFY(UCAttributeSet, MoveSpeed, COND_None, REPNOTIFY_Always);
DOREPLIFETIME_CONDITION_NOTIFY(UCAttributeSet, MoveAcceleration, COND_None, REPNOTIFY_Always);
}
void UCAttributeSet::PreAttributeChange(const FGameplayAttribute& Attribute, float& NewValue)
{
if (Attribute == GetHealthAttribute())
{
NewValue = FMath::Clamp(NewValue, 0.f, GetMaxHealth());
}
if (Attribute == GetManaAttribute())
{
NewValue = FMath::Clamp(NewValue, 0.f, GetMaxMana());
}
}
void UCAttributeSet::PostGameplayEffectExecute(const FGameplayEffectModCallbackData& Data)
{
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)
{
UAbilitySystemComponent* SourceASC = Data.EffectSpec.GetContext().GetOriginalInstigatorAbilitySystemComponent();
if (SourceASC)
{
bool bFound = false;
const float EffectiveCriticalHitChance = SourceASC->GetGameplayAttributeValue(UCHeroAttributeSet::GetCriticalStrikeChanceAttribute(), bFound);
if (bFound)
{
bFound = false;
if (const bool bCriticalHit = FMath::RandRange(1, 100) < EffectiveCriticalHitChance)
{
const float CriticalStrikeDamage = SourceASC->GetGameplayAttributeValue(UCHeroAttributeSet::GetCriticalStrikeDamageAttribute(), bFound);
if (bFound)
{
NewDamage *= (1.f + CriticalStrikeDamage / 100.f);
UE_LOG(LogTemp, Warning, TEXT("暴击"))
}
}
}
}
const float NewHealth = GetHealth() - NewDamage;
SetHealth(FMath::Clamp(NewHealth, 0.f, GetMaxHealth()));
UE_LOG(LogTemp, Warning, TEXT("NewDamage: %f"), NewDamage)
// Source是输出者,Target是挨打的
// UE_LOG(LogTemp, Warning, TEXT("SourceASCName: %s"), *Data.EffectSpec.GetContext().GetOriginalInstigatorAbilitySystemComponent()->GetName())
// UE_LOG(LogTemp, Warning, TEXT("TargetASCName: %s"), *UAbilitySystemBlueprintLibrary::GetAbilitySystemComponent(Data.Target.AbilityActorInfo->AvatarActor.Get())->GetName())
// UE_LOG(LogTemp, Warning, TEXT("SourceName: %s"), *Data.EffectSpec.GetContext().GetOriginalInstigatorAbilitySystemComponent()->AbilityActorInfo->AvatarActor.Get()->GetName())
// UE_LOG(LogTemp, Warning, TEXT("TargetName: %s"), *Data.Target.AbilityActorInfo->AvatarActor.Get()->GetName())
}
}
}
void UCAttributeSet::OnRep_Health(const FGameplayAttributeData& OldHealth)
{
GAMEPLAYATTRIBUTE_REPNOTIFY(UCAttributeSet, Health, OldHealth);
}
void UCAttributeSet::OnRep_MaxHealth(const FGameplayAttributeData& OldMaxHealth)
{
GAMEPLAYATTRIBUTE_REPNOTIFY(UCAttributeSet, MaxHealth, OldMaxHealth);
}
void UCAttributeSet::OnRep_Mana(const FGameplayAttributeData& OldMana)
{
GAMEPLAYATTRIBUTE_REPNOTIFY(UCAttributeSet, Mana, OldMana);
}
void UCAttributeSet::OnRep_MaxMana(const FGameplayAttributeData& OldMaxMana)
{
GAMEPLAYATTRIBUTE_REPNOTIFY(UCAttributeSet, MaxMana, OldMaxMana);
}
void UCAttributeSet::OnRep_AttackDamage(const FGameplayAttributeData& OldValue)
{
GAMEPLAYATTRIBUTE_REPNOTIFY(UCAttributeSet, AttackDamage, OldValue);
}
void UCAttributeSet::OnRep_Armor(const FGameplayAttributeData& OldValue)
{
GAMEPLAYATTRIBUTE_REPNOTIFY(UCAttributeSet, Armor, OldValue);
}
void UCAttributeSet::OnRep_MoveSpeed(const FGameplayAttributeData& OldValue)
{
GAMEPLAYATTRIBUTE_REPNOTIFY(UCAttributeSet, MoveSpeed, OldValue);
}
void UCAttributeSet::OnRep_MoveAcceleration(const FGameplayAttributeData& OldValue)
{
GAMEPLAYATTRIBUTE_REPNOTIFY(UCAttributeSet, MoveAcceleration, OldValue);
}
void UCAttributeSet::OnRep_AttackPower(const FGameplayAttributeData& OldValue)
{
GAMEPLAYATTRIBUTE_REPNOTIFY(UCAttributeSet, AttackPower, OldValue);
}
void UCAttributeSet::OnRep_MagicPower(const FGameplayAttributeData& OldValue)
{
GAMEPLAYATTRIBUTE_REPNOTIFY(UCAttributeSet, MagicPower, OldValue);
}
void UCAttributeSet::OnRep_MagicResistance(const FGameplayAttributeData& OldValue)
{
GAMEPLAYATTRIBUTE_REPNOTIFY(UCAttributeSet, MagicResistance, OldValue);
}
void UCAttributeSet::OnRep_AttackPowerCoefficient(const FGameplayAttributeData& OldAttackPowerCoefficient)
{
GAMEPLAYATTRIBUTE_REPNOTIFY(UCAttributeSet, AttackPowerCoefficient, OldAttackPowerCoefficient);
}
void UCAttributeSet::OnRep_BaseDamage(const FGameplayAttributeData& OldBaseDamage)
{
GAMEPLAYATTRIBUTE_REPNOTIFY(UCAttributeSet, BaseDamage, OldBaseDamage);
}
void UCAttributeSet::OnRep_MagicDamage(const FGameplayAttributeData& OldMagicDamage)
{
GAMEPLAYATTRIBUTE_REPNOTIFY(UCAttributeSet, MagicDamage, OldMagicDamage);
}
void UCAttributeSet::OnRep_TrueDamage(const FGameplayAttributeData& OldTrueDamage)
{
GAMEPLAYATTRIBUTE_REPNOTIFY(UCAttributeSet, TrueDamage, OldTrueDamage);
}
// 幻雨喜欢小猫咪
#pragma once
#include "CoreMinimal.h"
#include "AttributeSet.h"
#include "AbilitySystemComponent.h"
#include "CHeroAttributeSet.generated.h"
// 属性访问器宏,自动生成属性的Getter/Setter等
#define ATTRIBUTE_ACCESSORS(ClassName, PropertyName) \
GAMEPLAYATTRIBUTE_PROPERTY_GETTER(ClassName, PropertyName) \
GAMEPLAYATTRIBUTE_VALUE_GETTER(PropertyName) \
GAMEPLAYATTRIBUTE_VALUE_SETTER(PropertyName) \
GAMEPLAYATTRIBUTE_VALUE_INITTER(PropertyName)
/**
* 英雄属性集(UCHeroAttributeSet)
* 用于管理英雄的成长属性、经验、等级、升级点、金币等
* 支持属性同步、属性变化回调等功能
*/
UCLASS()
class UCHeroAttributeSet : public UAttributeSet
{
GENERATED_BODY()
public:
// 属性访问器声明(自动生成标准接口)
ATTRIBUTE_ACCESSORS(UCHeroAttributeSet, Intelligence) // 智力
ATTRIBUTE_ACCESSORS(UCHeroAttributeSet, Strength) // 力量
ATTRIBUTE_ACCESSORS(UCHeroAttributeSet, Experience) // 当前经验
ATTRIBUTE_ACCESSORS(UCHeroAttributeSet, PrevLevelExperience) // 上一级所需经验
ATTRIBUTE_ACCESSORS(UCHeroAttributeSet, NextLevelExperience) // 下一级所需经验
ATTRIBUTE_ACCESSORS(UCHeroAttributeSet, Level) // 当前等级
ATTRIBUTE_ACCESSORS(UCHeroAttributeSet, UpgradePoint) // 可用升级点
ATTRIBUTE_ACCESSORS(UCHeroAttributeSet, MaxLevel) // 最大等级
ATTRIBUTE_ACCESSORS(UCHeroAttributeSet, MaxLevelExperience) // 满级所需经验
ATTRIBUTE_ACCESSORS(UCHeroAttributeSet, Gold) // 金币
ATTRIBUTE_ACCESSORS(UCHeroAttributeSet, StrengthGrowthRate) // 力量成长率
ATTRIBUTE_ACCESSORS(UCHeroAttributeSet, IntelligenceGrowthRate) // 智力成长率
// 英雄的属性配置
ATTRIBUTE_ACCESSORS(UCHeroAttributeSet, AttackPowerGrowthRate) // 攻击力成长率(每等级增加的攻击力数值)
ATTRIBUTE_ACCESSORS(UCHeroAttributeSet, MagicPowerGrowthRate) // 法术强度成长率
ATTRIBUTE_ACCESSORS(UCHeroAttributeSet, HealthRegen) // 生命回复速率
ATTRIBUTE_ACCESSORS(UCHeroAttributeSet, HealthRegenGrowthRate) // 生命回复速率成长率
ATTRIBUTE_ACCESSORS(UCHeroAttributeSet, ManaRegen) // 法力回复速率
ATTRIBUTE_ACCESSORS(UCHeroAttributeSet, ManaRegenGrowthRate) // 法力回复速率成长率
ATTRIBUTE_ACCESSORS(UCHeroAttributeSet, ArmorPenetration) // 护甲穿透
ATTRIBUTE_ACCESSORS(UCHeroAttributeSet, MagicPenetration) // 法术穿透
ATTRIBUTE_ACCESSORS(UCHeroAttributeSet, ArmorPenetrationPercent)// 护甲穿透百分比
ATTRIBUTE_ACCESSORS(UCHeroAttributeSet, MagicPenetrationPercent)// 法术穿透百分比
ATTRIBUTE_ACCESSORS(UCHeroAttributeSet, LifeSteal) // 生命偷取
ATTRIBUTE_ACCESSORS(UCHeroAttributeSet, MagicLifeSteal) // 法术吸血
ATTRIBUTE_ACCESSORS(UCHeroAttributeSet, CooldownReduction) // 冷却缩减
ATTRIBUTE_ACCESSORS(UCHeroAttributeSet, CriticalStrikeChance) // 暴击率
ATTRIBUTE_ACCESSORS(UCHeroAttributeSet, CriticalStrikeDamage) // 暴击伤害
ATTRIBUTE_ACCESSORS(UCHeroAttributeSet, Toughness) // 韧性
ATTRIBUTE_ACCESSORS(UCHeroAttributeSet, DamageAmplification) // 伤害加深(增加对目标造成的伤害百分比)
ATTRIBUTE_ACCESSORS(UCHeroAttributeSet, DamageReduction) // 伤害减免(减少受到的伤害百分比)
// 属性同步(网络复制)配置
virtual void GetLifetimeReplicatedProps( TArray< class FLifetimeProperty > & OutLifetimeProps ) const override;
// private:
// 智力
UPROPERTY(ReplicatedUsing = OnRep_Intelligence)
FGameplayAttributeData Intelligence;
// 力量
UPROPERTY(ReplicatedUsing = OnRep_Strength)
FGameplayAttributeData Strength;
// 当前经验
UPROPERTY(ReplicatedUsing = OnRep_Experience)
FGameplayAttributeData Experience;
// 力量成长率
UPROPERTY()
FGameplayAttributeData StrengthGrowthRate;
// 智力成长率
UPROPERTY()
FGameplayAttributeData IntelligenceGrowthRate;
/** 攻击力成长率(每等级增加的攻击力数值) */
UPROPERTY()
FGameplayAttributeData AttackPowerGrowthRate;
/** 法术强度成长率(每等级增加的法术强度数值) */
UPROPERTY()
FGameplayAttributeData MagicPowerGrowthRate;
/** 生命回复速率(每秒回复的生命值) */
UPROPERTY(ReplicatedUsing = OnRep_HealthRegen)
FGameplayAttributeData HealthRegen;
/** 生命回复速率成长率(每等级增加的生命回复速率) */
UPROPERTY()
FGameplayAttributeData HealthRegenGrowthRate;
/** 法力回复速率(每秒回复的法力值) */
UPROPERTY(ReplicatedUsing = OnRep_ManaRegen)
FGameplayAttributeData ManaRegen;
/** 法力回复速率成长率(每等级增加的法力回复速率) */
UPROPERTY()
FGameplayAttributeData ManaRegenGrowthRate;
/** 护甲穿透(减少目标护甲的效果) */
UPROPERTY(ReplicatedUsing = OnRep_ArmorPenetration)
FGameplayAttributeData ArmorPenetration;
/** 法术穿透(减少目标法术抗性的效果) */
UPROPERTY(ReplicatedUsing = OnRep_MagicPenetration)
FGameplayAttributeData MagicPenetration;
/** 护甲穿透百分比(减少目标护甲的百分比效果) */
UPROPERTY(ReplicatedUsing = OnRep_ArmorPenetrationPercent)
FGameplayAttributeData ArmorPenetrationPercent;
/** 法术穿透百分比(减少目标法术抗性的百分比效果) */
UPROPERTY(ReplicatedUsing = OnRep_MagicPenetrationPercent)
FGameplayAttributeData MagicPenetrationPercent;
/** 生命偷取(造成物理伤害时回复生命值的百分比) */
UPROPERTY(ReplicatedUsing = OnRep_LifeSteal)
FGameplayAttributeData LifeSteal;
/** 法术吸血(造成法术伤害时回复生命值的百分比) */
UPROPERTY(ReplicatedUsing = OnRep_MagicLifesteal)
FGameplayAttributeData MagicLifeSteal;
/** 冷却缩减(减少技能冷却时间的百分比) */
UPROPERTY(ReplicatedUsing = OnRep_CooldownReduction)
FGameplayAttributeData CooldownReduction;
/** 暴击率(普通攻击暴击的几率) */
UPROPERTY(ReplicatedUsing = OnRep_CriticalStrikeChance)
FGameplayAttributeData CriticalStrikeChance;
// 暴击伤害
UPROPERTY(ReplicatedUsing = OnRep_CriticalStrikeDamage)
FGameplayAttributeData CriticalStrikeDamage;
/** 韧性(减少被控制效果影响的时间) */
UPROPERTY(ReplicatedUsing = OnRep_Toughness)
FGameplayAttributeData Toughness;
/** 伤害加深(增加对目标造成的伤害百分比) */
UPROPERTY(ReplicatedUsing = OnRep_DamageAmplification)
FGameplayAttributeData DamageAmplification;
/** 伤害减免(减少受到的伤害百分比) */
UPROPERTY(ReplicatedUsing = OnRep_DamageReduction)
FGameplayAttributeData DamageReduction;
// 上一级所需经验
UPROPERTY(ReplicatedUsing = OnRep_PrevLevelExperience)
FGameplayAttributeData PrevLevelExperience;
// 下一级所需经验
UPROPERTY(ReplicatedUsing = OnRep_NextLevelExperience)
FGameplayAttributeData NextLevelExperience;
// 当前等级
UPROPERTY(ReplicatedUsing = OnRep_Level)
FGameplayAttributeData Level;
// 可用升级点
UPROPERTY(ReplicatedUsing = OnRep_UpgradePoint)
FGameplayAttributeData UpgradePoint;
// 最大等级
UPROPERTY(ReplicatedUsing = OnRep_MaxLevel)
FGameplayAttributeData MaxLevel;
// 满级所需经验
UPROPERTY(ReplicatedUsing = OnRep_MaxLevelExperience)
FGameplayAttributeData MaxLevelExperience;
// 金币
UPROPERTY(ReplicatedUsing = OnRep_Gold)
FGameplayAttributeData Gold;
// 属性同步回调(用于客户端属性变化通知)
UFUNCTION()
void OnRep_Intelligence(const FGameplayAttributeData& OldValue);
UFUNCTION()
void OnRep_Strength(const FGameplayAttributeData& OldValue);
UFUNCTION()
void OnRep_Experience(const FGameplayAttributeData& OldValue);
UFUNCTION()
void OnRep_PrevLevelExperience(const FGameplayAttributeData& OldValue);
UFUNCTION()
void OnRep_NextLevelExperience(const FGameplayAttributeData& OldValue);
UFUNCTION()
void OnRep_Level(const FGameplayAttributeData& OldValue);
UFUNCTION()
void OnRep_UpgradePoint(const FGameplayAttributeData& OldValue);
UFUNCTION()
void OnRep_MaxLevel(const FGameplayAttributeData& OldValue);
UFUNCTION()
void OnRep_MaxLevelExperience(const FGameplayAttributeData& OldValue);
UFUNCTION()
void OnRep_Gold(const FGameplayAttributeData& OldValue);
UFUNCTION()
void OnRep_HealthRegen(const FGameplayAttributeData& OldValue);
UFUNCTION()
void OnRep_ManaRegen(const FGameplayAttributeData& OldValue);
UFUNCTION()
void OnRep_ArmorPenetration(const FGameplayAttributeData& OldValue);
UFUNCTION()
void OnRep_MagicPenetration(const FGameplayAttributeData& OldValue);
UFUNCTION()
void OnRep_ArmorPenetrationPercent(const FGameplayAttributeData& OldValue);
UFUNCTION()
void OnRep_MagicPenetrationPercent(const FGameplayAttributeData& OldValue);
UFUNCTION()
void OnRep_LifeSteal(const FGameplayAttributeData& OldValue);
UFUNCTION()
void OnRep_MagicLifeSteal(const FGameplayAttributeData& OldValue);
UFUNCTION()
void OnRep_CooldownReduction(const FGameplayAttributeData& OldValue);
UFUNCTION()
void OnRep_CriticalStrikeChance(const FGameplayAttributeData& OldValue);
UFUNCTION()
void OnRep_CriticalStrikeDamage(const FGameplayAttributeData& OldValue);
UFUNCTION()
void OnRep_Toughness(const FGameplayAttributeData& OldValue);
UFUNCTION()
void OnRep_DamageAmplification(const FGameplayAttributeData& OldValue);
UFUNCTION()
void OnRep_DamageReduction(const FGameplayAttributeData& OldValue);
};
// 幻雨喜欢小猫咪
#include "GAS/Core/CHeroAttributeSet.h"
#include "Net/UnrealNetwork.h"
#include "GameplayEffectExtension.h"
void UCHeroAttributeSet::GetLifetimeReplicatedProps(TArray<class FLifetimeProperty>& OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
DOREPLIFETIME_CONDITION_NOTIFY(UCHeroAttributeSet, Intelligence, COND_None, REPNOTIFY_Always);
DOREPLIFETIME_CONDITION_NOTIFY(UCHeroAttributeSet, Strength, COND_None, REPNOTIFY_Always);
DOREPLIFETIME_CONDITION_NOTIFY(UCHeroAttributeSet, Experience, COND_None, REPNOTIFY_Always);
DOREPLIFETIME_CONDITION_NOTIFY(UCHeroAttributeSet, PrevLevelExperience, COND_None, REPNOTIFY_Always);
DOREPLIFETIME_CONDITION_NOTIFY(UCHeroAttributeSet, NextLevelExperience, COND_None, REPNOTIFY_Always);
DOREPLIFETIME_CONDITION_NOTIFY(UCHeroAttributeSet, Level, COND_None, REPNOTIFY_Always);
DOREPLIFETIME_CONDITION_NOTIFY(UCHeroAttributeSet, UpgradePoint, COND_None, REPNOTIFY_Always);
DOREPLIFETIME_CONDITION_NOTIFY(UCHeroAttributeSet, MaxLevel, COND_None, REPNOTIFY_Always);
DOREPLIFETIME_CONDITION_NOTIFY(UCHeroAttributeSet, MaxLevelExperience, COND_None, REPNOTIFY_Always);
DOREPLIFETIME_CONDITION_NOTIFY(UCHeroAttributeSet, Gold, COND_None, REPNOTIFY_Always);
// DOREPLIFETIME_CONDITION_NOTIFY(UCHeroAttributeSet, AttackPowerGrowthRate, COND_None, REPNOTIFY_Always)
// DOREPLIFETIME_CONDITION_NOTIFY(UCHeroAttributeSet, MagicPowerGrowthRate, COND_None, REPNOTIFY_Always)
DOREPLIFETIME_CONDITION_NOTIFY(UCHeroAttributeSet, HealthRegen, COND_None, REPNOTIFY_Always)
DOREPLIFETIME_CONDITION_NOTIFY(UCHeroAttributeSet, ManaRegen, COND_None, REPNOTIFY_Always)
DOREPLIFETIME_CONDITION_NOTIFY(UCHeroAttributeSet, ArmorPenetration, COND_None, REPNOTIFY_Always)
DOREPLIFETIME_CONDITION_NOTIFY(UCHeroAttributeSet, MagicPenetration, COND_None, REPNOTIFY_Always)
DOREPLIFETIME_CONDITION_NOTIFY(UCHeroAttributeSet, ArmorPenetrationPercent, COND_None, REPNOTIFY_Always)
DOREPLIFETIME_CONDITION_NOTIFY(UCHeroAttributeSet, MagicPenetrationPercent, COND_None, REPNOTIFY_Always)
DOREPLIFETIME_CONDITION_NOTIFY(UCHeroAttributeSet, LifeSteal, COND_None, REPNOTIFY_Always)
DOREPLIFETIME_CONDITION_NOTIFY(UCHeroAttributeSet, MagicLifeSteal, COND_None, REPNOTIFY_Always)
DOREPLIFETIME_CONDITION_NOTIFY(UCHeroAttributeSet, CooldownReduction, COND_None, REPNOTIFY_Always)
DOREPLIFETIME_CONDITION_NOTIFY(UCHeroAttributeSet, CriticalStrikeChance, COND_None, REPNOTIFY_Always)
DOREPLIFETIME_CONDITION_NOTIFY(UCHeroAttributeSet, CriticalStrikeDamage, COND_None, REPNOTIFY_Always)
DOREPLIFETIME_CONDITION_NOTIFY(UCHeroAttributeSet, Toughness, COND_None, REPNOTIFY_Always)
DOREPLIFETIME_CONDITION_NOTIFY(UCHeroAttributeSet, DamageAmplification, COND_None, REPNOTIFY_Always)
DOREPLIFETIME_CONDITION_NOTIFY(UCHeroAttributeSet, DamageReduction, COND_None, REPNOTIFY_Always)
}
void UCHeroAttributeSet::OnRep_Intelligence(const FGameplayAttributeData& OldValue)
{
GAMEPLAYATTRIBUTE_REPNOTIFY(UCHeroAttributeSet, Intelligence, OldValue);
}
void UCHeroAttributeSet::OnRep_Strength(const FGameplayAttributeData& OldValue)
{
GAMEPLAYATTRIBUTE_REPNOTIFY(UCHeroAttributeSet, Strength, OldValue);
}
void UCHeroAttributeSet::OnRep_Experience(const FGameplayAttributeData& OldValue)
{
GAMEPLAYATTRIBUTE_REPNOTIFY(UCHeroAttributeSet, Experience, OldValue);
}
void UCHeroAttributeSet::OnRep_PrevLevelExperience(const FGameplayAttributeData& OldValue)
{
GAMEPLAYATTRIBUTE_REPNOTIFY(UCHeroAttributeSet, PrevLevelExperience, OldValue);
}
void UCHeroAttributeSet::OnRep_NextLevelExperience(const FGameplayAttributeData& OldValue)
{
GAMEPLAYATTRIBUTE_REPNOTIFY(UCHeroAttributeSet, NextLevelExperience, OldValue);
}
void UCHeroAttributeSet::OnRep_Level(const FGameplayAttributeData& OldValue)
{
GAMEPLAYATTRIBUTE_REPNOTIFY(UCHeroAttributeSet, Level, OldValue);
}
void UCHeroAttributeSet::OnRep_UpgradePoint(const FGameplayAttributeData& OldValue)
{
GAMEPLAYATTRIBUTE_REPNOTIFY(UCHeroAttributeSet, UpgradePoint, OldValue);
}
void UCHeroAttributeSet::OnRep_MaxLevel(const FGameplayAttributeData& OldValue)
{
GAMEPLAYATTRIBUTE_REPNOTIFY(UCHeroAttributeSet, MaxLevel, OldValue);
}
void UCHeroAttributeSet::OnRep_MaxLevelExperience(const FGameplayAttributeData& OldValue)
{
GAMEPLAYATTRIBUTE_REPNOTIFY(UCHeroAttributeSet, MaxLevelExperience, OldValue);
}
void UCHeroAttributeSet::OnRep_Gold(const FGameplayAttributeData& OldValue)
{
GAMEPLAYATTRIBUTE_REPNOTIFY(UCHeroAttributeSet, Gold, OldValue);
}
void UCHeroAttributeSet::OnRep_HealthRegen(const FGameplayAttributeData& OldValue)
{
GAMEPLAYATTRIBUTE_REPNOTIFY(UCHeroAttributeSet, HealthRegen, OldValue);
}
void UCHeroAttributeSet::OnRep_ManaRegen(const FGameplayAttributeData& OldValue)
{
GAMEPLAYATTRIBUTE_REPNOTIFY(UCHeroAttributeSet, ManaRegen, OldValue);
}
void UCHeroAttributeSet::OnRep_ArmorPenetration(const FGameplayAttributeData& OldValue)
{
GAMEPLAYATTRIBUTE_REPNOTIFY(UCHeroAttributeSet, ArmorPenetration, OldValue);
}
void UCHeroAttributeSet::OnRep_MagicPenetration(const FGameplayAttributeData& OldValue)
{
GAMEPLAYATTRIBUTE_REPNOTIFY(UCHeroAttributeSet, MagicPenetration, OldValue);
}
void UCHeroAttributeSet::OnRep_ArmorPenetrationPercent(const FGameplayAttributeData& OldValue)
{
GAMEPLAYATTRIBUTE_REPNOTIFY(UCHeroAttributeSet, ArmorPenetrationPercent, OldValue);
}
void UCHeroAttributeSet::OnRep_MagicPenetrationPercent(const FGameplayAttributeData& OldValue)
{
GAMEPLAYATTRIBUTE_REPNOTIFY(UCHeroAttributeSet, MagicPenetrationPercent, OldValue);
}
void UCHeroAttributeSet::OnRep_LifeSteal(const FGameplayAttributeData& OldValue)
{
GAMEPLAYATTRIBUTE_REPNOTIFY(UCHeroAttributeSet, LifeSteal, OldValue);
}
void UCHeroAttributeSet::OnRep_MagicLifeSteal(const FGameplayAttributeData& OldValue)
{
GAMEPLAYATTRIBUTE_REPNOTIFY(UCHeroAttributeSet, MagicLifeSteal, OldValue);
}
void UCHeroAttributeSet::OnRep_CooldownReduction(const FGameplayAttributeData& OldValue)
{
GAMEPLAYATTRIBUTE_REPNOTIFY(UCHeroAttributeSet, CooldownReduction, OldValue);
}
void UCHeroAttributeSet::OnRep_CriticalStrikeChance(const FGameplayAttributeData& OldValue)
{
GAMEPLAYATTRIBUTE_REPNOTIFY(UCHeroAttributeSet, CriticalStrikeChance, OldValue);
}
void UCHeroAttributeSet::OnRep_CriticalStrikeDamage(const FGameplayAttributeData& OldValue)
{
GAMEPLAYATTRIBUTE_REPNOTIFY(UCHeroAttributeSet, CriticalStrikeDamage, OldValue);
}
void UCHeroAttributeSet::OnRep_Toughness(const FGameplayAttributeData& OldValue)
{
GAMEPLAYATTRIBUTE_REPNOTIFY(UCHeroAttributeSet, Toughness, OldValue);
}
void UCHeroAttributeSet::OnRep_DamageAmplification(const FGameplayAttributeData& OldValue)
{
GAMEPLAYATTRIBUTE_REPNOTIFY(UCHeroAttributeSet, DamageAmplification, OldValue);
}
void UCHeroAttributeSet::OnRep_DamageReduction(const FGameplayAttributeData& OldValue)
{
GAMEPLAYATTRIBUTE_REPNOTIFY(UCHeroAttributeSet, DamageReduction, OldValue);
}

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐
所有评论(0)