当前位置: 首页 > news >正文

UE5多人MOBA+GAS 番外篇:同时造成多种类型伤害

文章目录

  • 重构伤害类型
  • 重构伤害应用
  • 添加新的属性以及接收属性的修改
  • 修改ECC让其适用于多种伤害类型


重构伤害类型

CGameplayAbilityTypes中重构伤害类型

UENUM(BlueprintType)
enum class EDamageType : uint8
{PhysicalDamage					UMETA(DisplayName="物理伤害"),  // 物理伤害MagicDamage						UMETA(DisplayName="魔法伤害"),  // 魔法伤害TrueDamage						UMETA(DisplayName="真实伤害"),  // 真实伤害
};// 
USTRUCT(BlueprintType)
struct FDamageDefinition
{GENERATED_BODY()
public:FDamageDefinition();// 基础伤害UPROPERTY(EditAnywhere)FScalableFloat BaseDamage;// 属性的百分比伤害加成UPROPERTY(EditAnywhere)TMap<FGameplayAttribute, float> AttributeDamageModifiers;
};
// 伤害效果定义
USTRUCT(BlueprintType)
struct FGenericDamageEffectDef
{GENERATED_BODY()
public:FGenericDamageEffectDef();// 伤害类型UPROPERTY(EditAnywhere)TSubclassOf<UGameplayEffect> DamageEffect;// 伤害类型UPROPERTY(EditAnywhere)TMap<EDamageType,FDamageDefinition> DamageTypeDefinitions;// 力的大小UPROPERTY(EditAnywhere)FVector PushVelocity;
};
FDamageDefinition::FDamageDefinition(): BaseDamage{0.f}
{
}FGenericDamageEffectDef::FGenericDamageEffectDef():DamageEffect{nullptr},PushVelocity{0.f}
{
}

重构伤害应用

修改一下CGameplayAbility中的伤害配置

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);// 配置伤害,这个也可以拆开来MakeDamage(Damage, Level);// 创建效果Spec句柄,指定效果类、能力等级和上下文FGameplayEffectSpecHandle EffectSpecHandle = ASC->MakeOutgoingSpec(Damage.DamageEffect, Level, ContextHandle);// 在目标上应用游戏效果规范ApplyGameplayEffectSpecToTarget(GetCurrentAbilitySpecHandle(),GetCurrentActorInfo(),GetCurrentActivationInfo(),EffectSpecHandle,UAbilitySystemBlueprintLibrary::AbilityTargetDataFromActor(TargetActor));
}void UCGameplayAbility::MakeDamage(const FGenericDamageEffectDef& Damage, int Level)
{// 通通置为0float BaseAttackDamage = 0.f;float BaseMagicDamage = 0.f;float BaseTrueDamage = 0.f;for (const auto& TypePair : Damage.DamageTypeDefinitions){float TotalModifier = TypePair.Value.BaseDamage.GetValueAtLevel(Level);for (const auto& Modifier : TypePair.Value.AttributeDamageModifiers){bool bFound ;float AttributeValue = GetAbilitySystemComponentFromActorInfo()->GetGameplayAttributeValue(Modifier.Key, bFound);if (bFound){TotalModifier += AttributeValue * Modifier.Value / 100.0f;}}switch (TypePair.Key){case EDamageType::PhysicalDamage :BaseAttackDamage = TotalModifier;break;case EDamageType::MagicDamage :BaseMagicDamage = TotalModifier;break;case EDamageType::TrueDamage :BaseTrueDamage = TotalModifier;break;default:break;}}GetAbilitySystemComponentFromActorInfo()->ApplyModToAttribute(UCAttributeSet::GetBaseAttackDamageAttribute(), EGameplayModOp::Override, BaseAttackDamage);GetAbilitySystemComponentFromActorInfo()->ApplyModToAttribute(UCAttributeSet::GetBaseMagicDamageAttribute(), EGameplayModOp::Override, BaseMagicDamage);GetAbilitySystemComponentFromActorInfo()->ApplyModToAttribute(UCAttributeSet::GetBaseTrueDamageAttribute(), EGameplayModOp::Override, BaseTrueDamage);
}

