UE5多人MOBA+GAS 番外篇:使用ECC(UGameplayEffectExecutionCalculation)制作伤害计算的流程

文章目录

  • 定义一些属性用于作为伤害基础还有获取要打出去的伤害
  • 创建一个ECC(里面执行伤害的计算)
  • 在执行ECC的GE之前需要修改ECC需要调用的值,也可以不改直接计算
  • 在属性中监听ECC输出的那个值然后处理扣血


定义一些属性用于作为伤害基础还有获取要打出去的伤害

伤害的传递位置和接收位置
在这里插入图片描述

创建一个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);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/89984.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/89984.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SpringBoot实战0-5

接口文档&#xff1a;通俗的讲&#xff0c;接口文档能告诉开发者接口能返回的数据&#xff0c;以及为了获取这些数据&#xff0c;开发者需要输入什么样的数据&#xff0c;请求哪个接口&#xff08;即规范&#xff09;为什么使用接口文档&#xff1a;1、项目开发过程中前后端工程…

二、SpringBoot-REST开发

rest开发&#xff08;表现形式转换&#xff09;&#xff1a; 1、优点&#xff1a;隐藏访问资源的行为&#xff0c;无法通过地址得知对资源是何种操作&#xff0c;书写简化 2、GET查询 POST 新增/保存 PUT&#xff08;修改/更新&#xff09; DELETE&#xff08;删除&#xff09;…

大数据之路:阿里巴巴大数据实践——离线数据开发

数据开发平台 统一计算平台MaxCompute&#xff1a;主要服务于海量数据的存储和计算 &#xff0c;提供完善的数据导入方案&#xff0c; 以及多种经典的分布式计算模型&#xff0c;提供海量数据仓库的解决方案&#xff0c;能够更快速地解决用户的海量数据计算问题&#xff0c;有效…

我的网页聊天室设计

一、需求分析1.用户管理模块注册功能实现一个注册页面。注册页面上包含了一个输入框&#xff0c;输入用户名和密码. 注册成功后可以跳转到登录页面.登录功能实现一个登录页面。登录页面上包含一个输入框。输入用户名和密码. 登录成功后可以跳转到主页面.2.主界面用户信息左上角…

数据结构自学Days10 -- 二叉树的常用实现

✅ 一、为什么要学习二叉树&#xff1f; 1. &#x1f4e6; 组织数据的高效方式 二叉树可以快速插入、删除、查找数据&#xff0c;尤其在平衡时&#xff0c;时间复杂度为 $O(\log n)$。 适合表示分层结构&#xff08;如组织结构、文件系统、语法树&#xff09;。 2. &#x…

Java注解家族--`@ResponseBody`

ResponseBody ResponseBody是 Spring 框架中的一个注解&#xff0c;在基于 Spring 的 Web 开发中扮演着重要角色&#xff0c;以下是对它的详细总结&#xff1a; 1.定义与基本功能 定义&#xff1a;ResponseBody注解用于将 Controller 方法的返回值&#xff0c;通过适当的 HttpM…

react-window 大数据列表和表格数据渲染组件之虚拟滚动

简介 React Window 是一个高效的 React 组件库&#xff0c;专为渲染大数据列表和表格数据而设计。它通过”虚拟化”技术&#xff08;也称为”窗口化”或”列表虚拟化”&#xff09;解决了在 React 应用中渲染大量数据时的性能问题。与传统方法不同&#xff0c;React Window 只…

Eltable tree形式,序号列实现左对齐,并且每下一层都跟上一层的错位距离拉大

要的是如图所示效果序号加个class-name写样式然后给eltable加indent属性就可以了&#xff0c;我设置的25

FOC算法中SIMULINK一些常用模块(2)-Permanent Magnet Synchronous Machine模块

一&#xff0c;介绍这三个模块一起介绍了&#xff0c;由左到右&#xff0c;分别是电源模块&#xff0c;驱动模块和电机模块。主要介绍一下电机模块二&#xff0c;DC Voltage SourceDC Voltage Source 模块是用于表示直流电压源的基本组件&#xff0c;可以提供恒流直压&#xff…

RPG62.制作敌人攻击波数二:攻击ui

