第5章---GameplayEffect的使用

由于GE拥有丰富的可选项,我们甚至不需要去设置子类,直接用插件的类来创建蓝图GE类就可以了,在这里写下所有的选项对应的功能。

GE结构以及对于部分结构的解释

  • Period

    • Period : 只有当Duration Policy 选项为 Infinite 或 Has Duration 时才出现,输入一个float数据或一个曲线表,表示每x秒出发一次GE效果
    • Execute Periodic Effect on Application : 布尔值,为true则在第0秒时触发一次,为false则不触发
    • Periodic Inhibition Policy : 有3个选项,Never Reset, Reset Period, Execute and Reset Period
  • Overflow

    • Overflow Effects
    • Deny Overflow Application
    • Clear Stack on Overflow
  • Expiration

    • Premature Expiration Effect Classes
    • Routine Expiraction Effect Classes
  • Immunity

    • GrantedApplicationImmunityTags
      • Require Tags
      • Ignore Tags
    • Granted Application Immunity Query
      • Custom Mach Delegate BP
      • Owing Tag Query
      • Effect Tag Query
      • Source Tag Query
      • Modyfing Attribute
      • Effect Source
      • Effect Definition
  • Stacking

    • Stacking Type : 有三个选项,None, Aggregate by Source, Aggregate by Target,None意为不进行堆叠(只要触发了GE就直接应用),Aggregate by Source意为以来源为基准进行堆叠(同一个源头只能对同一个对象同时触发规定个数内的GE),Aggregate by Target意为以对象为基准进行堆叠(同一个对象只能被同时触发规定个数内的GE)
    • Stack Limit Count : 堆叠GE的最大数量
    • Stack Duration Refresh Policy : 有两个选项,Refresh on Successful Application, Never Refresh,Refresh on Successful Application意为在GE成功进入堆叠后重新设置GE持续事件(可以续Buff), Never Refresh意为在GE成功进入堆叠后不刷新GE的持续事件(不可以续Buff)
    • Stack Period Reset Policy : 有两个选项,Refresh on Successful Application, Never Refresh,Refresh on Successful Application意为在GE成功进入堆叠后立即以新的GE为准触发, Never Refresh意为在GE成功进入堆叠后仍然以旧的GE为准进行触发
    • Stack Expiration Policy : 有三个选项,Clear Entire Stack, Remove Single Stack and Refresh Duration, Refresh Duration,Clear Entire Stack意为在GE到期时移除所有的GE堆叠,Remove Single Stack and Refresh Duration意为在GE到期时移除一层堆叠并开始新一轮的触发GE效果(道具的堆叠效果),Refresh Duration意为不对堆叠做任何处理,单纯开始新一轮的触发GE效果
  • Granted Abilities

    • Granted Abilities
  • Gameplay Effect

    • Duration Policy : 有三个选项,Instant, Infinite, Has Duration,选择Instance意为即刻应用GE,Infinite意为永远无限长时间内应用该GE, Has Duration意为在一段时间内应用GE
    • Duration Magnitude : 意为GE的持续时间
      • Magnitude Calculation Type : 有四个选项,Scalable Float, Attribute Based, Custom Calculation Class, SetbyCallse
      • Scalable Float Magnitude : 根据Magnitude Calculation Type进行改变,Scalable Float时填入float数据或数据表格,意为直接使用float内的数据或表格数据,此时float数据为乘数
    • Modifiers
      • 数组
        • Attribute : 指需要改变的Attribute对象
        • Modifier Op : 有Add, Multiply, Divide, Override, Invalid对应加,乘,除,重写(将对应Attribute的BaseValue和CurrentValue都变成指定数值)
        • Modifier Magnitude
          • Magnitude Calculation Type : 有四个选项,Scalable Float, Attribute Based, Custom Calculation Class, SetbyCallse
          • Scalable Float Magnitude : 根据Magnitude Calculation Type进行改变,Scalable Float时填入float数据或数据表格,意为直接使用float内的数据或表格数据,此时float数据为乘数
        • Source Tags
          • Require Tags
          • Ignore Tags
        • Target Tags
          • Require Tags
          • Ignore Tags
      • Executions
        • 数组
          • Calculations Class
          • Conditional Gameplay Effects
      • Conditional Gameplay Effects
  • Application

    • Chance to Apply to Target
    • Application Requirement
  • 显示

    • Require Modifiers Success to Trigger Cues
    • Supress Stacking Cuse
    • Gameplay Cues
    • UIData
  • 标签

    • Gameplay Effect Asset Tag : 与父类相关,不会将其中拥有的Tag赋予给施加GE的Actor的ASC上
      • Combined Tags : Added中提及以及Removed没有提及的所有Tag
      • Added : 添加的Tag
      • Removed : 移除的Tag
    • Granted Tags : 在其中的Tag将会被附加到Actor的ASC上
    • Granted Bloked Ability Tags
    • Ongoing Tag Requirements
    • Application Tag Requirements
    • Removal Tag Requirements
    • Remove Gameplay Effect Query
    • Remove Gameplay Effect with Tags