添加新的属性以及接收属性的修改

修改一下属性CAttributeSet,为其添加一些新的东西

USTRUCT()
struct FEffectProperties
{GENERATED_BODY()FEffectProperties(){}UPROPERTY()FGameplayEffectContextHandle EffectContextHandle;UPROPERTY()UAbilitySystemComponent* SourceASC = nullptr;UPROPERTY()AActor* SourceAvatarActor = nullptr;UPROPERTY()AController* SourceController = nullptr;UPROPERTY()ACharacter* SourceCharacter = nullptr;UPROPERTY()UAbilitySystemComponent* TargetASC = nullptr;UPROPERTY()AActor* TargetAvatarActor = nullptr;UPROPERTY()AController* TargetController = nullptr;UPROPERTY()ACharacter* TargetCharacter = nullptr;};
	// 传值物理的基础伤害UPROPERTY(ReplicatedUsing = OnRep_BaseAttackDamage)FGameplayAttributeData BaseAttackDamage;ATTRIBUTE_ACCESSORS(UCAttributeSet, BaseAttackDamage)// 魔法的基础伤害UPROPERTY(ReplicatedUsing = OnRep_BaseMagicDamage)FGameplayAttributeData BaseMagicDamage;ATTRIBUTE_ACCESSORS(UCAttributeSet, BaseMagicDamage)// 真伤的基础伤害UPROPERTY(ReplicatedUsing = OnRep_BaseTrueDamage)FGameplayAttributeData BaseTrueDamage;ATTRIBUTE_ACCESSORS(UCAttributeSet, BaseTrueDamage)UFUNCTION()void OnRep_BaseAttackDamage(const FGameplayAttributeData& OldBaseAttackDamage);UFUNCTION()void OnRep_BaseMagicDamage(const FGameplayAttributeData& OldBaseMagicDamage);UFUNCTION()void OnRep_BaseTrueDamage(const FGameplayAttributeData& OldBaseTrueDamage);// 设置效果属性void SetEffectProperties(const FGameplayEffectModCallbackData& Data, FEffectProperties& Props) const;// 伤害处理函数void Damage(const FEffectProperties& Props, EDamageType Type, const float Damage);

