虚幻引擎5 GAS开发俯视角RPG游戏 #06-7:无限游戏效果
一. 无限游戏效果策略:
1.添加枚举
Source/CC_Aura/Public/Actor/CC_EffectActor.h:
//效果应用策略枚举
UENUM(BlueprintType)
enum class EEffectApplicationPolicy :uint8 //使用BlueprintType标记的枚举类型目前仅支持uint8作为基础类型。
{ApplyOnOverlap, //重叠时应用ApplyOnEndOverlap, //结束重叠时应用DoNotApply
};//效果移除策略枚举
UENUM(BlueprintType)
enum class EEffectRemovalPolicy :uint8
{RemoveOnEndOverlap, //在结束重叠时移除DoNotRemove
};
赋值:
//给对象添加效果UFUNCTION(BlueprintCallable)void ApplyEffectToTarget(AActor* TargetActor, TSubclassOf<UGameplayEffect> GameplayEffectClass);//即时游戏效果UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Applied Effects")TSubclassOf<UGameplayEffect> InstantGameplayEffectClass;UPROPERTY(EditAnywhere, BlueprintReadOnly, Category="Apply Effects")EEffectApplicationPolicy InstantEffectApplicationPolicy = EEffectApplicationPolicy::DoNotApply;//持续游戏效果UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Applied Effects")TSubclassOf<UGameplayEffect> DurationGameplayEffectClass;UPROPERTY(EditAnywhere, BlueprintReadOnly, Category="Apply Effects")EEffectApplicationPolicy DurationEffectApplicationPolicy = EEffectApplicationPolicy::DoNotApply;//无限游戏效果UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Applied Effects")TSubclassOf<UGameplayEffect> InfiniteGameplayEffectClass;UPROPERTY(EditAnywhere, BlueprintReadOnly, Category="Apply Effects")EEffectApplicationPolicy InfinityEffectApplicationPolicy = EEffectApplicationPolicy::DoNotApply;UPROPERTY(EditAnywhere, BlueprintReadOnly, Category="Apply Effects")EEffectRemovalPolicy InfinityEffectRemovalPolicy = EEffectRemovalPolicy::RemoveOnEndOverlap;
2.添加函数:
//在重叠开始时处理效果的添加删除逻辑UFUNCTION(BlueprintCallable) void OnOverlap(AActor* TargetActor);//在重叠结束时处理效果的添加删除逻辑UFUNCTION(BlueprintCallable) void OnEndOverlap(AActor* TargetActor);
在Source/CC_Aura/Private/Actor/CC_EffectActor.cpp:
void ACC_EffectActor::OnOverlap(AActor* TargetActor)
{//即时效果if (InstantEffectApplicationPolicy == EEffectApplicationPolicy::ApplyOnOverlap){ApplyEffectToTarget(TargetActor, InstantGameplayEffectClass);}//持续效果if (DurationEffectApplicationPolicy == EEffectApplicationPolicy::ApplyOnOverlap){ApplyEffectToTarget(TargetActor, DurationGameplayEffectClass);}//无限效果if (InfinityEffectApplicationPolicy == EEffectApplicationPolicy::ApplyOnOverlap){ApplyEffectToTarget(TargetActor, InfiniteGameplayEffectClass);}
}
3.修改ApplyEffectToTarget函数,当无限效果时,保存效果规格句柄:
void ACC_EffectActor::ApplyEffectToTarget(AActor* TargetActor, TSubclassOf<UGameplayEffect> GameplayEffectClass)
{checkf(GameplayEffectClass, TEXT("%s中:GameplayEffectClass没有设置!!!"), *GetName());//1.获取目标Actor的AbilitySystemComponent组件UAbilitySystemComponent* TargetASC = UAbilitySystemBlueprintLibrary::GetAbilitySystemComponent(TargetActor);if (TargetASC == nullptr) return;//2.创建效果上下文句柄FGameplayEffectContextHandle EffectContextHandle = TargetASC->MakeEffectContext();EffectContextHandle.AddSourceObject(this); //设置效果来源对象为当前EffectActor//3.创建效果规格句柄(Spec)const FGameplayEffectSpecHandle EffectSpecHandle = TargetASC->MakeOutgoingSpec(GameplayEffectClass, 1.f, EffectContextHandle);//4.应用效果const FActiveGameplayEffectHandle ActiveGameplayEffectHandle = TargetASC->ApplyGameplayEffectSpecToSelf(*EffectSpecHandle.Data.Get());//5.如果是无限效果,存储权柄信息const bool bIsInfinite = EffectSpecHandle.Data.Get()->Def.Get()->DurationPolicy == EGameplayEffectDurationType::Infinite;//无限效果 && 结束覆盖时移除if (bIsInfinite && InfinityEffectRemovalPolicy == EEffectRemovalPolicy::RemoveOnEndOverlap){//存储信息ActiveEffectHandles.Add(ActiveGameplayEffectHandle, TargetASC);}
}
4.结束重叠时,触发事件函数:
void ACC_EffectActor::OnEndOverlap(AActor* TargetActor)
{//添加效果if(InstantEffectApplicationPolicy == EEffectApplicationPolicy::ApplyOnEndOverlap){ApplyEffectToTarget(TargetActor, InstantGameplayEffectClass);}if(DurationEffectApplicationPolicy == EEffectApplicationPolicy::ApplyOnEndOverlap){ApplyEffectToTarget(TargetActor, DurationGameplayEffectClass);}if(InfinityEffectApplicationPolicy == EEffectApplicationPolicy::ApplyOnEndOverlap){ApplyEffectToTarget(TargetActor, InfiniteGameplayEffectClass);}//手动结束无限效果if (InfinityEffectRemovalPolicy == EEffectRemovalPolicy::RemoveOnEndOverlap){//1.获取目标Actor的AbilitySystemComponent组件UAbilitySystemComponent* TargetASC = UAbilitySystemBlueprintLibrary::GetAbilitySystemComponent(TargetActor);if (!IsValid(TargetASC)) return;//创建存储需要移除的效果句柄存储Key,用于遍历完成后移除效果TArray<FActiveGameplayEffectHandle> HandlesToRemove;//循环map内存的数据for(TTuple<FActiveGameplayEffectHandle, UAbilitySystemComponent*> HandlePair : ActiveEffectHandles){//判断是否ASC相同if(TargetASC == HandlePair.Value){//通过句柄将效果移除,注意,有可能有多层效果,不能将其它层的效果也移除掉,所以只移除一层TargetASC->RemoveActiveGameplayEffect(HandlePair.Key, 1);//添加到移除列表HandlesToRemove.Add(HandlePair.Key);}}//遍历完成后,在Map中将移除效果的KeyValue删除for(auto& Handle : HandlesToRemove){ActiveEffectHandles.FindAndRemoveChecked(Handle);}}
}
5.在BP_FireArea:
6.火焰效果:
源代码:
Source/CC_Aura/Public/Actor/CC_EffectActor.h:
// 版权归陈超所有#pragma once#include "CoreMinimal.h"
#include "ActiveGameplayEffectHandle.h"
#include "GameFramework/Actor.h"
#include "CC_EffectActor.generated.h"//struct FActiveGameplayEffectHandle;
class UAbilitySystemComponent;
class UGameplayEffect;
class USphereComponent;
class UStaticMeshComponent;//效果应用策略枚举
UENUM(BlueprintType)
enum class EEffectApplicationPolicy :uint8 //使用BlueprintType标记的枚举类型目前仅支持uint8作为基础类型。
{ApplyOnOverlap, //重叠时应用ApplyOnEndOverlap, //结束重叠时应用DoNotApply
};//效果移除策略枚举
UENUM(BlueprintType)
enum class EEffectRemovalPolicy :uint8
{RemoveOnEndOverlap, //在结束重叠时移除DoNotRemove
};UCLASS()
class CC_AURA_API ACC_EffectActor : public AActor
{GENERATED_BODY()public: ACC_EffectActor();protected:virtual void BeginPlay() override;//给对象添加效果UFUNCTION(BlueprintCallable)void ApplyEffectToTarget(AActor* TargetActor, TSubclassOf<UGameplayEffect> GameplayEffectClass);//在重叠开始时处理效果的添加删除逻辑UFUNCTION(BlueprintCallable) void OnOverlap(AActor* TargetActor);//在重叠结束时处理效果的添加删除逻辑UFUNCTION(BlueprintCallable) void OnEndOverlap(AActor* TargetActor);//即时游戏效果UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Applied Effects")TSubclassOf<UGameplayEffect> InstantGameplayEffectClass;UPROPERTY(EditAnywhere, BlueprintReadOnly, Category="Apply Effects")EEffectApplicationPolicy InstantEffectApplicationPolicy = EEffectApplicationPolicy::DoNotApply;//持续游戏效果UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Applied Effects")TSubclassOf<UGameplayEffect> DurationGameplayEffectClass;UPROPERTY(EditAnywhere, BlueprintReadOnly, Category="Apply Effects")EEffectApplicationPolicy DurationEffectApplicationPolicy = EEffectApplicationPolicy::DoNotApply;//无限游戏效果UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Applied Effects")TSubclassOf<UGameplayEffect> InfiniteGameplayEffectClass;UPROPERTY(EditAnywhere, BlueprintReadOnly, Category="Apply Effects")EEffectApplicationPolicy InfinityEffectApplicationPolicy = EEffectApplicationPolicy::DoNotApply; //无限效果应用效果UPROPERTY(EditAnywhere, BlueprintReadOnly, Category="Apply Effects")EEffectRemovalPolicy InfinityEffectRemovalPolicy = EEffectRemovalPolicy::RemoveOnEndOverlap; //无限效果移除策略//用于存储当前已经激活的GameplayEffect的句柄的mapTMap<FActiveGameplayEffectHandle, UAbilitySystemComponent*> ActiveEffectHandles;
};
Source/CC_Aura/Private/Actor/CC_EffectActor.cpp:
// 版权归陈超所有#include "Actor/CC_EffectActor.h"#include "AbilitySystemComponent.h"
#include "AbilitySystemBlueprintLibrary.h"ACC_EffectActor::ACC_EffectActor()
{// 将此参与者设置为每帧调用Tick()。如果你不需要它,你可以关闭它来提高性能。PrimaryActorTick.bCanEverTick = false;SetRootComponent(CreateDefaultSubobject<USceneComponent>("SceneRoot"));
}// 在游戏开始或生成时调用
void ACC_EffectActor::BeginPlay()
{Super::BeginPlay();
}void ACC_EffectActor::ApplyEffectToTarget(AActor* TargetActor, TSubclassOf<UGameplayEffect> GameplayEffectClass)
{checkf(GameplayEffectClass, TEXT("%s中:GameplayEffectClass没有设置!!!"), *GetName());//1.获取目标Actor的AbilitySystemComponent组件UAbilitySystemComponent* TargetASC = UAbilitySystemBlueprintLibrary::GetAbilitySystemComponent(TargetActor);if (TargetASC == nullptr) return;//2.创建效果上下文句柄FGameplayEffectContextHandle EffectContextHandle = TargetASC->MakeEffectContext();EffectContextHandle.AddSourceObject(this); //设置效果来源对象为当前EffectActor//3.创建效果规格句柄(Spec)const FGameplayEffectSpecHandle EffectSpecHandle = TargetASC->MakeOutgoingSpec(GameplayEffectClass, 1.f, EffectContextHandle);//4.应用效果const FActiveGameplayEffectHandle ActiveGameplayEffectHandle = TargetASC->ApplyGameplayEffectSpecToSelf(*EffectSpecHandle.Data.Get());//5.如果是无限效果,存储权柄信息const bool bIsInfinite = EffectSpecHandle.Data.Get()->Def.Get()->DurationPolicy == EGameplayEffectDurationType::Infinite;//无限效果 && 结束覆盖时移除if (bIsInfinite && InfinityEffectRemovalPolicy == EEffectRemovalPolicy::RemoveOnEndOverlap){//存储信息ActiveEffectHandles.Add(ActiveGameplayEffectHandle, TargetASC);}
}void ACC_EffectActor::OnOverlap(AActor* TargetActor)
{//即时效果if (InstantEffectApplicationPolicy == EEffectApplicationPolicy::ApplyOnOverlap){ApplyEffectToTarget(TargetActor, InstantGameplayEffectClass);}//持续效果if (DurationEffectApplicationPolicy == EEffectApplicationPolicy::ApplyOnOverlap){ApplyEffectToTarget(TargetActor, DurationGameplayEffectClass);}//无限效果if (InfinityEffectApplicationPolicy == EEffectApplicationPolicy::ApplyOnOverlap){ApplyEffectToTarget(TargetActor, InfiniteGameplayEffectClass);}
}void ACC_EffectActor::OnEndOverlap(AActor* TargetActor)
{//添加效果if(InstantEffectApplicationPolicy == EEffectApplicationPolicy::ApplyOnEndOverlap){ApplyEffectToTarget(TargetActor, InstantGameplayEffectClass);}if(DurationEffectApplicationPolicy == EEffectApplicationPolicy::ApplyOnEndOverlap){ApplyEffectToTarget(TargetActor, DurationGameplayEffectClass);}if(InfinityEffectApplicationPolicy == EEffectApplicationPolicy::ApplyOnEndOverlap){ApplyEffectToTarget(TargetActor, InfiniteGameplayEffectClass);}//手动结束无限效果if (InfinityEffectRemovalPolicy == EEffectRemovalPolicy::RemoveOnEndOverlap){//1.获取目标Actor的AbilitySystemComponent组件UAbilitySystemComponent* TargetASC = UAbilitySystemBlueprintLibrary::GetAbilitySystemComponent(TargetActor);if (!IsValid(TargetASC)) return;//创建存储需要移除的效果句柄存储Key,用于遍历完成后移除效果TArray<FActiveGameplayEffectHandle> HandlesToRemove;//循环map内存的数据for(TTuple<FActiveGameplayEffectHandle, UAbilitySystemComponent*> HandlePair : ActiveEffectHandles){//判断是否ASC相同if(TargetASC == HandlePair.Value){//通过句柄将效果移除,注意,有可能有多层效果,不能将其它层的效果也移除掉,所以只移除一层TargetASC->RemoveActiveGameplayEffect(HandlePair.Key, 1);//添加到移除列表HandlesToRemove.Add(HandlePair.Key);}}//遍历完成后,在Map中将移除效果的KeyValue删除for(auto& Handle : HandlesToRemove){ActiveEffectHandles.FindAndRemoveChecked(Handle);}}
}