Information
I want to create a system where, whenever a bullet hits a target, it calls a Hit function on the StatComponent of the affected Character. This function will apply a GameplayEffect associated with the weapon to modify the health attribute of the specific bone that was hit, provided that the hit is valid.
I need this system to work for multiple enemy types, each with different bone structures. For example, a smaller enemy might have three attributes (main, leg1, and leg2), while a larger enemy could have eight (main, leg1, leg2, torso, head, hand1, hand2, etc.).
I’m explaining this to ensure that my approach aligns with the built-in Gameplay Ability System (GAS) in Unreal Engine. This is the most advanced system I’ve attempted, and I want to make sure I implement it correctly this time.
Thank you for taking the time to read this long message!
Attribute Set
- Setup the maximum number of Attributes but no need to use all of them (customizable system)
UCLASS()
class UEnemyAttributeSet : public UAttributeSet
{
GENERATED_BODY()
public:
UPROPERTY(BlueprintReadOnly, Category = "BoneHealth", ReplicatedUsing = OnRep_BoneHealth0)
FGameplayAttributeData BoneHealth0;
ATTRIBUTE_ACCESSORS(UEnemyAttributeSet, BoneHealth0)
UPROPERTY(BlueprintReadOnly, Category = "BoneHealth", ReplicatedUsing = OnRep_BoneHealth1)
FGameplayAttributeData BoneHealth1;
ATTRIBUTE_ACCESSORS(UEnemyAttributeSet, BoneHealth1)
// Define up to the maximum number of bones
UPROPERTY(BlueprintReadOnly, Category = "BoneHealth", ReplicatedUsing = OnRep_BoneHealth2)
FGameplayAttributeData BoneHealth2;
ATTRIBUTE_ACCESSORS(UEnemyAttributeSet, BoneHealth2)
// ...more attributes as needed...
// Replication functions for each attribute
UFUNCTION()
void OnRep_BoneHealth0(const FGameplayAttributeData& OldBoneHealth0);
UFUNCTION()
void OnRep_BoneHealth1(const FGameplayAttributeData& OldBoneHealth1);
// More OnRep functions for other bone health attributes...
};
Stat Component
UCLASS()
class UGlobalStatComponent : public UActorComponent
{
GENERATED_BODY()
public:
UGlobalStatComponent();
// Player
FGameplayAttribute HealthAttribute;
// Map bone names to GAS attributes for enemies
TMap<FName, FGameplayAttribute> BoneHealthSlotMap;
void InitializeBoneHealthMap(UEnemyAttributeSet* EnemyAttributes, const TArray<FName>& BoneNames);
void ApplyDamageToBone(FName BoneName, float DamageAmount);
};
Initializing on Beginplay all attributes
// Initialize the map for enemy bone health attributes, this function is customizable and works for different amount of enemy bones
void UGlobalStatComponent::InitializeBoneHealthMap(UEnemyAttributeSet* EnemyAttributes, const TArray<FName>& BoneNames)
{
// Example: Map bones to health slots (attributes) dynamically
for (int32 i = 0; i < BoneNames.Num(); ++i)
{
FName BoneName = BoneNames[i];
switch (i)
{
case 0:
BoneHealthSlotMap.Add(BoneName, UEnemyAttributeSet::GetBoneHealth0Attribute());
break;
case 1:
BoneHealthSlotMap.Add(BoneName, UEnemyAttributeSet::GetBoneHealth1Attribute());
break;
case 2:
BoneHealthSlotMap.Add(BoneName, UEnemyAttributeSet::GetBoneHealth2Attribute());
break;
// Map up to the number of predefined attributes...
default:
break;
}
}
}
Example of customizable initialization for different enemies:
// Should be matching with the Skeletal Mesh
BoneNames = { "Head", "LeftArm", "RightArm" };
GlobalStatComponent->InitializeBoneHealthMap(EnemyAttributes, BoneNames);
Apply Damage with the GE
void UGlobalStatComponent::ApplyDamageToBone(FName BoneName, float DamageAmount)
{
if (BoneHealthSlotMap.Contains(BoneName))
{
FGameplayAttribute BoneHealthAttribute = BoneHealthSlotMap[BoneName];
// Get the Ability System Component (ASC) of the owner
UAbilitySystemComponent* ASC = GetOwner()->FindComponentByClass<UAbilitySystemComponent>();
if (ASC)
{
// ASC->ApplyGameplayEffect(...); from a given DataAsset
}
}
}
This system would enable me to utilize GAS to apply effects easily and manipulate bones depending on their health! I need your opinions and insights!