Event AnyDamage / Apply Damage¶
At a glance
Lives in: Blueprint API / Game / Damage and Add Event / Game / Damage -
Apply Damage returns: a real number: the damage the target accepted,
usually 0.0 on failure -
Event AnyDamage returns: no value; it starts execution on the damaged
actor -
Network rule: Blueprint damage events are authority-only; put real
health changes on the server -
Official docs: Apply Damage
and Event AnyDamage
The one-minute version¶
Apply Damageis the sender. It says: "tell this actor it took this much generic damage, from this controller, caused by this actor."Event AnyDamageis the receiver. It runs inside the actor that was damaged.- Neither node has health built in. Unreal delivers the damage message. Your Blueprint subtracts health, checks death, plays reactions, and replicates the result if the game is networked.
- The
Apply DamageReturn Value is a number, not the damaged actor. Treat0.0as "no damage was applied" unless your own C++ damage override says otherwise. Instigated Byis aController.Damage Causeris anActor. For a projectile, the instigator is usually the shooter's controller; the causer is the projectile or weapon actor.- In multiplayer,
Event AnyDamageonly fires on the server. A client pressing Fire usually asks the server to apply damage; the server changes health; the replicated health or cosmetic event tells clients what happened.
What it actually does¶
Unreal's built-in damage system is a message pipeline between actors. It is not a health component, hit-point variable, or automatic death system.
The generic flow is:
flowchart LR
Cause[Projectile / hazard / attack graph] --> Apply[Apply Damage]
Apply --> Target[Damaged Actor]
Target --> TakeDamage[Actor TakeDamage path]
TakeDamage --> AnyDamage[Event AnyDamage on target]
AnyDamage --> Health[Your health logic]
In Blueprint terms, Apply Damage packages five pieces of information:
| Pin | Means |
|---|---|
| Damaged Actor | The actor that should receive the damage message. |
| Base Damage | The numeric amount you want to send. |
| Event Instigator | The controller responsible for the damage. |
| Damage Causer | The actor that directly caused it: projectile, trap, sword, explosion actor. |
| Damage Type Class | Optional class data describing what kind of damage this is. If you leave it empty, the generic damage type is used. |
The engine-side shape is roughly:
pseudocode of the engine behavior - not engine source
function ApplyDamage(DamagedActor, BaseDamage, Instigator, Causer, TypeClass):
if DamagedActor is None or BaseDamage is 0:
return 0
DamageEvent = a generic damage event using TypeClass or the default type
return DamagedActor.TakeDamage(BaseDamage, DamageEvent, Instigator, Causer)
function Actor.TakeDamage(Damage, Event, Instigator, Causer):
if this actor cannot currently be damaged:
return 0
broadcast generic damage to Blueprint and delegates
return the amount this actor accepted
For a Blueprint-only actor, that generic broadcast is what reaches
Event AnyDamage. In C++, an actor can override TakeDamage, change the
amount, block it, call Super::TakeDamage, or skip the Blueprint event path if
the override is written that way. That is why the Return Value means "what
the target's damage path accepted", not "what health was subtracted."
When it fails (and what failure does)¶
Apply Damage has no Failed execution pin. The white execution wire continues.
Failure usually looks like a Return Value of 0.0 and no Event AnyDamage on
the target.
Common causes:
- Damaged Actor is
None. Nothing can receive the message. - Base Damage is zero. The generic node does not send a useful damage
event for
0.0. - The target cannot be damaged. The built-in Actor path respects the actor's damage-enabled state before it broadcasts Blueprint damage events.
- You applied damage on the wrong machine. The Blueprint node and
Event AnyDamageare authority-only. If a network client does local damage logic, the server's real health state did not change. - The target's C++ override changed the rules. A native override can
reduce, absorb, redirect, or ignore damage. If it does not call the parent
implementation, Blueprint
Event AnyDamagemay never run.
Failure does not throw an exception, print a guaranteed warning, retry later, create the health variable, or destroy anything. The only automatic output you get from the sender is the numeric Return Value.
What Event AnyDamage gives you¶
Event AnyDamage runs on the actor that took damage and exposes the generic
damage package:
| Pin | Type beginners should remember | Use it for |
|---|---|---|
| Damage | Number | Subtract from health, clamp, scale, or reject. |
| Damage Type | Damage type object | Branch on fire, poison, fall damage, and similar categories if your project uses custom damage types. |
| Instigated By | Controller |
Award score, decide team ownership, or find the pawn that caused the damage. |
| Damage Causer | Actor |
Ignore self-damage, identify the projectile/trap/weapon, spawn impact reactions near the causer. |
The important beginner trap is the controller/actor split. If your projectile was spawned from a character, a clean setup is:
Character Fire
-> Spawn Actor from Class (BP_Projectile)
Instigator = self
Projectile Hit
-> Get Instigator Controller
-> Apply Damage
Damaged Actor = hit actor
Event Instigator = instigator controller
Damage Causer = self projectile
The target's Event AnyDamage can now tell both stories:
- who was responsible: the controller;
- what physically caused it: the projectile actor.
That distinction matters for friendly fire, kill credit, score, and filtering out damage caused by your own projectile.
The pattern everyone actually uses¶
For a first single-player enemy:
Projectile OnHit
-> Break Hit Result
-> Hit Actor
-> Is Valid
-> Apply Damage
Damaged Actor = Hit Actor
Base Damage = 25
Event Instigator = Get Instigator Controller
Damage Causer = self
Enemy Event AnyDamage
-> Health = Clamp(Health - Damage, 0, MaxHealth)
-> Branch Health <= 0
-> Destroy Actor or play death flow
For damage over time, do not Tick every frame unless you need every-frame damage. Use a timer:
BeginOverlap lava volume
-> Set Timer by Event, looping every 1.0 seconds
-> Apply Damage to overlapping actor
EndOverlap
-> Clear and Invalidate Timer by Handle
For multiplayer, keep the same idea but move authority to the server:
Client input or local hit prediction
-> Run on Server event
-> server verifies target/range/team rules
-> server calls Apply Damage
-> target's Event AnyDamage changes replicated Health
Do not rely on Event AnyDamage running on every client. It is a server event.
Clients should see the result through replicated state, a multicast cosmetic
event, or client-side presentation code driven by the server-approved hit.
The C++ twin, for the curious (our own example code):
void ATrainingProjectile::ApplyHitDamage(AActor* HitActor)
{
if (!IsValid(HitActor))
{
return;
}
const float AppliedDamage = UGameplayStatics::ApplyDamage(
HitActor,
DamageAmount,
GetInstigatorController(),
this,
UDamageType::StaticClass());
if (AppliedDamage <= 0.0f)
{
return;
}
Destroy();
}
Lookalikes - which one do I want?¶
| Node or hook | Use when | What it does not do |
|---|---|---|
| Apply Damage | You want simple generic damage to one actor. | It does not include hit location, bone name, radius, or automatic health. |
| Event AnyDamage | This actor needs to react to any generic, point, or radial damage that reaches it. | It does not run on clients in a network game. |
| Apply Point Damage | You have one impact: bullet, melee trace, projectile hit. | It is not for area damage. |
| Event PointDamage | The receiver needs hit location, hit normal, hit component, or bone name. | It is narrower than AnyDamage. |
| Apply Radial Damage | You have an explosion or area hazard. | It is not a simple "damage this one actor" node. |
| Event RadialDamage | The receiver needs radial-damage details. | It is narrower than AnyDamage. |
| On Take Any Damage | Another object wants to bind to this actor's damage delegate. | It is not the normal single Blueprint event override. |
| TakeDamage (C++) | Native code needs to customize how an actor accepts damage. | Blueprint beginners usually use Event AnyDamage instead. |
| Overlap / Hit events | You are detecting contact. | Detection is not damage; you still decide whether to call Apply Damage. |
Rule of thumb: detect contact with overlap, hit, or trace; send the damage with an Apply Damage node; receive it with the matching damage event on the target.
Going deeper¶
- Spawn Actor from Class - how projectile
OwnerandInstigatorsetup starts before damage is applied. - Ownership and lifetime - why damage instigator, actor owner, component owner, and possession are different relationships.
- Possession - why
Instigated Byis a controller, while the pawn is the body that fired or attacked. - Is Valid - guard a target reference before sending damage into it.
- The frame: Tick, timers, and timelines - use timers for periodic damage instead of per-frame polling.
- Official docs: Apply Damage, Event AnyDamage, Apply Point Damage, Apply Radial Damage, On Take Any Damage, and AActor::TakeDamage.
- Engine source (requires engine access - we do not reproduce it here):
UGameplayStatics::ApplyDamage,UGameplayStatics::ApplyPointDamage, andUGameplayStatics::ApplyRadialDamageinEngine/Source/Runtime/Engine/Private/GameplayStatics.cpp;AActor::TakeDamage,AActor::ReceiveAnyDamage, andAActor::OnTakeAnyDamageinEngine/Source/Runtime/Engine/Private/Actor.cpp; declarations inEngine/Source/Runtime/Engine/Classes/GameFramework/Actor.h.