GameplayAbilities API – implementing buffs with GameplayEffect

2021/01 02 14:01

A buff is just an effect that introduces a temporary, permanent, or recurring change to a game unit’s attributes from its AttributeSet. Buffs can either be good or bad, supplying either bonuses or penalties. For example, you might have a hex buff that slows a unit to half speed, an angel wing buff that increases unit speed by 2x, or a cherub buff that recovers 5 hp every 5 seconds for 3 minutes. A GameplayEffect affects an individual gameplay attribute in the UAttributeSet that’s attached to an AbilitySystemComponent of an Actor.

Getting ready

Brainstorm your game units’ effects that happen during the game. Be sure that you’ve created an AttributeSet, as shown in the previous recipe, with gameplay attributes that you’d like to affect. Select an effect to implement and follow the succeeding steps with your example.You may want to turn LogAbilitySystem into a VeryVerbose setting by going to the Output Log and typing `, and then Log LogAbilitySystem All. This will display much more information from AbilitySystem in the Output Log, making it easier to see what’s going on within the system.

How to do it…

In the following steps, we’ll construct a quick GameplayEffect that heals 50 hp to the selected unit’s AttributeSet:

  1. Open up the Warrior.h file we created previously. In there, add the following function definition:
void TestGameplayEffect();
  1. Afterwards, open up Warrior.cpp and add the following methods:
inline UGameplayEffect* ConstructGameplayEffect(FString name)
{
return NewObject<UGameplayEffect>(GetTransientPackage(), FName(*name));
}

inline FGameplayModifierInfo& AddModifier(
UGameplayEffect* Effect, UProperty* Property,
EGameplayModOp::Type Op,
const FGameplayEffectModifierMagnitude& Magnitude)
{
int32 index = Effect->Modifiers.Num();
Effect->Modifiers.SetNum(index + 1);
FGameplayModifierInfo& Info = Effect->Modifiers[index];
Info.ModifierMagnitude = Magnitude;
Info.ModifierOp = Op;
Info.Attribute.SetUProperty(Property);
return Info;
}
  1. Then, add the following code to implement:
void AWarrior::TestGameplayEffect()
{
// Construct & retrieve UProperty to affect
UGameplayEffect* RecoverHP = ConstructGameplayEffect("RecoverHP");

// Compile-time checked retrieval of Hp UPROPERTY()
// from our UGameUnitAttributeSet class (listed in
// UGameUnitAttributeSet.h)
UProperty* hpProperty = FindFieldChecked<UProperty>(
UGameUnitAttributeSet::StaticClass(),
GET_MEMBER_NAME_CHECKED(UGameUnitAttributeSet, Hp));

}
  1. Use the AddModifier function to change the Hp field of GameUnitAttributeSet, as follows:
  // Command the addition of +5 HP to the hpProperty
AddModifier(RecoverHP, hpProperty, EGameplayModOp::Additive, FScalableFloat(50.f));
  1. Fill in the other properties of GameplayEffect, including fields such as DurationPolicy and ChanceToApplyToTarget, or any other fields that you’d like to modify, as follows:
// .. for a fixed-duration of 10 seconds ..
RecoverHP->DurationPolicy = EGameplayEffectDurationType::HasDuration;
RecoverHP->DurationMagnitude = FScalableFloat(10.f);

// .. with 100% chance of success ..
RecoverHP->ChanceToApplyToTarget = 1.f;

// .. with recurrency (Period) of 0.5 seconds
RecoverHP->Period = 0.5f;
  1. Apply the effect to an AbilitySystemComponent of your choice. The underlying UAttributeSet will be affected and modified by your call, as shown in the following piece of code:
FActiveGameplayEffectHandle recoverHpEffectHandle =
AbilitySystemComponent->ApplyGameplayEffectToTarget(
RecoverHP, AbilitySystemComponent, 1.f);

How it works…

GameplayEffects are simply little objects that effect changes to an actor’s AttributeSet. GameplayEffects can occur once, or repeatedly, in intervals over a Period. You can program-in effects pretty quickly, and the GameplayEffect class creation is intended to be inline.

There’s more…

Once the GameplayEffect is active, you will receive an FActiveGameplayEffectHandle. You can use this handle to attach a function delegate to run when the effect is over using the OnRemovedDelegate member of the FActiveGameplayEffectHandle. For example, you might call the following code:

FOnActiveGameplayEffectRemoved* ep = AbilitySystemComponent->
OnGameplayEffectRemovedDelegate(recoverHpEffectHandle);

if (ep)
{
ep->AddLambda([]()
{
UE_LOG(LogTemp, Warning, TEXT("Recover effect has been removed."), 1);
});
}