GameplayAbilities

A Gameplay Ability is an ingame action that an Actor can own and trigger repeatedly. Common examples include spells, special attacks, or effects triggered by items. This concept is very common in video games, so much so it is often taken for granted, though the processes involved in running an ability are often complex and require specific timing. For example, while coding an attack activation is fairly simple in itself, over the course of a long-term project the complexity of building abilities can explode as you add resource costs, buff or debuff effects to add or remove from players, combo systems, and other details. As such, there are three major considerations involved in how Unreal Engine's Gameplay Ability System is designed.

GameplayAbilities run on the owning client and/or the server depending on the Net Execution Policy but not simulated proxies. The Net Execution Policy determines if a GameplayAbility will be locally predicted. They include default behavior for optional cost and cooldown GameplayEffects. GameplayAbilities use AbilityTasks for actions that happen over time like waiting for an event, waiting for an attribute change, waiting for players to choose a target, or moving a Character with Root Motion Source. Simulated clients will not run GameplayAbilities. Instead, when the server runs the ability, anything that visually needs to play on the simulated proxies (like animation montages) will be replicated or RPC'd through AbilityTasks or GameplayCues for cosmetic things like sounds and particles.

All GameplayAbilities will have their ActivateAbility() function overriden with your gameplay logic. Additional logic can be added to EndAbility() that runs when the GameplayAbility completes or is canceled.

Flowchart of a simple GameplayAbility:

Flowchart of a more complex GameplayAbility:

GASDocumentation

Coordinating an Ability's Execution

An ability must be able to interact with multiple different systems during its execution, with specific timing. These interactions can include:

  1. Activating animation montages.

  2. Taking temporary control of a character's movement.

  3. Triggering visual effects.

  4. Performing overlap or collision events.

  5. Changing characters' stats, either temporarily or permanently.

  6. Increasing or decreasing ingame resources.

  7. Allowing or blocking the activation of other abilities.

  8. Handling cooldowns to restrict ability usage.

  9. Getting interrupted by ingame events.

  10. Canceling other abilities in-progress.

  11. Making major state changes to a character, such as activating a new movement mode.

  12. Responding to input in the middle of other interactions.

  13. Updating UI elements to show ingame status for abilities.

Depending on how an ability works, it could perform any of these interactions at many different points in time while it is active, including in the middle of animations, and some effects may need to persist after the ability itself completes. 

Handling Abilities and Their Execution

A Gameplay Ability is a Blueprint object that is responsible for executing all of an ability's events, including playing animations, triggering effects, fetching attributes from its owner, and displaying visual effects.

Controlling Activation You can Activate Gameplay Abilities through four main methods:

  1. You can activate an Ability explicitly through Blueprint or C++ code using a Gameplay Ability Handle. This is provided by the Ability System Component when an Ability is granted.

  2. Using Gameplay Events. This fires all abilities with a matching Ability Trigger. If you need to abstract your input and decision mechanisms, this method is preferable, as it provides the greatest degree of flexibility.

  3. Using Gameplay Effects with matching tags. This fires all abilities with a matching Ability Trigger. This is the preferred method for triggering abilities off of Gameplay Effects. A typical use case would be a Sleep debuff, which triggers an ability that plays a disabled animation and inhibits other game actions.

  4. Using Input Codes. These are added to the Ability System Component, and when called they will trigger all Abilities that match. This functions similarly to Gameplay Events.

TIP:

Gameplay Abilities can represent a wide array of ingame actions, and are not limited to powers or spells that players explicitly use. Hit reactions, or the above example of a Sleep animation, are good examples.

When you Activate a Gameplay Ability, the system recognizes that ability as being in-progress. It then fires off any code attached to the Activate event, moving through each function and Gameplay Task until you call the Finish function to signal the ability is finished executing. You can attach further code to the On Finished event if you need to do any extra cleanup. You can also Cancel an ability to stop it mid-execution.

Gameplay Abilities use Gameplay Tags to limit execution. All abilities have a list of tags that they add to their owning Actor when they activate, as well as lists of tags that block activation or automatically cancel that ability. While you can manually cancel, block, or allow abilities' execution with your own code, this provides a method that is systemically consistent.

Attribute Sets and Attributes

