文章目录
添加一个标签用来区分该Actor是否是英雄单位
cpp
CRUNCH_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(Role_Hero)
cpp
UE_DEFINE_GAMEPLAY_TAG_COMMENT(Role_Hero, "Role.Hero", "英雄角色")
添加死亡被动
继承C技能添加一个死亡被动技能
cpp
// 幻雨喜欢小猫咪
#pragma once
#include "CoreMinimal.h"
#include "GAS/Core/CGameplayAbility.h"
#include "GAP_Dead.generated.h"
/**
* 死亡能力类
* 负责角色死亡时的奖励分配(经验、金币等)
*/
UCLASS()
class CRUNCH_API UGAP_Dead : public UCGameplayAbility
{
GENERATED_BODY()
public:
UGAP_Dead();
virtual void ActivateAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo, const FGameplayEventData* TriggerEventData) override;
};
cpp
// 幻雨喜欢小猫咪
#include "GAS/Abilities/GAP_Dead.h"
#include "GAS/Core/TGameplayTags.h"
UGAP_Dead::UGAP_Dead()
{
// 设置网络执行策略为仅在服务器端执行
NetExecutionPolicy = EGameplayAbilityNetExecutionPolicy::ServerOnly;
// 创建一个新触发数据对象
FAbilityTriggerData TriggerData;
// 设置触发数据的触发源为游戏事件
TriggerData.TriggerSource = EGameplayAbilityTriggerSource::GameplayEvent;
TriggerData.TriggerTag = TGameplayTags::Stats_Dead;
AbilityTriggers.Add(TriggerData);
// 死亡去除眩晕状态
ActivationBlockedTags.RemoveTag(TGameplayTags::Stats_Stun);
}
void UGAP_Dead::ActivateAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo, const FGameplayEventData* TriggerEventData)
{
if (K2_HasAuthority())
{
AActor* Killer = TriggerEventData->ContextHandle.GetEffectCauser();
if (!Killer)
{
UE_LOG(LogTemp, Warning, TEXT("Killer is null"))
}else
{
UE_LOG(LogTemp, Warning, TEXT("Killer is : %s"), *Killer->GetName())
}
}
}
激活死亡被动技能
ASC中添加被动技能,以及在死亡的时候激活死亡被动技能(如果使用MMC的话就在这里激活技能使用ECC的话获取不到敌人)
这是直接用GE来计算扣血的操作
ECC的扣血触发的话就会无法获取角色
cpp
// 被动技能
UPROPERTY(EditDefaultsOnly, Category = "Gameplay Ability")
TArray<TSubclassOf<UGameplayAbility>> PassiveAbilities;
cpp
void UCAbilitySystemComponent::GiveInitialAbilities()
{
// 检查当前组件是否拥有拥有者,并且拥有者是否具有网络权限(权威性)
if (!GetOwner() || !GetOwner()->HasAuthority()) return;
for (const TPair<ECAbilityInputID,TSubclassOf<UGameplayAbility>>& AbilityPair : BasicAbilities)
{
// 赋予技能 等级为 1
GiveAbility(FGameplayAbilitySpec(AbilityPair.Value, 1, static_cast<int32>(AbilityPair.Key), nullptr));
}
for (const TPair<ECAbilityInputID,TSubclassOf<UGameplayAbility>>& AbilityPair : Abilities)
{
GiveAbility(FGameplayAbilitySpec(AbilityPair.Value, 0, static_cast<int32>(AbilityPair.Key), nullptr));
}
for (const TSubclassOf<UGameplayAbility>& PassiveAbility : PassiveAbilities)
{
GiveAbility(FGameplayAbilitySpec(PassiveAbility, 1, -1, nullptr));
}
}

