“Damage” is a common concept in games, so I wanted to give a quick primer on the damage functionality we’ve included in the UE4 game framework.
Damage support is a feature of the base Actor class, making it widely available. The system provides easy access to common functionality for quick results, while also being extensible to allow you to customize your damage model when needed. We’ve also made an effort to avoid making assumptions about how to respond to damage, meaning you won’t find any notion of “hit points” or “death” in the engine. These concepts tend to be very game-specific, and we’ve found that attempts to generalize them end up causing more pain than they prevent.
Basic damage-related concepts
There are a few commonly-used concepts we use when talking about damage that I’ll cover quickly.
As the name suggests, a DamageType is an object used to describe the “type” of damage, independent of its origin. This can be a very useful concept if you have many sources of damage and you want common functionality between them.
An easy example to illustrate this would be fire damage. Let’s say you want anyone who takes fire damage to yell “WOW SO HOT” and run to the nearest water. Rather than duplicate code to do this into every actor that can burn the player (or for every type of actor who could be burned), you can define a damage type for fire (UDamageTypeFire), give it some type of HandleDamagedCharacter() function, and call it appropriately from your TakeDamage() call chain.
The Instigator is who caused the damage, typically a PlayerController or an AIController. In the case of fire damage, this might be the player or AI who lit the fire.
The “causer” is usually what caused the damage, such as the ACampFire actor that you just walked through.
Damage in C++
Let’s look first at damage support in native code. In this case, damaging an actor is simple – just call TakeDamage() on it.
virtual float TakeDamage(float DamageAmount, struct FDamageEvent const& DamageEvent, class AController* EventInstigator, class AActor* DamageCauser);
Likewise, to respond to damage, simply override TakeDamage() on the receiving actor and insert your custom handling. Easy!
You’ll notice that the TakeDamage() call accepts a DamageEvent as a parameter. This FDamageEvent data structure contains data about the specific circumstances of the damaging event so that your response code can react appropriately. UE4 comes with 3 flavors of damage event built-in.
“This particular spot on my face hurts because it got hit from that direction.”
A point damage event models damage applied at a specific point on the victim, such as from a bullet or a punch. It contains the direction the hit came from and a FHitResult that describes the surface impact.
“My whole left side hurts because of that big blast over there.”
A radial damage event models radial damage from a point source, the obvious example being from an explosion. It contains the epicenter of the blast, data to describe the damage falloff through space, and a list of affected components.
This is the most generic damage model available, containing only an optional DamageTypeClass.
If none of these built-in events types meets your needs, you can derive your own structure from FDamageEvent and store whatever data you need.
Damage in Blueprints
Dealing with damage in Blueprints is similar, except the damage application and responses are already broken out by event type. There are globally-accessible nodes available to inflict damage, such as ApplyDamage, ApplyPointDamage, and ApplyRadialDamage. To respond to damage events, there is a similar suite of “took damage” events for both actor classes and for actor instances within the level.
If you define custom damage events for your project, you will probably want to expose a similar set of functions and delegates for use in Blueprints.
Happy damaging! And for damage-related inquiries and anecdotes, post below!