When using the Unreal Gameplay Ability System we have a set of C++ classes at our disposal that makes our lives easier, on of those are the Attribute Sets [ UAttributeSet ]
The best way to understand GAS Attribute Sets is as a container of float values.
This values can represent anything ( Health, MovementSpeed, RemainingAmmo, CooldownDuration... ) whatever we want. And one of the advantages of holding these values in a Gameplay Ability System Attribute Set is that we are able to modify them in a special way using what is called an Aggregator.
As there is not much Gameplay Ability System documentation it might be difficult to get started. The first thing we will need to do is to create a new class in Unreal and inherit from UAttributeSet. This will give us all the functionality we need.
Once we have done that we will be able to start adding the attributes to the set. To do that we will see that we will declare them in a very specific way to allow us to get the full benefits of using them with GAS.
Looking at the AttributeSet.h file Epic recommends creating a macro to make our lives easier so we will do that.
Now we can start declaring our attributes, as an example we will declare a Health attribute as a property inside our HealthAttributeSet.
As you see we mark the attribute as a UPROPERTY, then we declare the attribute with type FGameplayAttributeData and give it a default value. Finally, we use the macro ATTRIBUTE_ACCESSORS that we have previously created with the name of our class and the name of the attribute.
Internally what this macro will do is create setters and getters for us so working with the attribute becomes easier.
We can now add as many attributes as we want the same way, for instance if we wanted to add a MaxHealth attribute the resulting full code would look like this.
There are multiple ways to give an Attribute Set to an actors, but if our actor already has a UAbilitySytemComponent the easiest way is to simply declare the attribute set as a SubObject of that actor.
By doing this the GAS Ability System Component will automatically find the attribute set during initialization so simply by having a subobject of that type everything will work automatically.
That being said, if we want to add attributes in a dynamic way, the Ability System Component also supports other ways of adding the attributes:
The ideal way to modify attributes using the Unreal Gameplay Ability System is to modify them using Gameplay Effects. That being said, this may be out of scope for this article and we will take a look in the future in another article abut GAS Gameplay Effects.
So, how do we modify attributes then without using Gameplay Effects?
We can use some of the accessors we created combined with the API of the Gameplay Ability System Component.
To modify Attribute values we will use the SetNumericAttributeBase function from the ASC.
So if we want to directly set a value we can do it like this:
As we will see in the future this is not the desired way to modify attributes during normal gameplay, but this can be useful to initialize attribute value.
To read the current value an attribute holds we are also gonna do it through the Ability System Component, as you will see it is quite similar.
You can read values of attributes by using the GetNumericAttribute function.
By using this code we can read the value of any attribute any time you want.
You will have seen that in we have used SetNumericAttributeBase call to set the values but GetNumericAttribute to read them. If you look at the Ability System API you will find that a GetNumericAttributeBase exists, so why have we not used that one?
The way that attribute properties hold values is with the use of two float values: BaseValue and CurrentValue.
In GAS Gameplay Effects can be used to modify values but there are different kind of modifications that you can do:
You can modify an attribute permanently: You took damage, your movement speed has been initialized, you have spent ammo from your weapon..
You can modify an attribute temporarily: You get a speed boost, extra damage for 5s, a debuff that halves your health while inside a trigger...
In order to be able to support having temporary values and then returing to the "actual" value, that is why Base Value and Current Value are used.
When something modifies your value permanently what we modify is the BaseValue.
When something applies a temporal modification we modify the CurrentValue.
So that is why in the first case, when we initialized our attributes we used SetNumericAttributeBase, we want to modify the value permanently.
But when we want to read the value we want the current value, with all temporary modifications applied, which is the actual current value of the attribute. So we use GetNumericAttribute without the "Base" part.
This can get confusing, so if you want to get a hang of it since Unreal 5.1 GAS supports the use of the console command AbilitySystem.DebugAttribute
As epic states in its usage info the way to use it is as follows:
Usage: AbilitySystem.DebugAttribute [AttributeName] [AttributeName]...
So in our case we would use AbilitySystem.DebugAttribute Health MaxHealth.
This will display not only the CurrentValue but also the BaseValue, that way we can get an intuition of when one or the other changes.
This has been only an introduction to getting started with using Attribute Sets inside the Unreal Ability System Plugin.
Attributes are an incredibly powerful way to hold data with temporary modifications and can be used for a variety of use cases.
In this example we only created one AttributeSet, but we can have different UAttributeSet to represent Ammo for our weapons, character-specific data or whatever else we need.
In the future we will explore how we can use Gameplay Effects to modify attributes and how that allows us to start creating interesting behaviors.
I hope this articles will hope as another entry point that people can use as a sorts of Gameplay Ability System Documentation.
As always if you have any doubt don't hesitate to contact me, see you in the future.