MMC做法
cpp
void UCAbilitySystemComponent::HealthUpdated(const FOnAttributeChangeData& ChangeData)
{
if (!GetOwner() || !GetOwner()->HasAuthority()) return;
// 获取当前最大生命值
bool bFound = false;
float MaxHealth = GetGameplayAttributeValue(UCAttributeSet::GetMaxHealthAttribute(), bFound);
// 如果生命值达到最大值,添加生命值已满标签
if (bFound && ChangeData.NewValue >= MaxHealth)
{
if (!HasMatchingGameplayTag(TGameplayTags::Stats_Health_Full))
{
// 仅本地会添加标签
AddLooseGameplayTag(TGameplayTags::Stats_Health_Full);
}
}
else
{
// 移除生命值已满标签
RemoveLooseGameplayTag(TGameplayTags::Stats_Health_Full);
}
if (ChangeData.NewValue <= 0.0f)
{
if (!HasMatchingGameplayTag(TGameplayTags::Stats_Health_Empty))
{
// 本地添加生命值清零标签
AddLooseGameplayTag(TGameplayTags::Stats_Health_Empty);
// 角色死亡
if (DeathEffect)
{
AuthApplyGameplayEffect(DeathEffect);
}
// 创建需要传给死亡被动技能的事件数据
FGameplayEventData DeadAbilityEventData;
if (ChangeData.GEModData)
{
DeadAbilityEventData.ContextHandle = ChangeData.GEModData->EffectSpec.GetContext();
}else
{
UE_LOG(LogTemp, Error, TEXT("ChangeData.GEModData is null"))
}
UAbilitySystemBlueprintLibrary::SendGameplayEventToActor(GetOwner(),
TGameplayTags::Stats_Dead,
DeadAbilityEventData);
}
}else
{
RemoveLooseGameplayTag(TGameplayTags::Stats_Health_Empty);
}
}
ECC做法
MMC那种在ASC里面获取的GEModData
和属性里获取的const FGameplayEffectModCallbackData& Data
是同一种数据类型
在属性里伤害接收这里判断生命是否小于等于0
两种方法都可以
cpp
void UCAttributeSet::OnDeadAbility(const FGameplayEffectModCallbackData& Data)
{
FGameplayEventData DeadAbilityEventData;
if (AActor* TargetActor = Data.EffectSpec.GetContext().GetOriginalInstigatorAbilitySystemComponent()->AbilityActorInfo->AvatarActor.Get())
{
UE_LOG(LogTemp, Warning, TEXT("Dead:%s"), *GetOwningActor()->GetName())
DeadAbilityEventData.Target = TargetActor;
DeadAbilityEventData.ContextHandle = Data.EffectSpec.GetContext();
}
UAbilitySystemBlueprintLibrary::SendGameplayEventToActor(GetOwningActor(),
TGameplayTags::Stats_Dead,
DeadAbilityEventData);
}
cpp
void UGAP_Dead::ActivateAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo, const FGameplayEventData* TriggerEventData)
{
if (K2_HasAuthority())
{
// MMC 获取
// AActor* Killer = TriggerEventData->ContextHandle.GetEffectCauser();
// ECC 获取
AActor* Killer = nullptr;
if (TriggerEventData->ContextHandle.GetOriginalInstigatorAbilitySystemComponent()->AbilityActorInfo->AvatarActor.Get())
{
Killer = TriggerEventData->ContextHandle.GetOriginalInstigatorAbilitySystemComponent()->AbilityActorInfo->AvatarActor.Get();
UE_LOG(LogTemp, Warning, TEXT("TriggerEventData->ContextHandle.GetOriginalInstigatorAbilitySystemComponent()->AbilityActorInfo->AvatarActor.Get(): %s"), *Killer->GetName())
}
if (TriggerEventData->Target)
{
Killer = static_cast<AActor*>(TriggerEventData->Target);
UE_LOG(LogTemp, Warning, TEXT("TriggerEventData->Target: %s"), *Killer->GetName())
}
if (!Killer)
{
UE_LOG(LogTemp, Warning, TEXT("Killer is null"))
}else
{
UE_LOG(LogTemp, Warning, TEXT("Killer is : %s"), *Killer->GetName())
}
}
}
寻找奖励目标
设置一个范围的检测,寻找击杀者的阵容的英雄单位,因此在CAbilitySystemStatics
中添加一个函数来判断是否为英雄
cpp
// 判断是否为英雄
static bool IsHero(const AActor* ActorToCheck);
cpp
bool UCAbilitySystemStatics::IsHero(const AActor* ActorToCheck)
{
const IAbilitySystemInterface* ActorISA = Cast<IAbilitySystemInterface>(ActorToCheck);
if (ActorISA)
{
UAbilitySystemComponent* ActorASC = ActorISA->GetAbilitySystemComponent();
if (ActorASC)
{
return ActorASC->HasMatchingGameplayTag(TGameplayTags::Role_Hero);
}
}
return false;
}
cpp
private:
// 奖励分配的范围,在该范围内的队友可获得奖励
UPROPERTY(EditDefaultsOnly, Category = "Reward")
float RewardRange = 1000.f;
// 获取奖励目标(如附近的队友等)
TArray<AActor*> GetRewardTargets() const;
cpp
// 幻雨喜欢小猫咪
#include "GAS/Abilities/GAP_Dead.h"
#include "AbilitySystemComponent.h"
#include "Engine/OverlapResult.h"
#include "GAS/Core/CAbilitySystemStatics.h"
#include "GAS/Core/TGameplayTags.h"
UGAP_Dead::UGAP_Dead()
{
// 设置网络执行策略为仅在服务器端执行
NetExecutionPolicy = EGameplayAbilityNetExecutionPolicy::ServerOnly;
// 创建一个新触发数据对象
FAbilityTriggerData TriggerData;
// 设置触发数据的触发源为游戏事件
TriggerData.TriggerSource = EGameplayAbilityTriggerSource::GameplayEvent;
TriggerData.TriggerTag = TGameplayTags::Stats_Dead;
AbilityTriggers.Add(TriggerData);
// 死亡去除眩晕状态
ActivationBlockedTags.RemoveTag(TGameplayTags::Stats_Stun);
}
void UGAP_Dead::ActivateAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo, const FGameplayEventData* TriggerEventData)
{
if (K2_HasAuthority())
{
// MMC 获取
// AActor* Killer = TriggerEventData->ContextHandle.GetEffectCauser();
// ECC 获取
AActor* Killer = nullptr;
if (TriggerEventData->Target)
{
Killer = static_cast<AActor*>(TriggerEventData->Target);
UE_LOG(LogTemp, Warning, TEXT("TriggerEventData->Target: %s"), *Killer->GetName())
}
if (!Killer)
{
UE_LOG(LogTemp, Warning, TEXT("Killer is null"))
K2_EndAbility();
return;
}
TArray<AActor*> RewardTargets = GetRewardTargets();
for (const AActor* RewardTarget : RewardTargets)
{
UE_LOG(LogTemp, Warning, TEXT("Find Reward Target: %s"), *RewardTarget->GetName());
}
K2_EndAbility();
}
}
TArray<AActor*> UGAP_Dead::GetRewardTargets() const
{
TSet<AActor*> OutActors;
AActor* AvatarActor = GetAvatarActorFromActorInfo();
if (!AvatarActor || !GetWorld())
{
return OutActors.Array();
}
// 配置碰撞检测参数
FCollisionObjectQueryParams ObjectQueryParams;
ObjectQueryParams.AddObjectTypesToQuery(ECC_Pawn);
FCollisionShape CollisionShape;
CollisionShape.SetSphere(RewardRange); // 使用奖励范围作为检测半径
TArray<FOverlapResult> OverlapResults;
// 检测碰撞
if (GetWorld()->OverlapMultiByObjectType(OverlapResults, AvatarActor->GetActorLocation(), FQuat::Identity, ObjectQueryParams, CollisionShape))
{
for (const FOverlapResult& OverlapResult : OverlapResults)
{
// 获取团队接口,给死亡目标的敌对单位提供奖励
const IGenericTeamAgentInterface* TeamInterface = Cast<IGenericTeamAgentInterface>(OverlapResult.GetActor());
// 过滤非敌对单位
if (!TeamInterface || TeamInterface->GetTeamAttitudeTowards(*AvatarActor) != ETeamAttitude::Hostile)
{
continue;
}
// 判断是否为英雄单位
if (!UCAbilitySystemStatics::IsHero(OverlapResult.GetActor()))
{
continue;
}
// 添加到奖励目标集合
OutActors.Add(OverlapResult.GetActor());
}
}
return OutActors.Array();
}
创建一个GE用来将英雄的Tag赋值给英雄
奖励的计算与发放
添加两个标签用于GE调用数值
cpp
// 经验
CRUNCH_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(AttributeSet_Experience)
// 金币
CRUNCH_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(AttributeSet_Gold)
cpp
UE_DEFINE_GAMEPLAY_TAG_COMMENT(AttributeSet_Experience, "AttributeSet.Experience", "经验值")
UE_DEFINE_GAMEPLAY_TAG_COMMENT(AttributeSet_Gold, "AttributeSet.Gold", "金币")
给死亡被动添加一些属性用于分配奖励以及发放奖励的GE
cpp
private:
// 奖励分配的范围,在该范围内的队友可获得奖励
UPROPERTY(EditDefaultsOnly, Category = "Reward", meta=(DisplayName="奖励范围"))
float RewardRange = 1000.f;
// 基础经验奖励
UPROPERTY(EditDefaultsOnly, Category = "Reward", meta=(DisplayName="基础经验奖励"))
float BaseExperienceReward = 200.f;
// 基础金币奖励
UPROPERTY(EditDefaultsOnly, Category = "Reward", meta=(DisplayName="基础金币奖励"))
float BaseGoldReward = 200.f;
// 额外经验奖励系数(根据目标经验值加成)
UPROPERTY(EditDefaultsOnly, Category = "Reward", meta=(DisplayName="经验奖励系数(每单位经验)"))
float ExperienceRewardPerExperience = 0.1f;
// 额外金币奖励系数(根据目标经验值加成)
UPROPERTY(EditDefaultsOnly, Category = "Reward", meta=(DisplayName="金币奖励系数(每单位经验)"))
float GoldRewardPerExperience = 0.05f;
// 击杀者奖励占比(击杀者获得的奖励比例,其余分配给队友)
UPROPERTY(EditDefaultsOnly, Category = "Reward", meta=(DisplayName="击杀者奖励比例(0-1)"))
float KillerRewardPortion = 0.5f;
// 获取奖励目标(如附近的队友等)
TArray<AActor*> GetRewardTargets() const;
// 奖励GE(用于发放经验、金币等)
UPROPERTY(EditDefaultsOnly, Category = "Reward", meta=(DisplayName="奖励效果(GE类)"))
TSubclassOf<UGameplayEffect> RewardEffect;
cpp
void UGAP_Dead::ActivateAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo, const FGameplayEventData* TriggerEventData)
{
if (K2_HasAuthority())
{
// MMC 获取
// AActor* Killer = TriggerEventData->ContextHandle.GetEffectCauser();
// ECC 获取
AActor* Killer = nullptr;
if (TriggerEventData->Target)
{
Killer = static_cast<AActor*>(TriggerEventData->Target);
UE_LOG(LogTemp, Warning, TEXT("TriggerEventData->Target: %s"), *Killer->GetName())
}
// 击杀者不存在或者击杀者为非英雄单位
if (!Killer || !UCAbilitySystemStatics::IsHero(Killer))
{
Killer = nullptr;
}
// 获取需要奖励的目标
TArray<AActor*> RewardTargets = GetRewardTargets();
// 如果没有奖励目标又没有击杀者直接结束技能不需要奖励
if (RewardTargets.Num() == 0 && !Killer)
{
K2_EndAbility();
return;
}
// 击杀者存在并且不在奖励目标中,将击杀者添加进去
if (Killer && !RewardTargets.Contains(Killer))
{
RewardTargets.Add(Killer);
}
bool bFound = false;
// 获取角色当前经验属性值
float SelfExperience = GetAbilitySystemComponentFromActorInfo_Ensured()->GetGameplayAttributeValue(UCHeroAttributeSet::GetExperienceAttribute(), bFound);
// 计算总奖励(基础奖励+基于经验的奖励)
float TotalExperienceReward = BaseExperienceReward + ExperienceRewardPerExperience * SelfExperience;
float TotalGoldReward = BaseGoldReward + GoldRewardPerExperience * SelfExperience;
// 判断是否有击杀的英雄单位,给他分大头
if (Killer)
{
float KillerExperienceReward = TotalExperienceReward * KillerRewardPortion;
float KillerGoldReward = TotalGoldReward * KillerRewardPortion;
// 创建击杀者奖励效果
FGameplayEffectSpecHandle EffectSpecHandle = MakeOutgoingGameplayEffectSpec(RewardEffect);
// 设置GE上面的属性值
EffectSpecHandle.Data->SetSetByCallerMagnitude(TGameplayTags::AttributeSet_Experience, KillerExperienceReward);
EffectSpecHandle.Data->SetSetByCallerMagnitude(TGameplayTags::AttributeSet_Gold, KillerGoldReward);
// 对击杀者应用奖励效果
K2_ApplyGameplayEffectSpecToTarget(EffectSpecHandle, UAbilitySystemBlueprintLibrary::AbilityTargetDataFromActor(Killer));
// 从总奖励中扣除击杀者部分
TotalExperienceReward -= KillerExperienceReward;
TotalGoldReward -= KillerGoldReward;
}
// 把剩余的奖励平均分配给没有k到头的英雄单位(k到的也能多吃一口)
float ExperiencePerTarget = TotalExperienceReward / RewardTargets.Num();
float GoldPerTarget = TotalGoldReward / RewardTargets.Num();
// 创建群体奖励效果
FGameplayEffectSpecHandle EffectSpecHandle = MakeOutgoingGameplayEffectSpec(RewardEffect);
// 设置GE上面的属性值
EffectSpecHandle.Data->SetSetByCallerMagnitude(TGameplayTags::AttributeSet_Experience, ExperiencePerTarget);
EffectSpecHandle.Data->SetSetByCallerMagnitude(TGameplayTags::AttributeSet_Gold, GoldPerTarget);
// 对所有奖励目标应用奖励
K2_ApplyGameplayEffectSpecToTarget(EffectSpecHandle, UAbilitySystemBlueprintLibrary::AbilityTargetDataFromActorArray(RewardTargets, true));
K2_EndAbility();
}
}
创建一个GE用于给奖励
配置到死亡被动中
添加两个属性监听看一下效果