文件结构

Source

  • Private
    • AbilitySystemComponen
      • RPGAbilitySystemComponent.cpp
      • RPGAttributeSet.cpp
    • Character
      • PGGameCharacterBase.cpp
      • RPGGameEnemy.cpp
      • RPGGamePlayerCharacter.cpp
    • Game
      • RPGGameModeBase.cpp
    • Interaction
      • EnemyInterface.cpp
    • Player
      • RPGPlayerController.cpp
      • RPGPlayerState.cpp
    • Actor
      • RPGEffectActor.cpp
    • UI
      • HUD
        • RPGHUD.cpp
      • WidgetController
        • OverlayWidgetController.cpp
        • RPGWidgetController.cpp
      • Widgets
        • RPGUserWidget.cpp
  • Public
    • AbilitySystemComponent
      • RPGAbilitySystemComponent.h
      • RPGAttributeSet.h
    • Character
      • RPGGameCharacterBase.h
      • RPGGameEnemy.h
      • RPGGamePlayerCharacter.h
    • Game
      • RPGGameModeBase.h
    • Interaction
      • EnemyInterface.h
    • Player
      • RPGPlayerController.h
      • RPGPlayerState.h
    • Actor
      • RPGEffectActor.h
    • UI
      • HUD
        • RPGHUD.h
      • WidgetController
        • OverlayWidgetController.h
        • RPGWidgetController.h
      • Widgets
        • RPGUserWidget.h

文件概述

RPGAttributeSet

.h文件
// Copyright KimiLiu

#pragma once

#include "CoreMinimal.h"
#include "AbilitySystemComponent.h"
#include "AttributeSet.h"
#include "RPGAttributeSet.generated.h"

#define ATTRIBUTE_ACCESSORS(ClassName, PropertyName) \
    GAMEPLAYATTRIBUTE_PROPERTY_GETTER(ClassName, PropertyName) \
    GAMEPLAYATTRIBUTE_VALUE_GETTER(PropertyName) \
    GAMEPLAYATTRIBUTE_VALUE_SETTER(PropertyName) \
    GAMEPLAYATTRIBUTE_VALUE_INITTER(PropertyName)

// 逻辑处理数据结构,在这个结构中能够获取目标ASC以及源头ASC,以及目标对象,源头对象,目标控制器,源头控制器
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;
};

/**
 * AS拥有预测功能(Prediction)能够让多人游戏的客户端在拥有更少的延迟。客户端能够立刻改变自己维护的AS,然后通知服务端,由服务端判定这个更
 *  改是否合法,如果不合法,则服务端拒绝更改AS并通知客户端回滚AS
 */