The Gameplay Ability System interacts with Actors mainly through Attribute Sets, which contain Gameplay Attributes. These are numeric, floating point values that can be used in calculations or modified by Gameplay Abilities. These can be used for any purpose you want, but common use-cases include tracking a character's health or hit points, as well as values for a character's core statistics (such as Strength and Intelligence). While you can use basic variables to represent these values, Gameplay Attributes provide several advantages:

  1. Attribute Sets provide a consistent, reusable group of attributes that you can build systems around.

  2. Gameplay Abilities can access Gameplay Attributes through reflection, making it possible to create simple calculations and effects directly in the Blueprint editor.

  3. Gameplay Attributes track their default value, current value, and maximum value separately, making it easier to create temporary modifications (buffs and debuffs) and persistent effects. Gameplay Attributes also replicate their value to all clients, and are safe for local UI visualizations such as enemy health bars.

For an Actor to use Gameplay Attributes, you must add an Attribute Set to its Ability System Component. After that, the Ability System Component can automatically access the attributes you assigned to the Attribute Set.

Handling Gameplay Effects

The Gameplay Ability System uses Gameplay Effects to apply changes to Actors targeted by Gameplay Abilities. These can be one-shot effects, such as applying damage, or persistent effects, such as ongoing poison damage, buffs, and debuffs. In the case of persistent effects, the Gameplay Effect attaches itself to the target Actor until it is removed, and they can be pre-set to have a limited lifetime before they expire and clean themselves up, undoing any changes to the target Actor's Gameplay Attributes.

Gameplay Effects use Gameplay Effect Calculations to handle calculations based on Gameplay Attributes. While you can create simple calculations directly in the Blueprint editor, you can also program custom Effect Calculations that have more complex logic and affect multiple attributes at a time. These are able to process information from both the owning Actor of the Gameplay Ability and the target Actor, so you can concentrate common calculations into one reusable piece of code.

Taken from : Official Documentation

Console Commands

By default, GAS comes with useful console commands you can use to debug your gameplay

showdebug abilitysystem

showdebug abilitysystem mainly use for opening and closing the gameplay debugger in runtime

AbilitySystem.Debug

AbilitySystem.Debug.NextCategory

AbilitySystem.Debug.NextCategory cycles betwen pages of GAS debugger

The first page shows the CurrentValue of all of your Attributes:

The second page shows all of the Duration and Infinite GameplayEffects on you, their number of stacks, what GameplayTags they give, and what Modifiers they give.

The third page shows all of the GameplayAbilities that have been granted to you, whether they are currently running, whether they are blocked from activating, and the status of currently running AbilityTasks.

AbilitySystem.Debug.NextTarget / AbilitySystem.Debug.PrevTarget

AbilitySystem.Debug.NextTarget / AbilitySystem.Debug.PrevTargetallow you to debug all available AbilitySystemComponent in the world and switch to the next or previous target of said ASC

GASDocumentation

GCCAbilitySystemComponent

What is AbilitySystemComponent?

A component to easily interface with the 3 aspects of the AbilitySystem:

GameplayAbilities:

  • Provides a way to give/assign abilities that can be used (by a player or AI for example)

  • Provides management of instanced abilities (something must hold onto them)

  • Provides replication functionality

  • Ability state must always be replicated on the UGameplayAbility itself, but UAbilitySystemComponent provides RPC replication for the actual activation of abilities

GameplayEffects:

  • Provides an FActiveGameplayEffectsContainer for holding active GameplayEffects

  • Provides methods for applying GameplayEffects to a target or to self

  • wrappers for querying information in FActiveGameplayEffectsContainers (duration, magnitude, etc)

  • Provides methods for clearing/remove GameplayEffects

GameplayAttributes:

  • Provides methods for allocating and initializing attribute sets

  • Provides methods for getting AttributeSets

The Ability System Component (UAbilitySystemComponent) is the bridge between Actors and the Gameplay Ability System. Any Actor that intends to interact with the Gameplay Ability System needs its own Ability System Component, or access to an Ability System Component owned by another Actor. Make sure that your project is set up to use the Gameplay Ability System Pluginbefore attempting to use the Ability System Component. Official Documentation

The AbilitySystemComponent (ASC) is the heart of GAS. It's a UActorComponent (UAbilitySystemComponent) that handles all interactions with the system. Any Actor that wishes to use GameplayAbilities, have Attributes, or receive GameplayEffects must have one ASC attached to them. These objects all live inside of and are managed and replicated by (with the exception of Attributes which are replicated by their AttributeSet) the ASC. Developers are expected but not required to subclass this.

