Skip to content

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 Damage is the sender. It says: "tell this actor it took this much generic damage, from this controller, caused by this actor."
  • Event AnyDamage is 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 Damage Return Value is a number, not the damaged actor. Treat 0.0 as "no damage was applied" unless your own C++ damage override says otherwise.
  • Instigated By is a Controller. Damage Causer is an Actor. For a projectile, the instigator is usually the shooter's controller; the causer is the projectile or weapon actor.
  • In multiplayer, Event AnyDamage only 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:

  1. Damaged Actor is None. Nothing can receive the message.
  2. Base Damage is zero. The generic node does not send a useful damage event for 0.0.
  3. The target cannot be damaged. The built-in Actor path respects the actor's damage-enabled state before it broadcasts Blueprint damage events.
  4. You applied damage on the wrong machine. The Blueprint node and Event AnyDamage are authority-only. If a network client does local damage logic, the server's real health state did not change.
  5. 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 AnyDamage may 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 Owner and Instigator setup starts before damage is applied.
  • Ownership and lifetime - why damage instigator, actor owner, component owner, and possession are different relationships.
  • Possession - why Instigated By is 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, and UGameplayStatics::ApplyRadialDamage in Engine/Source/Runtime/Engine/Private/GameplayStatics.cpp; AActor::TakeDamage, AActor::ReceiveAnyDamage, and AActor::OnTakeAnyDamage in Engine/Source/Runtime/Engine/Private/Actor.cpp; declarations in Engine/Source/Runtime/Engine/Classes/GameFramework/Actor.h.