1。经典创建userwidget&#xff0c;使用xmbtextblock&#xff0c;结构如下。然后设置动画与音频&#xff0c;上下的参数是一样的&#xff0c;转到图表打开BP_SurvialGameMode2.再创建一个widget&#xff0c;结构如下新添的动画打开XMBGameModeBase&#xff0c;创建构造函数AXMB…

DL00691-基于深度学习的轴承表面缺陷目标检测含源码python

DL00691-基于深度学习的轴承表面缺陷目标检测含源码python

Word 中为什么我的图片一拖就乱跑,怎么精确定位?

核心原因&#xff1a;文字环绕方式 (Text Wrapping) 问题的根源在于图片的**“文字环绕”**设置。 默认状态&#xff1a;“嵌入型” (In Line with Text) 当您插入一张图片时&#xff0c;Word默认会把它当作一个巨大的文字字符来处理。这就是为什么您拖动它时&#xff0c;它会像…

Linux物理地址空间入门:从硬件到内核内存的基石

目录 一、物理地址空间是什么&#xff1f; 二、物理地址空间的构成&#xff1a;不仅仅是内存 三、Linux内核如何管理物理地址空间 &#xff08;1&#xff09;物理内存的碎片化问题 &#xff08;2&#xff09;物理地址的分区管理 &#xff08;3&#xff09;物理地址与内核…

【2025最新版】PDFelement全能PDF编辑器

工具https://pan.quark.cn/s/a56d17fd05dd强大全能的PDF编辑神器PDFelementPro 全能PDF工具套装 PDF阅读器 PDF创建器 PDF编辑器 PDF注释器 PDF转换器 OCR识别工具 表单填写和创建 数据提取 批量处理 更多详情万兴PDF专业版特性。格式转换&#xff1a;PDFelement轻松…

基于单片机汽车驾驶防瞌睡防疲劳报警器自动熄火设计

&#xff08;一&#xff09;系统功能设计 51单片机汽车驾驶防疲劳防瞌睡报警器自动熄火15 本系统由STC89C52单片机、蜂鸣器、ADXL345重力加速度传感器、继电器控制、按键、指示灯及电源组成。 1、通过按键点亮led灯&#xff0c;代表车辆启动和熄火。 2、车辆启动后&#xff0c;…

OpenCV中的卷积高斯模糊与中值模糊

目录 一、卷积高斯模糊 (Gaussian Blur) 1. 原理与数学基础 2. OpenCV函数实现 3. 关键参数说明 4. 代码示例 5. 特点与应用 二、中值模糊 (Median Blur) 1. 原理与数学基础 2. OpenCV函数实现 3. 关键参数说明 4. 代码示例 5. 特点与应用 三、两种模糊方法对比分析…

macbookpro m1 max本儿上速搭一个elasticsearch+kibana环境

一、找个目录&#xff0c;新建一个: docker-compose.yml version: "3.9" services:elasticsearch:image: docker.elastic.co/elasticsearch/elasticsearch:8.13.0 # 与 Kibana 版本一致container_name: elasticsearchenvironment:- discovery.typesingle-node- xpa…

部署zabbix企业级分布式监控

一. 监控系统的功能概述监控、从中文的字义来看&#xff0c;有两个内容&#xff0c;一是检测&#xff0c;二是控制。重点在第一个字眼&#xff0c;即检测、预防的意思。监控&#xff0c;对应的英文单词是 Monitoring。在计算机领域&#xff0c;可以将其分为5种监控类型。应用性…

【重学MySQL】redolog binlog

目录 Buffer Pool是什么&#xff1f; redo log&#xff08;Innodb独有&#xff09; 为什么需要redolog&#xff1f; 类比的方式巧记redolog binlog&#xff08;Server层独有&#xff09; binlog是干啥的&#xff1f; 为什么有了 binlog&#xff0c; 还要有 redo log&…

企业信息化建设技术底座建设解决方案

1、企业数字化底座与数字化综述2、企业数字化底座与数字化总体架构3、企业数字化底座与数字化规划设计4、企业数字化底座与数字化建设运营5、企业数字化底座与数字化未来展望篇幅有限以下只展示部分截图&#xff1a;