UCLASS()
class AURA_API URPGAttributeSet : public UAttributeSet
{
    GENERATED_BODY()

public:
    URPGAttributeSet();

    //复制变量时必须重写的函数,用于注册需要复制的变量
    virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;
    
    //在属性被更改前调用,不用来处理逻辑,只用来限制值大小
    virtual void PreAttributeChange(const FGameplayAttribute& Attribute, float& NewValue) override;

    //在属性被更改后调用,用来处理逻辑
    virtual void PostGameplayEffectExecute(const FGameplayEffectModCallbackData& Data) override;

    /**
     * 创建AS属性步骤:
     * 1. 声明FGameplayAttributeData类型变量
     * 2. 用UPROPERTY()宏修饰
     * 3. 如果是多人游戏,需要在宏内声明: ReplicatedUsing = OnRep_属性名,同时声明一个UFUNCTION()方法OnRep_属性名()。当服务端的该属性
     *    值变化时,OnRep_属性名()将会被调用,我们在这个函数内处理变化事件
     * 4. 实现OnRep_属性名()函数,在函数内调用GAMEPLAYATTRIBUTE_REPNOTIFY(URPGAttributeSet, 属性名, 旧属性值)宏,用来保存旧值用于
     *    服务端通知客户端进行回滚
     * 5. 重写GetLifetimeReplicatedProps()函数,在该函数内注册属性
     * 6. 使用ATTRIBUTE_ACCESSORS()宏来初始化value_getter, property_getter, value_setter, initter
     */
    
    UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_Health, Category="Vital Attribute")
    FGameplayAttributeData Health;
    ATTRIBUTE_ACCESSORS(URPGAttributeSet, Health);

    UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_MaxHealth, Category="Vital Attribute")
    FGameplayAttributeData MaxHealth;
    ATTRIBUTE_ACCESSORS(URPGAttributeSet, MaxHealth);
    
    UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_Mana, Category="Vital Attribute")
    FGameplayAttributeData Mana;
    ATTRIBUTE_ACCESSORS(URPGAttributeSet, Mana);

    UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_Mana, Category="Vital Attribute")
    FGameplayAttributeData MaxMana;
    ATTRIBUTE_ACCESSORS(URPGAttributeSet, MaxMana);

    UFUNCTION()
    void OnRep_Health(const FGameplayAttributeData& OldHealth) const;

    UFUNCTION()
    void OnRep_MaxHealth(const FGameplayAttributeData& OldMaxHealth) const ;

    UFUNCTION()
    void OnRep_Mana(const FGameplayAttributeData& OldMana) const;

    UFUNCTION()
    void OnRep_MaxMana(const FGameplayAttributeData& OldMaxMana) const;

private:
    //设置FEffectProperties类数据,Props内有很多信息,参照上面的结构体声明
    void SetEffectProperties(const FGameplayEffectModCallbackData& Data, FEffectProperties& Props) const;
};
.cpp文件
// Copyright KimiLiu


#include "AbilitySytstem/RPGAttributeSet.h"

#include "AbilitySystemBlueprintLibrary.h"
#include "Net/UnrealNetwork.h"
#include "GameplayEffectExtension.h"
#include "GameFramework/Character.h"

URPGAttributeSet::URPGAttributeSet()
{
    InitHealth(50.f);
    InitMaxHealth(100.f);
    InitMana(50.f);
    InitMaxMana(100.f);
}

void URPGAttributeSet::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
    Super::GetLifetimeReplicatedProps(OutLifetimeProps);

    //注册需要复制的属性Health,没有复制条件,不论复制的结果是否等于客户端原有结果,都进行复制调用
    DOREPLIFETIME_CONDITION_NOTIFY(URPGAttributeSet, Health, COND_None, REPNOTIFY_Always);
    DOREPLIFETIME_CONDITION_NOTIFY(URPGAttributeSet, MaxHealth, COND_None, REPNOTIFY_Always);
    DOREPLIFETIME_CONDITION_NOTIFY(URPGAttributeSet, Mana, COND_None, REPNOTIFY_Always);
    DOREPLIFETIME_CONDITION_NOTIFY(URPGAttributeSet, MaxMana, COND_None, REPNOTIFY_Always);
}