The Actor with the ASC attached to it is referred to as the OwnerActor of the ASC. The physical representation Actor of the ASC is called the AvatarActor. The OwnerActor and the AvatarActor can be the same Actor as in the case of a simple AI minion in a MOBA game. They can also be different Actors as in the case of a player controlled hero in a MOBA game where the OwnerActor is the PlayerState and the AvatarActor is the hero's Character class. Most Actors will have the ASC on themselves. If your Actor will respawn and need persistence of Attributes or GameplayEffects between spawns (like a hero in a MOBA), then the ideal location for the ASC is on the PlayerState.

Note: If your ASC is on your PlayerState, then you will need to increase the NetUpdateFrequency of your PlayerState. It defaults to a very low value on the PlayerState and can cause delays or perceived lag before changes to things like Attributes and GameplayTags happen on the clients. Be sure to enable Adaptive Network Update Frequency, Fortnite uses it.

Both, the OwnerActor and the AvatarActor if different Actors, should implement the IAbilitySystemInterface. This interface has one function that must be overriden, UAbilitySystemComponent* GetAbilitySystemComponent() const, which returns a pointer to its ASC. ASCs interact with each other internally to the system by looking for this interface function.

The ASC holds its current active GameplayEffects in FActiveGameplayEffectsContainer ActiveGameplayEffects.

The ASC holds its granted Gameplay Abilities in FGameplayAbilitySpecContainer ActivatableAbilities. Any time that you plan to iterate over ActivatableAbilities.Items, be sure to add ABILITYLIST_SCOPE_LOCK(); above your loop to lock the list from changing (due to removing an ability). Every ABILITYLIST_SCOPE_LOCK(); in scope increments AbilityScopeLockCount and then decrements when it falls out of scope. Do not try to remove an ability inside the scope of ABILITYLIST_SCOPE_LOCK(); (the clear ability functions check AbilityScopeLockCount internally to prevent removing abilities if the list is locked). GASDocumentation

Basic Requirements

To set up your AActor subclass to use the Gameplay Ability System, implement the IAbilitySystemInterface interface and override the GetAbilitySystemComponent function. This function must return the Ability System Component associated with your Actor. In most cases, the Actor class will have a variable, tagged with UPROPERTY, that stores a pointer to the Ability System Component, similar to any built-in Component on any Actor type. While it is common for an Actor to have its own Ability System Component, there are cases in which you might want an Actor, such as a player's Pawn or Character, to use an Ability System Component owned by another Actor, like a Player State or Player Controller. Reasons for this may include things like a player's score, or long-lasting ability cooldown timers that do not reset when the player's Pawn or Character is destroyed and respawned, or when the player possesses a new Pawn or Character. The Gameplay Ability System supports this behavior; to implement it, write the Actor's GetAbilitySystemComponent function so that it returns the Ability System Component you want to use. Official Documentation

So, What does AbilitySystemComponent do in CommonGAS?

Our ASC is mainly handling the initialization for the GCCPawnExtensionComponent and relationship of AbilityTagRelationshipMapping.

C++ API:

NameFunctionality

GetActiveAbilitiesWithTags

Returns a list of currently active ability instances that match the tags

GetAbilitySystemComponentFromActor

Version of function in AbilitySystemGlobals that returns correct type

AbilityInputTagPressed

AbilityInputTagReleased

ProcessAbilityInput

ClearAbilityInput

SetTagRelationshipMapping

Sets the current tag relationship mapping, if null it will clear it out

GetAdditionalActivationTagRequirements

Looks at ability tags and gathers additional required and blocking tags

GCCGameplayAbility

Class Defaults

Map of gameplay tags to gameplay effect containers and Boolean check if an ability to be granted on granted

Name

Effect Container Map

An array of CommonEffectContainer reference

Activation Policy

Defines how an ability is meant to activate.

Activation Group

Defines how an ability activates in relation to other abilities.

GCCAbilitySet

What is Ability Set?

Gameplay Ability Sets allow you define a set of abilities and effects which are given to the target ASC, I use these to apply the default generic abilities a player has, and default generic effects each player will have. These can also be used for things like perks, etc. The other benefit is, they can be added and removed via a simple handle.