击杀者拿一半,然后再两个人再平分剩下的一半,没错
完整死亡被动
cpp
// 幻雨喜欢小猫咪
#pragma once
#include "CoreMinimal.h"
#include "GAS/Core/CGameplayAbility.h"
#include "GAP_Dead.generated.h"
/**
* 死亡能力类
* 负责角色死亡时的奖励分配(经验、金币等)
*/
UCLASS()
class CRUNCH_API UGAP_Dead : public UCGameplayAbility
{
GENERATED_BODY()
public:
UGAP_Dead();
virtual void ActivateAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo, const FGameplayEventData* TriggerEventData) override;
private:
// 奖励分配的范围,在该范围内的队友可获得奖励
UPROPERTY(EditDefaultsOnly, Category = "Reward", meta=(DisplayName="奖励范围"))
float RewardRange = 1000.f;
// 基础经验奖励
UPROPERTY(EditDefaultsOnly, Category = "Reward", meta=(DisplayName="基础经验奖励"))
float BaseExperienceReward = 200.f;
// 基础金币奖励
UPROPERTY(EditDefaultsOnly, Category = "Reward", meta=(DisplayName="基础金币奖励"))
float BaseGoldReward = 200.f;
// 额外经验奖励系数(根据目标经验值加成)
UPROPERTY(EditDefaultsOnly, Category = "Reward", meta=(DisplayName="经验奖励系数(每单位经验)"))
float ExperienceRewardPerExperience = 0.1f;
// 额外金币奖励系数(根据目标经验值加成)
UPROPERTY(EditDefaultsOnly, Category = "Reward", meta=(DisplayName="金币奖励系数(每单位经验)"))
float GoldRewardPerExperience = 0.05f;
// 击杀者奖励占比(击杀者获得的奖励比例,其余分配给队友)
UPROPERTY(EditDefaultsOnly, Category = "Reward", meta=(DisplayName="击杀者奖励比例(0-1)"))
float KillerRewardPortion = 0.5f;
// 获取奖励目标(如附近的队友等)
TArray<AActor*> GetRewardTargets() const;
// 奖励GE(用于发放经验、金币等)
UPROPERTY(EditDefaultsOnly, Category = "Reward", meta=(DisplayName="奖励效果(GE类)"))
TSubclassOf<UGameplayEffect> RewardEffect;
};
cpp
// 幻雨喜欢小猫咪
#include "GAS/Abilities/GAP_Dead.h"
#include "AbilitySystemBlueprintLibrary.h"
#include "AbilitySystemComponent.h"
#include "Engine/OverlapResult.h"
#include "GAS/Core/CAbilitySystemStatics.h"
#include "GAS/Core/CHeroAttributeSet.h"
#include "GAS/Core/TGameplayTags.h"
UGAP_Dead::UGAP_Dead()
{
// 设置网络执行策略为仅在服务器端执行
NetExecutionPolicy = EGameplayAbilityNetExecutionPolicy::ServerOnly;
// 创建一个新触发数据对象
FAbilityTriggerData TriggerData;
// 设置触发数据的触发源为游戏事件
TriggerData.TriggerSource = EGameplayAbilityTriggerSource::GameplayEvent;
TriggerData.TriggerTag = TGameplayTags::Stats_Dead;
AbilityTriggers.Add(TriggerData);
// 死亡去除眩晕状态
ActivationBlockedTags.RemoveTag(TGameplayTags::Stats_Stun);
}
void UGAP_Dead::ActivateAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo, const FGameplayEventData* TriggerEventData)
{
if (K2_HasAuthority())
{
// MMC 获取
// AActor* Killer = TriggerEventData->ContextHandle.GetEffectCauser();
// ECC 获取
AActor* Killer = nullptr;
if (TriggerEventData->Target)
{
Killer = static_cast<AActor*>(TriggerEventData->Target);
UE_LOG(LogTemp, Warning, TEXT("TriggerEventData->Target: %s"), *Killer->GetName())
}
// 击杀者不存在或者击杀者为非英雄单位
if (!Killer || !UCAbilitySystemStatics::IsHero(Killer))
{
Killer = nullptr;
}
// 获取需要奖励的目标
TArray<AActor*> RewardTargets = GetRewardTargets();
// 如果没有奖励目标又没有击杀者直接结束技能不需要奖励
if (RewardTargets.Num() == 0 && !Killer)
{
K2_EndAbility();
return;
}
// 击杀者存在并且不在奖励目标中,将击杀者添加进去
if (Killer && !RewardTargets.Contains(Killer))
{
RewardTargets.Add(Killer);
}
bool bFound = false;
// 获取角色当前经验属性值
float SelfExperience = GetAbilitySystemComponentFromActorInfo_Ensured()->GetGameplayAttributeValue(UCHeroAttributeSet::GetExperienceAttribute(), bFound);
// 计算总奖励(基础奖励+基于经验的奖励)
float TotalExperienceReward = BaseExperienceReward + ExperienceRewardPerExperience * SelfExperience;
float TotalGoldReward = BaseGoldReward + GoldRewardPerExperience * SelfExperience;
// 判断是否有击杀的英雄单位,给他分大头
if (Killer)
{
float KillerExperienceReward = TotalExperienceReward * KillerRewardPortion;
float KillerGoldReward = TotalGoldReward * KillerRewardPortion;
UE_LOG(LogTemp, Warning, TEXT("击杀者经验奖励:%f"), KillerExperienceReward)
// 创建击杀者奖励效果
FGameplayEffectSpecHandle EffectSpecHandle = MakeOutgoingGameplayEffectSpec(RewardEffect);
// 设置GE上面的属性值
EffectSpecHandle.Data->SetSetByCallerMagnitude(TGameplayTags::AttributeSet_Experience, KillerExperienceReward);
EffectSpecHandle.Data->SetSetByCallerMagnitude(TGameplayTags::AttributeSet_Gold, KillerGoldReward);
// 对击杀者应用奖励效果
K2_ApplyGameplayEffectSpecToTarget(EffectSpecHandle, UAbilitySystemBlueprintLibrary::AbilityTargetDataFromActor(Killer));
// 从总奖励中扣除击杀者部分
TotalExperienceReward -= KillerExperienceReward;
TotalGoldReward -= KillerGoldReward;
}
// 把剩余的奖励平均分配给没有k到头的英雄单位
float ExperiencePerTarget = TotalExperienceReward / RewardTargets.Num();
float GoldPerTarget = TotalGoldReward / RewardTargets.Num();
UE_LOG(LogTemp, Warning, TEXT("数组里面多少人%d"), RewardTargets.Num())
UE_LOG(LogTemp, Warning, TEXT("平均经验奖励:%f"), ExperiencePerTarget)
// 创建群体奖励效果
FGameplayEffectSpecHandle EffectSpecHandle = MakeOutgoingGameplayEffectSpec(RewardEffect);
// 设置GE上面的属性值
EffectSpecHandle.Data->SetSetByCallerMagnitude(TGameplayTags::AttributeSet_Experience, ExperiencePerTarget);
EffectSpecHandle.Data->SetSetByCallerMagnitude(TGameplayTags::AttributeSet_Gold, GoldPerTarget);
// 对所有奖励目标应用奖励
K2_ApplyGameplayEffectSpecToTarget(EffectSpecHandle, UAbilitySystemBlueprintLibrary::AbilityTargetDataFromActorArray(RewardTargets, true));
K2_EndAbility();
}
}
TArray<AActor*> UGAP_Dead::GetRewardTargets() const
{
TSet<AActor*> OutActors;
AActor* AvatarActor = GetAvatarActorFromActorInfo();
if (!AvatarActor || !GetWorld())
{
return OutActors.Array();
}
// 配置碰撞检测参数
FCollisionObjectQueryParams ObjectQueryParams;
ObjectQueryParams.AddObjectTypesToQuery(ECC_Pawn);
FCollisionShape CollisionShape;
CollisionShape.SetSphere(RewardRange); // 使用奖励范围作为检测半径
TArray<FOverlapResult> OverlapResults;
// 检测碰撞
if (GetWorld()->OverlapMultiByObjectType(OverlapResults, AvatarActor->GetActorLocation(), FQuat::Identity, ObjectQueryParams, CollisionShape))
{
for (const FOverlapResult& OverlapResult : OverlapResults)
{
// 获取团队接口,给死亡目标的敌对单位提供奖励
const IGenericTeamAgentInterface* TeamInterface = Cast<IGenericTeamAgentInterface>(OverlapResult.GetActor());
// 过滤非敌对单位
if (!TeamInterface || TeamInterface->GetTeamAttitudeTowards(*AvatarActor) != ETeamAttitude::Hostile)
{
continue;
}
// 判断是否为英雄单位
if (!UCAbilitySystemStatics::IsHero(OverlapResult.GetActor()))
{
continue;
}
// 添加到奖励目标集合
OutActors.Add(OverlapResult.GetActor());
}
}
return OutActors.Array();
}