I once had to solve the same problem for very similar reasons, so let me share the solution that I’ve been using ever since.
First - no, there is no way to have gameplay tag constants because gameplay tags aren’t known at compile time. They’re read from config files so the engine only knows about them after those files have been processed at game startup. Trying to define a const FGameplayTag
variable will just result in an empty tag.
What you can do instead is declaring gameplay tag variables and filling them with the actual values at a convenient time. See also the handy game flow chart in the docs. I decided to do that in UGameInstance::Init()
, there’s probably tons of other valid ways.
Here is an example from an actual game:
// AbilityTag.h
// ability tags are tags that identify gameplay abilities;
// the 'tag' tag is the tag that holds the parent in order
// to have a catch-all tag when needed
struct FAbilityTag
{
static FGameplayTag Tag;
static FGameplayTag GetDown;
static FGameplayTag GetUp;
static FGameplayTag PickUp;
static FGameplayTag Talk;
...
};
// UCustomGameInstance.cpp
FGameplayTag FAbilityTag::Tag;
FGameplayTag FAbilityTag::GetDown;
FGameplayTag FAbilityTag::GetUp;
FGameplayTag FAbilityTag::PickUp;
FGameplayTag FAbilityTag::Talk;
...
void UCustomGameInstance::Init()
{
Super::Init();
FAbilityTag::Tag = FGameplayTag::RequestGameplayTag(TEXT("Ability"));
FAbilityTag::GetDown = FGameplayTag::RequestGameplayTag(TEXT("Ability.Posture.Down"));
FAbilityTag::GetUp = FGameplayTag::RequestGameplayTag(TEXT("Ability.Posture.Up"));
FAbilityTag::PickUp = FGameplayTag::RequestGameplayTag(TEXT("Ability.PickUp"));
FAbilityTag::Talk = FGameplayTag::RequestGameplayTag(TEXT("Ability.Talk"));
...
}
With this setup you can make use of the static variables anywhere in the code, like so:
if (Ability->AbilityTags.First() == FAbilityTag::GetDown)
{
something something
}
If you decide to change a tag name, there’s no hunting it down throughout the code base. Just the .INI file and the game instance and you’re done.
If you want to extend this method to Blueprint, you have to do a little more work, though. Blueprint doesn’t support static UPROPERTY variables, so you can’t just declare
UPROPERTY(BlueprintReadOnly)
static FGameplayTag MyImportantTag;
What you have to do is create something like a UGameplayTagProvider
class as a singleton that you can call from Blueprint. The tags can then be declared as regular UPROPERTYs and called from BP.