Imagine you're building an RPG and you want to define stats for different enemy types like wolves and spiders. You could do this with hierarchical data like this:
UEnemyDataAsset - BP_EnemyBase // Blueprint subclass - BP_WolfBase // Blueprint subclass - BP_SpiderBase
You could define the stats for each enemy type with a simple
TMap<FGameplayTag, int32> and then override the values in child classes.
BP_EnemyBase TMap<FGameplayTag, int32> Stats hp = 10 legs = 2 BP_WolfBase: TMap<FGameplayTag, int32> Stats (Modified) hp = 8 legs = 4 BP_SpiderBase: TMap<FGameplayTag, int32> Stats (Modified) hp = 4 legs = 8
Notice in the example above that the
stats variable has been marked as
BP_SpiderBase, because we changed the number of
legs and hp. Once you have changed the TMap in a child class, any changes
made to the parent will no longer be reflected in the child!
Look what happens if we add a new
vision property to the
property does not appear either child Blueprint.
BP_EnemyBase TMap<FGameplayTag, int32> Stats hp = 10 legs = 2 vision = 5 // NEW! BP_WolfBase: TMap<FGameplayTag, int32> Stats (Modified) hp = 8 legs = 4 // <= No vision! BP_SpiderBase: TMap<FGameplayTag, int32> Stats (Modified) hp = 4 legs = 8 // <= No vision!
How can we make a data structure that lets us:
- Inherit stats defined in the parent.
- Override stats in child classes.
- Allow changes made in the parent to be reflected in children.
Huge thanks to Bohdon Sayre for this one. After
describing my problem he said that
FInheritedTagContainer in the
GameplayAbilities module had a solution for this.
The engine example is a bit more complicated for adding and removing tags, this just allows you to override values and not remove any tags added by the parent. It also works with Data Assets, not just Blueprint subclasses.