网络复制中添加一下新的变量
在这里插入图片描述

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){Damage(Props, EDamageType::PhysicalDamage, 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,EDamageType::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,EDamageType::TrueDamage, NewDamage);}}
}void UCAttributeSet::OnRep_BaseAttackDamage(const FGameplayAttributeData& OldBaseAttackDamage)
{GAMEPLAYATTRIBUTE_REPNOTIFY(UCAttributeSet, BaseAttackDamage, OldBaseAttackDamage);
}void UCAttributeSet::OnRep_BaseMagicDamage(const FGameplayAttributeData& OldBaseMagicDamage)
{GAMEPLAYATTRIBUTE_REPNOTIFY(UCAttributeSet, BaseMagicDamage, OldBaseMagicDamage);
}void UCAttributeSet::OnRep_BaseTrueDamage(const FGameplayAttributeData& OldBaseTrueDamage)
{GAMEPLAYATTRIBUTE_REPNOTIFY(UCAttributeSet, BaseTrueDamage, OldBaseTrueDamage);
}void UCAttributeSet::SetEffectProperties(const FGameplayEffectModCallbackData& Data, FEffectProperties& Props) const
{//Source 效果的所有者   Target 效果应用的目标Props.EffectContextHandle = Data.EffectSpec.GetContext();Props.SourceASC = Props.EffectContextHandle.GetOriginalInstigatorAbilitySystemComponent();//获取效果所有者的相关对象if (IsValid(Props.SourceASC) && Props.SourceASC->AbilityActorInfo.IsValid() && Props.SourceASC->AbilityActorInfo->AvatarActor.IsValid()){Props.SourceAvatarActor = Props.SourceASC->AbilityActorInfo->AvatarActor.Get();Props.SourceController = Props.SourceASC->AbilityActorInfo->PlayerController.Get();if (Props.SourceAvatarActor != nullptr && Props.SourceController == nullptr){if (const APawn* Pawn = Cast<APawn>(Props.SourceAvatarActor)){Props.SourceController = Pawn->Controller;}}if (Props.SourceController){Props.SourceCharacter = Cast<ACharacter>(Props.SourceController->GetPawn());}}if (Data.Target.AbilityActorInfo.IsValid() && Data.Target.AbilityActorInfo->AvatarActor.IsValid()){Props.TargetAvatarActor = Data.Target.AbilityActorInfo->AvatarActor.Get();Props.TargetController = Data.Target.AbilityActorInfo->PlayerController.Get();Props.TargetCharacter = Cast<ACharacter>(Props.TargetAvatarActor);Props.TargetASC = UAbilitySystemBlueprintLibrary::GetAbilitySystemComponent(Props.TargetAvatarActor);}
}void UCAttributeSet::Damage(const FEffectProperties& Props, EDamageType Type, const float Damage)
{bool bCriticalHit = false;float NewDamage = Damage;if (Props.SourceASC){bool bFound = false;const float EffectiveCriticalHitChance = Props.SourceASC->GetGameplayAttributeValue(UCHeroAttributeSet::GetCriticalStrikeChanceAttribute(), bFound);if (bFound){bFound = false;bCriticalHit = FMath::RandRange(1, 100) < EffectiveCriticalHitChance;if (bCriticalHit){const float CriticalStrikeDamage = Props.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, Log, TEXT("NewDamage: %f"), NewDamage)// 如果生命小于等于0触发死亡if (NewHealth <= 0.f){// 触发死亡被动OnDeadAbility(Props);}ShowFloatingText(Props,NewDamage, bCriticalHit, Type);
}

我还修改了一下死亡的传递值以及伤害的发送,为此,游戏控制器也要修改

	static void ShowFloatingText(const FEffectProperties& Props, float Damage, bool IsCriticalHitE, EDamageType Type);// 用于激活角色死亡被动的函数void OnDeadAbility(const FEffectProperties& Props);
void UCAttributeSet::ShowFloatingText(const FEffectProperties& Props, const float Damage, bool IsCriticalHit, EDamageType Type)
{// 从技能释放者身上获取PC并显示伤害数字if(ACPlayerController* PC = Cast<ACPlayerController>(Props.SourceCharacter->Controller)){PC->ShowDamageNumber(Damage, Props.TargetCharacter, IsCriticalHit, Type); //调用显示伤害数字}// 从目标身上获取PC并显示伤害数字if(ACPlayerController* PC = Cast<ACPlayerController>(Props.TargetCharacter->Controller)){PC->ShowDamageNumber(Damage, Props.TargetCharacter, IsCriticalHit, Type); //调用显示伤害数字}
}void UCAttributeSet::OnDeadAbility(const FEffectProperties& Props)
{FGameplayEventData DeadAbilityEventData;if (Props.SourceAvatarActor){// UE_LOG(LogTemp, Warning, TEXT("Dead:%s"), *GetOwningActor()->GetName())DeadAbilityEventData.Target = Props.SourceAvatarActor;}UAbilitySystemBlueprintLibrary::SendGameplayEventToActor(GetOwningActor(), TGameplayTags::Stats_Dead, DeadAbilityEventData);
}

到游戏控制器CPlayerController中修改一下输出数字的函数

	UFUNCTION(Client, Reliable)void ShowDamageNumber(float DamageAmount, ACharacter* TargetCharacter, bool bCriticalHit, EDamageType Type);
void ACPlayerController::ShowDamageNumber_Implementation(float DamageAmount, ACharacter* TargetCharacter, bool bCriticalHit, EDamageType Type)
{if (!IsValid(TargetCharacter) || !NumberPopComponentClass || !IsLocalController())return;// 获取目标Actor上的现有组件UNumberPopComponent_NiagaraText* DamageText = TargetCharacter->GetComponentByClass<UNumberPopComponent_NiagaraText>();// 不存在则创建并附加if (!DamageText){DamageText = NewObject<UNumberPopComponent_NiagaraText>(TargetCharacter, NumberPopComponentClass);if (!DamageText){
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)UE_LOG(LogTemp, Error, TEXT("Niagara组件创建失败,内存不足或配置错误"));
#endifreturn;}DamageText->RegisterComponent(); // 注册组件}// TODO:添加各种伤害类型的伤害数字特效// 设置显示参数FNumberPopRequest NumberPopRequest;NumberPopRequest.WorldLocation = TargetCharacter->GetActorLocation() + FVector(0, 0, 200);NumberPopRequest.bIsCriticalDamage = bCriticalHit;NumberPopRequest.NumberToDisplay = DamageAmount;DamageText->AddNumberPop(NumberPopRequest);
}

修改ECC让其适用于多种伤害类型

ECC_AttackDamage中进行一些伤害计算的调整

// 幻雨喜欢小猫咪#include "GAS/Executions/ECC_AttackDamage.h"#include "GAS/Core/CAttributeSet.h"
#include "GAS/Core/CHeroAttributeSet.h"struct FDamageStatics
{// FGameplayEffectAttributeCaptureDefinition// 物理基础伤害DECLARE_ATTRIBUTE_CAPTUREDEF(BaseAttackDamage);// 魔法基础伤害DECLARE_ATTRIBUTE_CAPTUREDEF(BaseMagicDamage);// 真实基础伤害DECLARE_ATTRIBUTE_CAPTUREDEF(BaseTrueDamage);// 护甲穿透DECLARE_ATTRIBUTE_CAPTUREDEF(ArmorPenetration);// 护甲穿透百分比DECLARE_ATTRIBUTE_CAPTUREDEF(ArmorPenetrationPercent);// 法术穿透DECLARE_ATTRIBUTE_CAPTUREDEF(MagicPenetration);// 法术穿透百分比DECLARE_ATTRIBUTE_CAPTUREDEF(MagicPenetrationPercent);// 伤害加深DECLARE_ATTRIBUTE_CAPTUREDEF(DamageAmplification);// 敌方的物理防御DECLARE_ATTRIBUTE_CAPTUREDEF(Armor);// 敌方的法术抗性DECLARE_ATTRIBUTE_CAPTUREDEF(MagicResistance);// 伤害减免DECLARE_ATTRIBUTE_CAPTUREDEF(DamageReduction);FDamageStatics(){// 参数:1.属性集 2.属性名 3.目标还是自身 4.是否设置快照(true为创建时获取,false为应用时获取)DEFINE_ATTRIBUTE_CAPTUREDEF(UCAttributeSet, BaseAttackDamage, Source, false);DEFINE_ATTRIBUTE_CAPTUREDEF(UCAttributeSet, BaseMagicDamage, Source, false);DEFINE_ATTRIBUTE_CAPTUREDEF(UCAttributeSet, BaseTrueDamage, 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);DEFINE_ATTRIBUTE_CAPTUREDEF(UCAttributeSet, Armor, Target, false);DEFINE_ATTRIBUTE_CAPTUREDEF(UCAttributeSet, MagicResistance, Target, false);DEFINE_ATTRIBUTE_CAPTUREDEF(UCHeroAttributeSet, DamageReduction, Target, false);}
};
// 静态数据访问函数(单例模式)
static FDamageStatics& DamageStatics()
{static FDamageStatics Statics;return Statics;
}UECC_AttackDamage::UECC_AttackDamage()
{// 将属性添加到捕获列表中RelevantAttributesToCapture.Add(DamageStatics().BaseAttackDamageDef);RelevantAttributesToCapture.Add(DamageStatics().BaseMagicDamageDef);RelevantAttributesToCapture.Add(DamageStatics().BaseTrueDamageDef);RelevantAttributesToCapture.Add(DamageStatics().ArmorPenetrationDef);RelevantAttributesToCapture.Add(DamageStatics().ArmorPenetrationPercentDef);RelevantAttributesToCapture.Add(DamageStatics().MagicPenetrationDef);RelevantAttributesToCapture.Add(DamageStatics().MagicPenetrationPercentDef);RelevantAttributesToCapture.Add(DamageStatics().DamageAmplificationDef);RelevantAttributesToCapture.Add(DamageStatics().ArmorDef);RelevantAttributesToCapture.Add(DamageStatics().MagicResistanceDef);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 DamageAmp = 0.0f;ExecutionParams.AttemptCalculateCapturedAttributeMagnitude(DamageStatics().DamageAmplificationDef, EvaluateParameters, DamageAmp);// 获取敌方的伤害减免float DamageReduction = 0.0f;ExecutionParams.AttemptCalculateCapturedAttributeMagnitude(DamageStatics().DamageReductionDef, EvaluateParameters, DamageReduction);// 计算基础物理伤害值float BaseAttackDamage = 0.0f;ExecutionParams.AttemptCalculateCapturedAttributeMagnitude(DamageStatics().BaseAttackDamageDef, EvaluateParameters, BaseAttackDamage);// 物理伤害的处理if (BaseAttackDamage > 0.0f){// 获取护甲穿透百分比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);// 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 = 0.0f;ExecutionParams.AttemptCalculateCapturedAttributeMagnitude(DamageStatics().BaseMagicDamageDef, EvaluateParameters, BaseMagicDamage);if (BaseMagicDamage > 0){// 获取法术穿透百分比float MagicPenetrationPercent = 0.0f;ExecutionParams.AttemptCalculateCapturedAttributeMagnitude(DamageStatics().MagicPenetrationPercentDef,EvaluateParameters, MagicPenetrationPercent);// 获取法术穿透float MagicPenetration = 0.0f;ExecutionParams.AttemptCalculateCapturedAttributeMagnitude(DamageStatics().MagicPenetrationDef,EvaluateParameters, MagicPenetration);// 获取目标法抗float TargetMagicResistance = 0.0f;ExecutionParams.AttemptCalculateCapturedAttributeMagnitude(DamageStatics().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 = 0.0f;ExecutionParams.AttemptCalculateCapturedAttributeMagnitude(DamageStatics().BaseTrueDamageDef, EvaluateParameters, BaseTrueDamage);if (BaseTrueDamage > 0.0f){// 计算伤害减免BaseTrueDamage *= (1.0f - FMath::Min(DamageReduction/100.0f, 1.0f));// 应用伤害加深(百分比提升)BaseTrueDamage *= (1.0f + DamageAmp / 100.0f);OutExecutionOutput.AddOutputModifier(FGameplayModifierEvaluatedData(UCAttributeSet::GetTrueDamageAttribute(), //获取到伤害属性EGameplayModOp::Override, BaseTrueDamage	//伤害));}
}

伤害的配置
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
伤害多个好像会被夺舍
在这里插入图片描述
或许多弄几个特效组件UNiagaraComponent就好了,一种伤害一个组件
在这里插入图片描述
我试着操作了一手(不建议这么搞,因为我感觉很抽象)
在这里插入图片描述

// 幻雨喜欢小猫咪#pragma once#include "CoreMinimal.h"
#include "Components/ControllerComponent.h"
#include "GAS/Core/CGameplayAbilityTypes.h"
#include "NumberPopComponent_NiagaraText.generated.h"// 定义一个结构体,表示一个数字弹出请求的数据
USTRUCT(BlueprintType)
struct FNumberPopRequest
{GENERATED_BODY()// 弹出数字的位置(世界坐标)UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Lyra|Number Pops")FVector WorldLocation;// 要显示的数字UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Lyra|Number Pops")int32 NumberToDisplay = 0;// 是否是“致命”伤害(@TODO: 应该使用标签来代替)UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Lyra|Number Pops")bool bIsCriticalDamage = false;// 构造函数,初始化默认值FNumberPopRequest(): WorldLocation(ForceInitToZero){}
};class UNiagaraSystem;
class UNiagaraComponent;/*** */
UCLASS(Blueprintable)
class UNumberPopComponent_NiagaraText : public UControllerComponent
{GENERATED_BODY()
public:UNumberPopComponent_NiagaraText(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get());/** * 添加一个数字弹出到列表中以进行可视化展示* @param NewRequest 新的数字弹出请求数据*/UFUNCTION(BlueprintCallable, Category = Foo)void AddNumberPop(const FNumberPopRequest& NewRequest, EDamageType Type);void AddAttackNumber(const FNumberPopRequest& NewRequest);void AddMagicNumber(const FNumberPopRequest& NewRequest);void AddTrueNumber(const FNumberPopRequest& NewRequest);UPROPERTY(EditDefaultsOnly, Category="DamagePop")FName NiagaraArrayName;UPROPERTY(EditDefaultsOnly, Category="DamagePop")TObjectPtr<UNiagaraSystem> TextNiagara;
protected:TArray<int32> DamageNumberArray;UPROPERTY(EditDefaultsOnly, Category = "Number Pop|Style")TObjectPtr<UNiagaraComponent> NiagaraComp;UPROPERTY(EditDefaultsOnly, Category = "Number Pop|Style")TObjectPtr<UNiagaraComponent> MagicNiagaraComp;UPROPERTY(EditDefaultsOnly, Category = "Number Pop|Style")TObjectPtr<UNiagaraComponent> TrueNiagaraComp;
};
// 幻雨喜欢小猫咪#include "Player/NumberPopComponent_NiagaraText.h"
#include "NiagaraComponent.h"
#include "NiagaraDataInterfaceArrayFunctionLibrary.h"UNumberPopComponent_NiagaraText::UNumberPopComponent_NiagaraText(const FObjectInitializer& ObjectInitializer): Super(ObjectInitializer)
{SetIsReplicatedByDefault(true);// bReplicates = true;
}void UNumberPopComponent_NiagaraText::AddNumberPop(const FNumberPopRequest& NewRequest, EDamageType Type)
{switch (Type){case EDamageType::PhysicalDamage:{AddAttackNumber(NewRequest);break;}case EDamageType::MagicDamage:{AddMagicNumber(NewRequest);break;}case EDamageType::TrueDamage:{AddTrueNumber(NewRequest);break;}default:{break;}}}void UNumberPopComponent_NiagaraText::AddAttackNumber(const FNumberPopRequest& NewRequest)
{int32 LocalDamage = NewRequest.NumberToDisplay;//Change Damage to negative to differentiate Critial vs Normal hit// 如果是致命伤害,则将数值设为负数以区分普通伤害if (NewRequest.bIsCriticalDamage){LocalDamage *= -1;}// 如果没有 Niagara 组件,则创建一个if (!NiagaraComp){NiagaraComp = NewObject<UNiagaraComponent>(GetOwner());if (TextNiagara != nullptr){NiagaraComp->SetAsset(TextNiagara);			// 设置 Niagara 资源NiagaraComp->bAutoActivate = false;				// 不自动激活}NiagaraComp->SetupAttachment(nullptr);      // 不附加到任何物体check(NiagaraComp);NiagaraComp->RegisterComponent();					// 注册组件以便更新和渲染// NiagaraComp->SetReplicate(true);}NiagaraComp->Activate(false);                     // 手动激活 Niagara 粒子效果NiagaraComp->SetWorldLocation(NewRequest.WorldLocation); // 设置弹出位置UE_LOG(LogTemp, Log, TEXT("DamageHit location : %s"), *(NewRequest.WorldLocation.ToString()));//Add Damage information to the current Niagara list - Damage informations are packed inside a FVector4 where XYZ = Position, W = Damage// 获取 Niagara 数组中的 FVector4 列表(XYZ 表示位置,W 表示伤害值)TArray<FVector4> DamageList = UNiagaraDataInterfaceArrayFunctionLibrary::GetNiagaraArrayVector4(NiagaraComp, NiagaraArrayName);// 添加新伤害信息到数组中DamageList.Add(FVector4(NewRequest.WorldLocation.X,NewRequest.WorldLocation.Y,NewRequest.WorldLocation.Z,LocalDamage));// 将更新后的数组写回 Niagara 组件UNiagaraDataInterfaceArrayFunctionLibrary::SetNiagaraArrayVector4(NiagaraComp, NiagaraArrayName, DamageList);UNiagaraDataInterfaceArrayFunctionLibrary::SetNiagaraArrayVector4(NiagaraComp, NiagaraArrayName, DamageList);
}void UNumberPopComponent_NiagaraText::AddMagicNumber(const FNumberPopRequest& NewRequest)
{int32 LocalDamage = NewRequest.NumberToDisplay;//Change Damage to negative to differentiate Critial vs Normal hit// 如果是致命伤害,则将数值设为负数以区分普通伤害if (NewRequest.bIsCriticalDamage){LocalDamage *= -1;}// 如果没有 Niagara 组件,则创建一个if (!MagicNiagaraComp){MagicNiagaraComp = NewObject<UNiagaraComponent>(GetOwner());if (TextNiagara != nullptr){MagicNiagaraComp->SetAsset(TextNiagara);			// 设置 Niagara 资源MagicNiagaraComp->bAutoActivate = false;				// 不自动激活}MagicNiagaraComp->SetupAttachment(nullptr);      // 不附加到任何物体check(MagicNiagaraComp);MagicNiagaraComp->RegisterComponent();					// 注册组件以便更新和渲染// NiagaraComp->SetReplicate(true);}MagicNiagaraComp->Activate(false);                     // 手动激活 Niagara 粒子效果MagicNiagaraComp->SetWorldLocation(NewRequest.WorldLocation); // 设置弹出位置UE_LOG(LogTemp, Log, TEXT("DamageHit location : %s"), *(NewRequest.WorldLocation.ToString()));//Add Damage information to the current Niagara list - Damage informations are packed inside a FVector4 where XYZ = Position, W = Damage// 获取 Niagara 数组中的 FVector4 列表(XYZ 表示位置,W 表示伤害值)TArray<FVector4> DamageList = UNiagaraDataInterfaceArrayFunctionLibrary::GetNiagaraArrayVector4(MagicNiagaraComp, NiagaraArrayName);// 添加新伤害信息到数组中DamageList.Add(FVector4(NewRequest.WorldLocation.X,NewRequest.WorldLocation.Y,NewRequest.WorldLocation.Z,LocalDamage));// 将更新后的数组写回 Niagara 组件UNiagaraDataInterfaceArrayFunctionLibrary::SetNiagaraArrayVector4(NiagaraComp, NiagaraArrayName, DamageList);UNiagaraDataInterfaceArrayFunctionLibrary::SetNiagaraArrayVector4(MagicNiagaraComp, NiagaraArrayName, DamageList);
}void UNumberPopComponent_NiagaraText::AddTrueNumber(const FNumberPopRequest& NewRequest)
{int32 LocalDamage = NewRequest.NumberToDisplay;// 如果是致命伤害,则将数值设为负数以区分普通伤害if (NewRequest.bIsCriticalDamage){LocalDamage *= -1;}// 如果没有 Niagara 组件,则创建一个if (!TrueNiagaraComp){TrueNiagaraComp = NewObject<UNiagaraComponent>(GetOwner());if (TextNiagara != nullptr){TrueNiagaraComp->SetAsset(TextNiagara);			// 设置 Niagara 资源TrueNiagaraComp->bAutoActivate = false;				// 不自动激活}TrueNiagaraComp->SetupAttachment(nullptr);      // 不附加到任何物体check(TrueNiagaraComp);TrueNiagaraComp->RegisterComponent();					// 注册组件以便更新和渲染}TrueNiagaraComp->Activate(false);                     // 手动激活 Niagara 粒子效果TrueNiagaraComp->SetWorldLocation(NewRequest.WorldLocation); // 设置弹出位置UE_LOG(LogTemp, Log, TEXT("DamageHit location : %s"), *(NewRequest.WorldLocation.ToString()));//Add Damage information to the current Niagara list - Damage informations are packed inside a FVector4 where XYZ = Position, W = Damage// 获取 Niagara 数组中的 FVector4 列表(XYZ 表示位置,W 表示伤害值)TArray<FVector4> DamageList = UNiagaraDataInterfaceArrayFunctionLibrary::GetNiagaraArrayVector4(TrueNiagaraComp, NiagaraArrayName);// 添加新伤害信息到数组中DamageList.Add(FVector4(NewRequest.WorldLocation.X,NewRequest.WorldLocation.Y,NewRequest.WorldLocation.Z,LocalDamage));// 将更新后的数组写回 Niagara 组件UNiagaraDataInterfaceArrayFunctionLibrary::SetNiagaraArrayVector4(NiagaraComp, NiagaraArrayName, DamageList);UNiagaraDataInterfaceArrayFunctionLibrary::SetNiagaraArrayVector4(TrueNiagaraComp, NiagaraArrayName, DamageList);
}

对于这几个添加数字的特效的函数也可以添加类型,具体操作我也不会特效,就将就这么放着
在这里插入图片描述

http://www.dtcms.com/a/307910.html

相关文章:

  • 虚幻引擎5 GAS开发俯视角RPG游戏 #06-11:游戏后效果执行
  • 关于AR地产发展现状的深度探究​
  • AR智能巡检:制造业运维效率提升的关键
  • 提示词增强工程(Prompt Enhancement Engineering)白皮书草稿
  • AR-Align-NN-2024
  • 一个轻量级、无依赖的 Loading 插件 —— @lijixuan/loading
  • 常用设计模式系列(十七)—命令模式
  • 一天两道力扣(7)
  • 第1章:基础篇——第1节:基础操作与认识界面
  • 每日算法刷题Day56:7.31:leetcode 栈6道题,用时2h30min
  • 使用python写一套完整的智能体小程序
  • BasicAuthenticationFilter处理 HTTP 基本认证(Basic Authentication)的核心过滤器详解
  • python逻辑回归:数学原理到实战应用
  • 逻辑回归详解:从数学原理到实际应用
  • 界面组件DevExpress WPF中文教程:网格视图数据布局 - 数据单元格
  • CentOS7 使用Docker安装MinIO完整教程
  • 使用ANSYS在系统级对降压转换器进行建模
  • 在超算平台异构加速卡AI * 1卡的Ubuntu20.04环境下安装docker服务(未成功)
  • 本土DevOps平台Gitee如何重塑中国研发团队的工作流
  • 为Github Copilot创建自定义指令/说明/注意事项
  • 计算机网络中的socket是什么?编程语言中的socket编程又是什么?python的socket编程又该如何用?
  • 浅谈“压敏电阻”
  • Kubernetes (K8s) 部署Doris
  • 智慧城市多源监控协同精度↑28%:陌讯多模态融合算法实战解析
  • 技术分享 | 悬镜亮相于“2025开放原子开源生态大会软件物料清单(SBOM)”分论坛
  • 计算机网络学习(一、Cisco Packet Tracer软件安装)
  • MySQL查询语句详解
  • matlab - 算4个数的加减法
  • pytorch的自定义 CUDA 扩展怎么学习
  • Wise Duplicate Finder 重复文件查找工具 - 永久免费专业版文件去重工具