虚幻引擎5 GAS开发俯视角RPG游戏 #06-11:游戏后效果执行

本文介绍了GameplayAbilitySystem中PostGameplayEffectExecute函数的实现与应用。该函数在数值变化后触发,主要用于Instant类GameplayEffect(Duration和Infinite类若设置Period也可触发)。文章详细展示了如何通过该函数修正数值(相比PreAttributeChange能真正修改数值),并演示了血量、蓝量等属性的安全范围控制。同时,定义了FEffectProperties结构体封装GE相关对象,提供了SetEffectProperties方法统一处理施放者和目标的对象引用获取,为后续逻辑处理提供便利。这些实现可用于死亡判定、无敌状态等游戏逻辑处理。

1.PostGameplayEffectExecute

PostGameplayEffectExecute()函数是在数值变化后触发的,一般只会在Instant类型的GameplayEffect才可以触发(Duration和Infinite类的GameplayEffect如果设置Period也可以触发)。

并且,我们还可以在这里面去修正数值,(在PreAttributeChange回调里面,只能修正显示的结果,实际结果没有变)。

这个函数的应用场景很多,我们可以做一些逻辑操作,比如死亡,无敌不扣血等等。

Source/CC_Aura/Public/AbilitySystem/CC_AttributeSet.h:

cpp 复制代码
//属性更改后的方法
	virtual void PostGameplayEffectExecute(const struct FGameplayEffectModCallbackData& Data) override;

Source/CC_Aura/Private/AbilitySystem/CC_AttributeSet.cpp:

cpp 复制代码
void UCC_AttributeSet::PostGameplayEffectExecute(const struct FGameplayEffectModCallbackData& Data)
{
	Super::PostGameplayEffectExecute(Data);
	
	if (Data.EvaluatedData.Attribute == GetHealthAttribute())
	{
		UE_LOG(LogTemp, Warning, TEXT("Health: %f"), GetHealth());
		UE_LOG(LogTemp, Warning, TEXT("Magnitude: %f"), Data.EvaluatedData.Magnitude);
	}
}

2.接下来,我们将从Data中获取到需要的然后封装成一个结构体,方便后续使用。

Source/CC_Aura/Public/AbilitySystem/CC_AttributeSet.h:

cpp 复制代码
// 用于存储施放GE的相关对象和目标的相关对象
USTRUCT()
struct FEffectProperties
{
	GENERATED_BODY()

	FEffectProperties(){}

	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;
};

3.创建私有函数,给FEffectProperties赋值

Source/CC_Aura/Public/AbilitySystem/CC_AttributeSet.h:

cpp 复制代码
private:
	void SetEffectProperties(const struct FGameplayEffectModCallbackData& Data, FEffectProperties& Props) const;

Source/CC_Aura/Private/AbilitySystem/CC_AttributeSet.cpp:

cpp 复制代码
void UCC_AttributeSet::SetEffectProperties(const struct FGameplayEffectModCallbackData& Data, FEffectProperties& Props) const
{
	Props.EffectContextHandle = Data.EffectSpec.GetContext();
	
	//获取效果所有者的相关对象
	Props.SourceASC = Props.EffectContextHandle.GetOriginalInstigatorAbilitySystemComponent();	//获取SourceASC
	if(IsValid(Props.SourceASC) && Props.SourceASC->AbilityActorInfo.IsValid() && Props.SourceASC->AbilityActorInfo->AvatarActor.IsValid())
	{
		Props.SourceAvatarActor = Props.SourceASC->AbilityActorInfo->AvatarActor.Get();			//获取SourceAvatarActor
		Props.SourceController = Props.SourceASC->AbilityActorInfo->PlayerController.Get();		//获取SourceController
		if(Props.SourceController == nullptr && Props.SourceAvatarActor != nullptr)
		{
			if(const APawn* Pawn = Cast<APawn>(Props.SourceAvatarActor))
			{
				Props.SourceController = Pawn->GetController();
			}
		}

		if(Props.SourceController)
		{
			Props.SourceCharacter = Cast<ACharacter>(Props.SourceController->GetPawn());	//获取SourceCharacter
		}
	}

	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);
	}	
}

4.将方法添加到PostGameplayEffectExecute函数里:

cpp 复制代码
void UCC_AttributeSet::PostGameplayEffectExecute(const struct FGameplayEffectModCallbackData& Data)
{
	Super::PostGameplayEffectExecute(Data);
	
	FEffectProperties Props;
	SetEffectProperties(Data, Props);
	
	if(Data.EvaluatedData.Attribute == GetHealthAttribute())
	{
		SetHealth(FMath::Clamp(GetHealth(), 0.f, GetMaxHealth()));
	}

	if(Data.EvaluatedData.Attribute == GetManaAttribute())
	{
		SetMana(FMath::Clamp(GetMana(), 0.f, GetMaxMana()));
	}
	
}
相关推荐
澈2076 小时前
深入浅出C++滑动窗口算法:原理、实现与实战应用详解
数据结构·c++·算法
A.A呐6 小时前
【C++第二十九章】IO流
开发语言·c++
ambition202426 小时前
从暴力搜索到理论最优:一道任务调度问题的完整算法演进历程
c语言·数据结构·c++·算法·贪心算法·深度优先
kebeiovo7 小时前
atomic原子操作实现无锁队列
服务器·c++
Yungoal7 小时前
常见 时间复杂度计算
c++·算法
6Hzlia7 小时前
【Hot 100 刷题计划】 LeetCode 48. 旋转图像 | C++ 矩阵变换题解
c++·leetcode·矩阵
Ricky_Theseus8 小时前
C++右值引用
java·开发语言·c++
吴梓穆8 小时前
UE5 c++ 常用方法
java·c++·ue5
云栖梦泽8 小时前
Linux内核与驱动:9.Linux 驱动 API 封装
linux·c++
Morwit9 小时前
【力扣hot100】 1. 两数之和
数据结构·c++·算法·leetcode·职场和发展