一. 无限游戏效果策略:
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的句柄的map
TMap<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);
}
}
}