void URPGAttributeSet::PreAttributeChange(const FGameplayAttribute& Attribute, float& NewValue)
{
    Super::PreAttributeChange(Attribute, NewValue);

    if (Attribute == GetHealthAttribute())
    {
       NewValue = FMath::Clamp(NewValue, 0.f, GetMaxHealth());
    }
    if (Attribute == GetMaxHealthAttribute())
    {
       
    }
    if (Attribute == GetManaAttribute())
    {
       NewValue = FMath::Clamp(NewValue, 0.f, GetMaxMana());
    }
    if (Attribute == GetMaxManaAttribute())
    {
       
    }
}

void URPGAttributeSet::SetEffectProperties(const FGameplayEffectModCallbackData& Data, FEffectProperties& Props) const
{
    // Source = causer of the effect, Target = target of the effect (owner of this AS)
    // 拿到源头的上下文,上下文内拥有指向ASC的指针
    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();
       // 若ASC组件没有控制器,则从逻辑拥有者那里获取控制器
       if (Props.SourceController == nullptr && Props.SourceAvatarActor != nullptr)
       {
          // Source有可能没有Controller
          if (const APawn* Pawn = Cast<APawn>(Props.SourceAvatarActor))
          {
             Props.SourceAvatarActor = Pawn->GetController();
          }
       }
       // 获取来源角色
       if (Props.SourceController)
       {
          Props.SourceCharacter = Cast<ACharacter>(Props.SourceController->GetPawn());
       }
    }

    // 拿到目标Actor
    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);
    }
}

// Data 很强大,我们可以从中拿到任何我们想拿到的东西,但是得注意是否是空指针,需要做判断
void URPGAttributeSet::PostGameplayEffectExecute(const FGameplayEffectModCallbackData& Data)
{
    Super::PostGameplayEffectExecute(Data);

    // Source = causer of the effect, Target = target of the effect (owner of this AS)

    FEffectProperties Props;
    SetEffectProperties(Data, Props);

    
    
}

void URPGAttributeSet::OnRep_Health(const FGameplayAttributeData& OldHealth) const 
{
    // 当Health属性被调用,此函数被调用,传入OldHealth作为旧值,该旧值将会被保存以免服务端通知客户端该属性需要回滚
    GAMEPLAYATTRIBUTE_REPNOTIFY(URPGAttributeSet, Health, OldHealth);
}

void URPGAttributeSet::OnRep_MaxHealth(const FGameplayAttributeData& OldMaxHealth) const 
{
    GAMEPLAYATTRIBUTE_REPNOTIFY(URPGAttributeSet, Health, OldMaxHealth);
}

void URPGAttributeSet::OnRep_Mana(const FGameplayAttributeData& OldMana) const
{
    GAMEPLAYATTRIBUTE_REPNOTIFY(URPGAttributeSet, Mana, OldMana);
}

void URPGAttributeSet::OnRep_MaxMana(const FGameplayAttributeData& OldMaxMana) const
{
    GAMEPLAYATTRIBUTE_REPNOTIFY(URPGAttributeSet, MaxMana, OldMaxMana);
}

RPGEffectActor

.h文件
// Copyright KimiLiu

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "GameplayEffectTypes.h"
#include "RPGEffectActor.generated.h"

class UAbilitySystemComponent;
class UGameplayEffect;

// GE实施策略
UENUM(BlueprintType)
enum class EEffectApplicationPolicy
{
	ApplyOnOverlap,
	ApplyOnEndOverlap,
	DoNotApply
};

