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
The Problem
Notice in the example above that the stats
variable has been marked as
modified in BP_WolfBase
and 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 BP_EnemyBase
, 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!
Solution
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.
Inherited Map
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.