Taken from: thegames.dev

What does Ability Set do?

In Lyra Game Sample, the ability set is being used to apply what default abilities, default attribute sets and default gameplay effects a character will have on startup. Their method of granting this to the owned character by using ULyraExperienceDefinition, ULyraPawnData, UGameFeatureAction_AddAbilities and ULyraEquipmentDefinitions Official Documentation

How does Common GAS apply the ability set?

In c++, you can get a reference to UGCCAbilitySet and calling GiveToAbilitySystem() where you need to give it a valid UAbilitySystemComponent reference so it can add it to

UPROPERTY(ReplicatedUsing=OnRep_ActivateAbilities, BlueprintReadOnly, Category = "Abilities")
FGameplayAbilitySpecContainer ActivatableAbilities;

for Default Character Abilities, Default Gameplay Effects will be added to FActiveGameplayEffectHandle and Default Attribute Set will be added using AbilitySystemComponent's AddAttributeSetSubobject()

NameFunctionality

Granted Gameplay Abilities

Gameplay abilities to grant when this ability set is granted.

Granted Gameplay Effects

Gameplay effects to grant when this ability set is granted.

Granted Attributes

Attribute sets to grant when this ability set is granted.o be applied on startup

GCCAbilityTagRelationshipMapping

What is AbilityTagRelationshipMapping?

UAbilityTagRelationshipMapping is a UDataAsset that managed mapping of how ability tags block or cancel other abilities. Without using AbilityTagRelationshipMapping, you have to make your own system by using and overriding UAbilitySystemComponent's


virtual void ApplyAbilityBlockAndCancelTags(const FGameplayTagContainer& AbilityTags, UGameplayAbility* RequestingAbility, bool bEnableBlockTags, const FGameplayTagContainer& BlockTags, bool bExecuteCancelTags, const FGameplayTagContainer& CancelTags) override;

and UGameplayAbility 's


virtual bool DoesAbilitySatisfyTagRequirements(const UAbilitySystemComponent& AbilitySystemComponent, const FGameplayTagContainer* SourceTags, const FGameplayTagContainer* TargetTags, FGameplayTagContainer* OptionalRelevantTags) const override;

How do we use AbilityTagRelationshipMapping in CommonGAS?

In CommonGAS, you have to make your own AbilityTagRelationshipMapping set and filling all of gameplay tag interactions required for you game

To do this, you need to find Miscellaneous-DataAsset and choose UGCCAbilityTagRelationshipMapping. After that, you will be greet with this:

Properties

NameFunctionality

AbilityTag

The tag that this container relationship is about. Single tag, but abilities can have multiple of these

AbilityTagsToBlock

The other ability tags that will be blocked by any ability using this tag

AbilityTagsToCancel

The other ability tags that will be canceled by any ability using this tag

ActivationRequiredTags

If an ability has the tag, this is implicitly added to the activation required tags of the ability

ActivationBlockedTags

If an ability has the tag, this is implicitly added to the activation blocked tags of the ability

GCCGameplayTags

What is Native Gameplay Tag?

Native tag is a way for add/use Gameplay Tags inside C++ and Blueprint and there are many ways you can do this. Unreal Engine has a very nice base struct we can utilize for this purpose, and we can make our own derived struct to handle these tags and provide nice C++ accessors Source Code:

Holds a gameplay tag that was registered during static construction of the module, and will
be unregistered when the module unloads.  Each registration is based on the native tag pointer
so even if two modules register the same tag and one is unloaded, the tag will still be registered
by the other one.

How to Use Native Gameplay Tag?

NativeGameplayTag.h provides these useful definitions:

namespace UE::GameplayTags::Private
{
    // Used to prevent people from putting UE_DEFINE_GAMEPLAY_TAG_STATIC and UE_DEFINE_GAMEPLAY_TAG in their headers.
    constexpr bool HasFileExtension(const char* File)
    {
        const char* It = File;
        while (*It)
            ++It;
        return It[-1] == 'p' && It[-2] == 'p' && It[-3] == 'c' && It[-4] == '.';
    }
}

/**
 * Declares a native gameplay tag that is defined in a cpp with UE_DEFINE_GAMEPLAY_TAG to allow other modules or code to use the created tag variable.
 */