// GE移除策略
UENUM(BlueprintType)
enum class EEffectRemovalPolicy
{
	RemoveOnEndOverlap,
	DoNotRemove
};

UCLASS()
class AURA_API ARPGEffectActor : public AActor
{
	GENERATED_BODY()
	
public:
	ARPGEffectActor(); 

protected:
	virtual void BeginPlay() override;

	// 对目标实施GE
	UFUNCTION(BlueprintCallable)
	void ApplyEffectToTarget(AActor* TargetActor , TSubclassOf<UGameplayEffect> GameplayEffectClass);

	// 自定义重叠开始事件
	UFUNCTION(BlueprintCallable)
	void OnOverlap(AActor* TargetActor);

	// 自定义重叠结束事件
	UFUNCTION(BlueprintCallable)
	void OnEndOverlap(AActor* TargetActor);
	
	// ~ Start GE类型以及GE的调用类型(蓝图内设置)
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category= "Applied Effects")
	TArray<TSubclassOf<UGameplayEffect>> InstantGameplayEffectClasses;

	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category= "Applied Effects")
	EEffectApplicationPolicy InstantEffectApplicationPolicy = EEffectApplicationPolicy::DoNotApply;

	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category= "Applied Effects")
	TArray<TSubclassOf<UGameplayEffect>> DurationGameplayEffectClasses;

	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category= "Applied Effects")
	EEffectApplicationPolicy DurationEffectApplicationPolicy = EEffectApplicationPolicy::DoNotApply;

	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category= "Applied Effects")
	TArray<TSubclassOf<UGameplayEffect>> InfiniteGameplayEffectClasses;

	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category= "Applied Effects")
	EEffectApplicationPolicy InfiniteEffectApplicationPolicy = EEffectApplicationPolicy::DoNotApply;

	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category= "Applied Effects")
	EEffectRemovalPolicy InfiniteEffectRemovalPolicy = EEffectRemovalPolicy::RemoveOnEndOverlap;
	// ~ End GE类型以及GE的调用类型(蓝图内设置)

	TMap<FActiveGameplayEffectHandle, UAbilitySystemComponent*> ActiveEffectHandles;

	// ~ Actor 等级设置
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category= "Applied Effects")
	float ActorLevel = 1.f;

};

.cpp文件
// Copyright KimiLiu


#include "Actor/RPGEffectActor.h"

#include "AbilitySystemComponent.h"
#include "AbilitySystemBlueprintLibrary.h"


// Sets default values
ARPGEffectActor::ARPGEffectActor()
{
	PrimaryActorTick.bCanEverTick = false;

	SetRootComponent(CreateDefaultSubobject<USceneComponent>("SceneRoot"));
}



void ARPGEffectActor::BeginPlay()
{
	Super::BeginPlay();
	
}

void ARPGEffectActor::ApplyEffectToTarget(AActor* TargetActor, TSubclassOf<UGameplayEffect> GameplayEffectClass)
{
	UAbilitySystemComponent* TargetASC = UAbilitySystemBlueprintLibrary::GetAbilitySystemComponent(TargetActor);
	if (TargetASC == nullptr)return;
		
	check(GameplayEffectClass);
	//GameplayEffectContext: GE的背景,例如谁造成了影响(Instigator), 这个GE的目标是谁(TargetActor), GE描述(例如这个GE是火焰效果或是
	//	雷电效果)
	FGameplayEffectContextHandle EffectContextHandle = TargetASC->MakeEffectContext();
	EffectContextHandle.AddSourceObject(this);

	//创造一个FGameplayEffectSpecHandle对象出来
	const FGameplayEffectSpecHandle EffectSpec = TargetASC->MakeOutgoingSpec(
		GameplayEffectClass, ActorLevel, EffectContextHandle);

	//将SpecHandle中的Spec对象传入,同时获取ActiveGameplayEffectHandle用于存储在Map中
	const FActiveGameplayEffectHandle ActiveEffectHandle = TargetASC->ApplyGameplayEffectSpecToSelf(*EffectSpec.Data.Get());

	//如果是Infinite类型的GE,同时会在停止重叠时移除的GE,我们会将其存储起来,等到停止重叠时直接调用函数来移除GE
	if(EffectSpec.Data.Get()->Def.Get()->DurationPolicy == EGameplayEffectDurationType::Infinite&&
		InfiniteEffectRemovalPolicy == EEffectRemovalPolicy::RemoveOnEndOverlap)
	{
		ActiveEffectHandles.Add(ActiveEffectHandle, TargetASC);
	}
	
}

