Filtering Gameplay Tags ? No problem

Gameplay tags are a very powerful feature introduced in Unreal Engine and nowadays pretty much everyone makes use of them, be it because of the Gameplay Ability System (GAS) or simply because of the need to categorize things.
Although they’re really powerful, as a project grows in size their number tends to increase by a fair bit and looking for the right tag at some point might take some time.
What not everyone knows is that the “search” can be avoided by simply adding a filter like so:

UPROPERTY(EditAnywhere, BlueprintReadWrite, meta=(Categories="DST.Pawn"), Category = "PawnInfo")
FGameplayTag PawnTag;

Basically the meta=(Categories=”DST.Pawn”) is telling the editor to only show children tags of “DST.Pawn”. Every other tag won’t clutter the tags panel when editing that property.

Cool right? What is even cooler is that you can also do it for functions 🙂


UFUNCTION(BlueprintCallable, BlueprintPure, Category ="DynamicSkillTree")
FDSTPawnInfo GetPawnInfo(UPARAM(meta=(Categories="DST.Pawn"))
FGameplayTag PawnTag);

The above does exactly the same as the previous example and avoids the risk of passing any unwanted tag to the function.

Enjoy!

There are no static virtual functions in UE4 or C++. Is there an alternative?

Sometimes it would be useful to have overridable virtual functions that can be called without having to instantiate a class by declaring the function static. Here is one such scenario: Imagine you have a base class that generates and returns transforms for your enemy units. Your game mode will use that class to generate spawning transforms for all your enemy units. You want to be able to easily create new rules for creating enemy unit transforms in BP, so you implement the function as a BlueprintNativeEvent like so:

UnitSpawnerBase.h

UFUNCTION(BlueprintNativeEvent, Category = "Unit Spawning")

TArray<FTransform> GenerateTransforms();


virtual TArray<FGenome> GenerateTransforms_Implementation();

UnitSpawnerBase.cpp

TArray<FGenome> UUnitSpawner::GenerateTransforms_Implementation()
{
	TArray<FTransforms> GeneratedTransforms;
	//Here we can put some logic that generates the transforms.
	return GeneratedTransforms;
}

Using a virtual BlueprintNativeEvent allows you to generate Blueprint child classes of the UnitSpawnerBase class and override the GenerateTransforms() event to have different rules for finding good spawning locations for your enemy units. This is a handy way to manage and extend the rules to spawn enemy units. You want different enemy spawn rules based on the map, difficulty level, enemy type? Just create new child classes for each!

To run GenerateTransforms() you instantiate the class in your game mode, for example using NewObject(), and then call the function in the instance:

UUnitSpawnerBase* UnitSpawner = NewObject<UnitSpawnerBase>(GetTransientPackage(), ClassToSpawn);

where ClassToSpawn is a TSubclassOf<UnitSpawnerBase> and contains the child BP of UnitSpawnerBase you want to use.

But you don’t really need an actual instance of UnitSpawnerBase, you just want to call its function GenerateTransforms() with the default values of the class.

Normally, you use static functions for functions you want to call without instantiating a class and that can be used anywhere. But you can’t override static functions because you can’t have virtual static functions in C++. Is there a way to access GenerateTransforms() without instantiating UnitSpawnerBase? 

There is! You can access all of UnitSpawnerBase’s variables’ default values and its functions by using its Default Object. The default object is an instance of the class that is automatically generated by UE and contains the default values of the variables and serves as a template to create further instances of the class. This is how you can use it to access virtual functions of a class without creating a new instance of that class:

UUnitSpawnerBase* UnitSpawner = Cast<UUnitSpawnerBase>(ClassToSpawn->GetDefaultObject());

TArray<FTransforms> SpawnTransforms = UnitSpawner->GenerateTransforms();

GenerateTransforms() will then either run the CPP implementation if the BP child class does not contain an override of the event, or it runs the override defined in the BP class. And it doesn’t need to instantiate the class to do that!

You can also use the DefaultObject of a class to access the default values of its variables.