#define UE_DECLARE_GAMEPLAY_TAG_EXTERN(TagName) extern FNativeGameplayTag TagName;

/**
 * Defines a native gameplay tag with a comment that is externally declared in a header to allow other modules or code to use the created tag variable.
 */
#define UE_DEFINE_GAMEPLAY_TAG_COMMENT(TagName, Tag, Comment) FNativeGameplayTag TagName(UE_PLUGIN_NAME, UE_MODULE_NAME, Tag, TEXT(Comment), ENativeGameplayTagToken::PRIVATE_USE_MACRO_INSTEAD); static_assert(UE::GameplayTags::Private::HasFileExtension(__FILE__), "UE_DEFINE_GAMEPLAY_TAG_COMMENT can only be used in .cpp files, if you're trying to share tags across modules, use UE_DECLARE_GAMEPLAY_TAG_EXTERN in the public header, and UE_DEFINE_GAMEPLAY_TAG_COMMENT in the private .cpp");

/**
 * Defines a native gameplay tag with no comment that is externally declared in a header to allow other modules or code to use the created tag variable.
 */
#define UE_DEFINE_GAMEPLAY_TAG(TagName, Tag) FNativeGameplayTag TagName(UE_PLUGIN_NAME, UE_MODULE_NAME, Tag, TEXT(""), ENativeGameplayTagToken::PRIVATE_USE_MACRO_INSTEAD); static_assert(UE::GameplayTags::Private::HasFileExtension(__FILE__), "UE_DEFINE_GAMEPLAY_TAG can only be used in .cpp files, if you're trying to share tags across modules, use UE_DECLARE_GAMEPLAY_TAG_EXTERN in the public header, and UE_DEFINE_GAMEPLAY_TAG in the private .cpp");

/**
 * Defines a native gameplay tag such that it's only available to the cpp file you define it in.
 */
#define UE_DEFINE_GAMEPLAY_TAG_STATIC(TagName, Tag) static FNativeGameplayTag TagName(UE_PLUGIN_NAME, UE_MODULE_NAME, Tag, TEXT(""), ENativeGameplayTagToken::PRIVATE_USE_MACRO_INSTEAD); static_assert(UE::GameplayTags::Private::HasFileExtension(__FILE__), "UE_DEFINE_GAMEPLAY_TAG_STATIC can only be used in .cpp files, if you're trying to share tags across modules, use UE_DECLARE_GAMEPLAY_TAG_EXTERN in the public header, and UE_DEFINE_GAMEPLAY_TAG in the private .cpp");

First, you need to add GCCGameplayTags.h in your include. There a two ways to use this,

  1. The first way is by using UE::GameplayTags::Private. Using the namespace way, you dont have to declare and putting UE_DEFINE_GAMEPLAY_TAG_STATIC and UE_DEFINE_GAMEPLAY_TAG in the header. In the future, we will use this namespace way of using native gameplay tag instead of the struct way as to it is way convenient.

  2. The second way is using UE_DEFINE_GAMEPLAY_TAG_STATIC and UE_DEFINE_GAMEPLAY_TAG.

UE_DEFINE_GAMEPLAY_TAG_STATIC is only to be use inside .cpp files and can only be use in that file. In my game, i use this static tag for defining movement blocking tag inside my UGameplayAbility class and my UCharacterMovementComponent class to block any movement related abilities.

Code:

UE_DEFINE_GAMEPLAY_TAG_STATIC(Static_Movement_Blocked, "Ability.Movement.Blocked");

UOuranosGameplayAbility::UOuranosGameplayAbility()
{
    ActivationBlockedTags.AddTag(Static_Movement_Blocked);
}

For UE_DEFINE_GAMEPLAY_TAG, you have to declare it in both header and cpp file. In CommonGAS, we use this for the built-in relationship blocking and canceling system of the AbilityTagRelationshipMaspping

You need to declare UE_DECLARE_GAMEPLAY_TAG_EXTERN(TAG_Gameplay_AbilityInputBlocked); in you header file:

Then, you need to declare UE_DEFINE_GAMEPLAY_TAG(TAG_Gameplay_AbilityInputBlocked, "Gameplay.AbilityInputBlocked"); in you cpp file:

Usage:

so, thats how we can use native tag. Right now, CommonGAS is using struct way of using native tag but in the future, we will moving to using namespace way of using native tag. :)

Last updated