void ARPGEffectActor::OnOverlap(AActor* TargetActor)
{
	if (InstantEffectApplicationPolicy == EEffectApplicationPolicy::ApplyOnOverlap)
	{
		for (const TSubclassOf<UGameplayEffect> InstantGameplayEffectClass : InstantGameplayEffectClasses)
		{
			ApplyEffectToTarget(TargetActor, InstantGameplayEffectClass);
		}
	}
	if (DurationEffectApplicationPolicy == EEffectApplicationPolicy::ApplyOnOverlap)
	{
		for (const TSubclassOf<UGameplayEffect> DurationGameplayEffectClass : DurationGameplayEffectClasses)
		{
			ApplyEffectToTarget(TargetActor, DurationGameplayEffectClass);
		}
	}
	if (InfiniteEffectApplicationPolicy == EEffectApplicationPolicy::ApplyOnOverlap)
	{
		for (const TSubclassOf<UGameplayEffect> InfiniteGameplayEffectClass : InfiniteGameplayEffectClasses)
		{
			ApplyEffectToTarget(TargetActor, InfiniteGameplayEffectClass);
		}
	}
	
}

void ARPGEffectActor::OnEndOverlap(AActor* TargetActor)
{
	if (InstantEffectApplicationPolicy == EEffectApplicationPolicy::ApplyOnEndOverlap)
	{
		for (const TSubclassOf<UGameplayEffect> InstantGameplayEffectClass : InstantGameplayEffectClasses)
		{
			ApplyEffectToTarget(TargetActor, InstantGameplayEffectClass);
		}
	}
	if (DurationEffectApplicationPolicy == EEffectApplicationPolicy::ApplyOnEndOverlap)
	{
		for (const TSubclassOf<UGameplayEffect> DurationGameplayEffectClass : DurationGameplayEffectClasses)
		{
			ApplyEffectToTarget(TargetActor, DurationGameplayEffectClass);
		}
	}
	if (InfiniteEffectApplicationPolicy == EEffectApplicationPolicy::ApplyOnEndOverlap)
	{
		for (const TSubclassOf<UGameplayEffect> InfiniteGameplayEffectClass : InfiniteGameplayEffectClasses)
		{
			ApplyEffectToTarget(TargetActor, InfiniteGameplayEffectClass);
		}
	}
	if (InfiniteEffectRemovalPolicy == EEffectRemovalPolicy::RemoveOnEndOverlap)
	{
		UAbilitySystemComponent* TargetASC = UAbilitySystemBlueprintLibrary::GetAbilitySystemComponent(TargetActor);
		if (!IsValid(TargetASC)) return;

		TArray<FActiveGameplayEffectHandle> HandlesToRemove;

		for (TTuple<FActiveGameplayEffectHandle, UAbilitySystemComponent*> HandlePair : ActiveEffectHandles)
		{
			if (HandlePair.Value == TargetASC)
			{
				TargetASC->RemoveActiveGameplayEffect(HandlePair.Key, 1);
				HandlesToRemove.Add(HandlePair.Key);
			}
		}

		for (FActiveGameplayEffectHandle& Handle : HandlesToRemove)
		{
			ActiveEffectHandles.FindAndRemoveChecked(Handle);
		}
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

楚江_wog1st

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值