Damage Types and Abilities


The Problem: I want to burn these Demons, but I can't

This week I chose to focus on implementing damage types and abilities. I started with damage types because I figured I could just use Unreal's built-in damage types with their damage system. The way it works is when applying damage, you pass a TSubclassOf<UDamageType> class to the ApplyDamage() function, Then in the characters OnTakeAnyDamage event, we do what we want with the damage information that was passed. The problem is that the damage type is passed as a const UDamageType so I was unable to get the actual damage type that was passed.

My other issue was figuring out how I am going to implement abilities. Each of the abilities we want to implement are different enough that I couldn't just make a single ability object and change some property values on them for each ability. They each have different functionalities so I couldn't do that. We also want abilities tied to weapons meaning that each weapon has an ability that comes with it and can be activated by the player. This meant that I needed a way for the player to activate the ability on the weapon.


The Solution: Create Own damage system and ability system

To solve my dilemma with damage types, I decided to just create our own damage system. I tried a few approaches to make UE's system work but I couldn't get it right. I tried casting to the damage type I wanted but that meant I had to make assumptions and I couldn't think of a way that would work. Another approach was to use an interface but that didn't work the way I wanted either because I still had to make assumptions. My solution was to make a delegate signature in the base character class, that will take an enum value for the damage type. I can then subscribe a function to it in the component that we are using to handle health and other attributes. Other objects will be able to call a static ApplyDamage() function which sets everything in motion.

---------BaseCharacter class--------- 
DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_FiveParams(FTakeDefaultDamageSignature, ABaseCharacter, OnTakeDefaultDamage, AActor*, DamagedActor, float, Damage, EDamageTypes, DamageType, class AController*, InstigatedBy, AActor*, DamageCauser);  
...  
/* The delegate */ 
FTakeDefaultDamageSignature OnTakeDefaultDamage;  
...  
/* the function used to broadcast the delegate */ 
float TakeDefaultDamage(AActor* DamagedActor, float Damage, EDamageTypes DamageType, class AController* InstigatedBy, AActor* DamageCauser);  
---------Static function class--------- 
/* this calls the TakeDefaultDamage function on the ABaseCharacter that is passed in */ 
static float ApplyDamage_(ABaseCharacter* DamagedCharacter, float BaseDamage, AController* EventInstigator, AActor* DamageCauser, TSubclassOf<UDamageType> DamageTypeClass, EDamageTypes DamageType);  
---------Attributes Component--------- 
void BeginPlay() 
{     
    ...     
    // Subscribe the function to the delegate     
    character->OnTakeDefaultDamage.AddDynamic(this, &UAttributes::OnTakeDefaultDamage);     
    ... 
}

Then in the OnTakeDefaultDamage() function, there is a switch statement that handles the different damage types that can be passed in. Looking back, I probably could've figured out how to make UE's damage types work with interfaces, but I didn't want to spend too much time on it given there were still other features we wanted to be implemented, so I chose to move on.

My solution to Abilities was to make our own stripped-down, simple version of UE4's ability system. First, I created an abstract base class for the ability that just had a few functions that all the abilities will use, such as ExecuteAbility(), as well as some properties like the description of the ability. Each ability would inherit from this base class and define the functions and properties as needed. The weapon would then have a TSubclassOf<UAbility> property to set the ability of that weapon. I then decided to create an ability component to attach to the characters. This component would be used to activate the ability with a function that takes the ability as a parameter and calls the ExecuteAbility() on the ability. I chose not to use UE4's ability system, again, because of time constraints. I felt I didn't have the time to learn it especially since there isn't a lot of documentation on it anyways. I was only able to get the foundation for abilities done this week and wasn't able to actually implement any of the abilities, but that is what I will be working on this coming week.

Get Lucifer's Hordes

Leave a comment

Log in with itch.io to leave a comment.