[UE5] Blueprint Interface Basics: Sending Damage to an Enemy and a Crate the Same Way

Created: 2025-12-12Last updated: 2026-09-05

Use a Blueprint Interface to send the same message to an enemy and a crate and reduce their HP. Diagrams cover Target, implementation, and arguments, when to use Cast instead, and how to inspect references in the Reference Viewer.

If what you hit is an enemy, reduce HP. If it is a crate, break it. Line up Casts asking "enemy? crate? tower?" for every new target and you keep adding target kinds to the attacking side.

With a Blueprint Interface you can ask a target "please take this much damage" through the same call. How it reacts is decided by the receiver. It is a mechanism where adding a new target does not add calls on the attacking side.

In this article we actually reduce an enemy's and a crate's HP, then move on to how it differs from Cast and how to inspect references. It is the hands-on for building and using the Interface introduced in choosing among three communication methods.

Cutting the chain that ties you to a specific target and replacing it with a shared call

What You'll Learn

  • The difference between what the Interface decides and what the receiver implements
  • How to reduce an enemy's and a crate's HP through the same Message node
  • Specifying Target, and what happens when you send to an unsupported target
  • When to use Cast, and what the Reference Viewer can confirm

Sponsored

An Interface is a shared request form

An enemy and a crate differ in appearance and role. Even so, standardize the entry point of "take damage" and the attacker can ask both the same way.

The Interface decides that entry point's name and the values it passes. Here we use the name ReceiveWeaponHit and pass a damage amount.

ResponsibilityWhat it decides here
BPI_DamageableA feature called ReceiveWeaponHit taking a float called DamageAmount
Enemy / crateOn receiving ReceiveWeaponHit, reduce its own HP
The attackerSpecify the target and pass 25 through ReceiveWeaponHit

Implementing means writing the actual logic behind that entry point. The Interface is a request form, so it holds neither the HP variable nor the HP-reducing logic. That content goes in the enemy's and crate's Blueprints.

BPI_Damageable defines the shared entry point and argument, while the enemy and crate each implement reducing their own Health

When calling it, you need a destination called Target. Even though you use the same Message node, one call handles the target you specified. It does not reach every nearby enemy and crate at once.

Hands-On: sending 25 damage to an enemy and a crate

We build a small experiment where F sends 25 damage to a designated Actor. Designate the enemy and HP goes 100 → 75; designate the crate and it goes 30 → 5. We confirm that the sending side's graph is the same even when you change the target.

The first Play sends 25 to the enemy, 100 to 75. Switching the target to the crate, the next Play goes 30 to 5

Create a UE5 Third Person template in Blueprint, choosing None if there is a Variant option. Building in a new practice folder keeps it from mixing with same-named Blueprints from other articles. Creating variables and using Get/Set assumes variable basics.

We confirm HP changes with Print String here. We add no attack animation or death effect, and the Actor stays even at 0 HP.

1. Create the request form

Right-click in the content browser → "Blueprints" → "Blueprint Interface" and create BPI_Damageable.

  1. Rename the function it opens with to ReceiveWeaponHit.
  2. Add DamageAmount to that function's Details → Inputs with type Float.
  3. Leave Outputs empty, then Compile and save.

Float is the type for decimals such as 25 or 12.5. DamageAmount is the argument passed when calling, representing "how much HP to reduce this time."

Not being able to place HP-reducing nodes here is correct. The request format now exists, so next we build the receiver's logic.

2. Prepare the enemy and crate Actors

From "Blueprint Class" → "Actor," create BP_Enemy and BP_Crate. Both have Actor as parent and are separate Classes.

SettingBP_EnemyBP_Crate
Part to addStatic MeshStatic Mesh
MeshThe engine's CylinderThe engine's Cube
VariableHealth, FloatHealth, Float
Health's default10030

If you cannot find the meshes, turn on "Show Engine Content" in the asset picker's Settings and use the ones in Engine/BasicShapes. Set the part's location and rotation to 0, Scale to 1, and Simulate Physics off.

Compile after adding the variables and enter Health's default. Save, place both in the level with Actor Scale 1 and centers about 50 cm above the floor. Lining them up somewhere visible from the character you control is enough.

Next, open both Blueprints and choose BPI_Damageable in the add field under "Class Settings" → "Interfaces," then Compile.

You have now declared "this Class supports ReceiveWeaponHit." There is no HP-reducing logic yet, so implement it next.

3. Reduce your own HP by the amount received

Right-click in BP_Enemy's Event Graph and add the Interface's Event ReceiveWeaponHit. Rather than creating a new Custom Event with the same name, choose the event from the Interface you added.

Event ReceiveWeaponHit has a white exec output and a DamageAmount value output. Connect it as follows.

  1. Connect the white exec output to Set Health.
  2. Create a Float subtraction with Get Health on A and the event's DamageAmount on B.
  3. Feed the subtraction result into a Float Max with the other input at 0.
  4. Connect Max's result to Set Health's value.
Get Health into the subtraction's A and the received DamageAmount into B, kept at 0 or above with Max and passed to Set Health

Max is a node returning the larger of two values. Subtracting 25 at 5 HP gives -20, but comparing against 0 and taking the larger stops HP at 0. In this exercise we send only positive damage amounts.

Connect a Print String after Set Health with Duration 10 seconds. Set Append's A to Enemy HP: and B to the updated Get Health converted to String, then pass the result to Print's In String.

From Set Health's exec output to Print. The updated Health becomes a display string via To String and Append

"From Set Health's exec output" in the diagram is a note showing the seam with the previous diagram. To String (Float) turns the number into text and Append concatenates the strings.

Build the same logic in BP_Crate, changing only Append's A to Crate HP: . Compile and save. The enemy and crate each hold their own Health, so damaging the crate never reduces the enemy's HP.

4. Designate a target and send the Message

Create BP_DamageSender with Actor as parent. Since it only sends, no visual parts are needed.

Create a variable TargetActor of type Actor Object Reference with Instance Editable on. Object Reference is a value designating an instance in the level. Rather than a BP_Enemy-specific type, we use the Actor type so the crate is accepted too.

Create a Custom Event SendHit in the Event Graph and connect the following.

  1. From SendHit, connect to an Is Valid with white exec pins.
  2. Put Get TargetActor into Is Valid's Input Object.
  3. Drag from Get TargetActor's blue pin and search for ReceiveWeaponHit (Message) to place it.
  4. Connect Is Valid's success side to the Message's white input and set Damage Amount to 25. Target is Get TargetActor.

Choose the Message node with the envelope icon. There is no need to add the Interface to BP_DamageSender itself. It can be called as long as the receiving enemy and crate implement it.

Is Valid checks whether the target exists and is usable. On the Is Not Valid side, show Target is not set with Print String for 10 seconds so a forgotten destination is obvious.

From SendHit through Is Valid, sending the ReceiveWeaponHit Message to TargetActor, with a Print when the target is unset

Compile, save, and place one BP_DamageSender in the level. In that Actor's Details, set Target Actor to the placed BP_Enemy. Creating the variable alone does not fill in the target.

Finally, with the placed BP_DamageSender still selected, open the Level Blueprint. Right-click → "Create a reference to [name]" and call SendHit from its blue output. Connect the F key's Pressed to SendHit's white input.

Calling SendHit from F's Pressed, with the reference to the placed BP_DamageSender as Target

The F key is this exercise's input, so we receive it in the Level Blueprint. There is no need to change BP_DamageSender's Auto Receive Input.

5. Confirm the same call works with a different target

Compile, save, Play, click the game view, and press F once. Enemy HP: 75 on screen means the 25 you sent reached the enemy.

Stop Play and change the level's BP_DamageSender Target Actor to the placed BP_Crate. Without editing the graph, Play again and press F.

ActionExpected display
Target the enemy, new Play → FEnemy HP: 75
Target the crate, new Play → FCrate HP: 5
Press F again in the same PlayCrate HP: 0
Press F againCrate HP: 0. It never goes negative

Just swapping the target let the same ReceiveWeaponHit invoke logic in different Classes. The sender rewrites neither the enemy's Health nor the crate's Health directly; it only passes a damage amount.

Next, place a plain Cube in the level and set Target Actor to that Cube. Since this Cube has no BPI_Damageable added, pressing F shows no HP. A Message does not invoke logic on a target that does not implement the Interface.

The Cube itself exists, so Is Valid succeeds. You can see that "exists" and "supports that request" are separate checks. Set Target Actor back to the enemy afterwards.

To change the damage amount too, change the Message's 25 to 40 and send to the enemy in a new Play. Going 100 → 60 means the receiver uses the argument rather than a fixed 25. Restore 25 afterwards.

Sponsored

Treat Cast and hard references as separate matters

Cast checks whether the reference you hold can be treated as the specified Class. On success you can use that Class's own variables and functions. It is not logic that spawns a different Actor or turns a crate into an enemy.

In other engines: it is close to C#'s as / is and GDScript's as — "confirm the type and treat it as that type." It is not the same as fetching a part the way GetComponent<T>() does.

If you want to change an enemy-only attack pattern, you do need to treat it as BP_Enemy. But when you only need the shared feature of "take damage," as here, you can ask through an Interface rather than lining up a Cast per target.

There is another, separate matter here: asset dependencies. A dependency is the connection "another asset is required for me to work."

A Blueprint containing Cast To BP_Enemy holds a hard reference to the BP_Enemy Blueprint asset. That is the connection where loading the referencer requires the target too. If BP_Enemy hard-references meshes and sounds in turn, loading chains onward.

So referencing a wide range of enemy and equipment Blueprints you do not currently need can add to loading and memory cost. This is a matter of separating the time to execute one Cast from the cost of loading the referenced assets. You cannot conclude "it is slow because there is a Cast."

With an Interface, the sender can use the shared BPI_Damageable instead of the concrete BP_Enemy. But dependencies do not become zero. There is still the reference to the Interface itself, plus references remaining in other variables and nodes, so confirm with the following method.

Comparing the path referencing the concrete enemy Blueprint against the path referencing the shared Interface. Check the other reference paths too

The difference between hard references and soft references that load on demand is also introduced in asset management basics.

Confirm dependencies with the Reference Viewer

The Reference Viewer is a tool for seeing "which asset uses which." Beyond whether the graph got shorter, it lets you check whether the sender still needs to know the enemy's kind directly.

  1. Compile and save BP_DamageSender.
  2. Right-click that asset in the content browser and open "Reference Viewer."
  3. From BP_DamageSender in the center, check the dependencies on the right.
  4. Look for the reference to BPI_Damageable and see whether a path depends directly on BP_Enemy or BP_Crate.

What you inspect is the BP_DamageSender asset. Opening the whole level also shows references to the enemies and crates placed there, which is a different investigation. The Target Actor assignment here was made on the Sender instance placed in the level.

When converting your own existing graph from a Cast version, keep a screenshot of the before state to compare. Match the "View" reference types, search depth, and display counts, and refresh under the same conditions. Do not mistake lines hidden by a filter for dependencies that disappeared.

If a reference to BP_Enemy remains, look for BP_Enemy-typed variables, other Casts, and nodes that specify a Class. Replacing one spot with a Message does not erase references via other paths.

The Cast version depends directly on BP_Enemy and BP_Crate, while the Interface version only looks at BPI_Damageable

To see a size breakdown, right-click the same asset → "Size Map." It shows the asset's and its dependencies' sizes as a diagram. When comparing, align display conditions such as Disk Size / Memory Size and investigate references taking a large share.

The Reference Viewer's lines show dependencies, and the Size Map shows sizes. Three fewer lines does not tell you how many seconds faster it got. Actual load time is also affected by other reference paths and by assets already loaded. When you want to confirm a speed improvement, measure runs under the same conditions with Unreal Insights or similar.

Where to look when calling it does nothing

SymptomWhere to check
"Target is not set" appearsWhether you assigned a placed Actor to the Sender in the level
The target exists but no HP appearsWhether you added BPI_Damageable to the target's Class Settings
The Interface is already addedWhether the white line from Event ReceiveWeaponHit continues to Set Health and Print
Sending 40 still subtracts only 25Whether the subtraction's B uses the event's DamageAmount
The Message cannot be foundWhether you compiled and saved the BPI, and searched from the Actor's blue reference pin
A different target reactsWhether the Message's Target points at the instance you meant to act on

Since nothing happens on an unsupported target, a missing implementation can be hard to notice from the sending side alone. When unsure, temporarily place a Print right after the receiver's Event ReceiveWeaponHit to first check whether it arrives.

Does Implement Interface returns whether a target supports that Interface. Give it the target's reference in Test Object and BPI_Damageable in Interface and it returns a Boolean. A Boolean is one of two values, True or False.

Checking support with Does Implement Interface and choosing the next step from the result

This is not something you must always insert before a Message. Use it when you want to choose logic based on support, as in "only change aim to supported targets" or "show different guidance when unsupported." Simply sending a request to a supported target is covered by the Message alone.

Sponsored

Bonus: Good to Know Up Front

Connecting to attack collision

We assigned TargetActor by hand here, but in a real attack you pass a Line Trace's Hit Actor, or the Other Actor a bullet overlapped, into the Message's Target. Separating "logic that finds the target" from "logic that asks the found target" lets a sword and a bullet share the same entry point.

The standard Apply Damage and Event AnyDamage can also handle damage. The ReceiveWeaponHit built here is a custom feature for learning Interfaces; it does not automatically call the standard damage event. For hands-on work with the standard feature, go to the health and damage article.

Combining with a health Component

If you use BP_HealthComponent from the health Component article, call the part's ApplyHealthDamage from the Actor's Event ReceiveWeaponHit. Pass your own HealthComponent reference to Target and the received DamageAmount to Damage Amount.

In that case, the Actor-side Health variable and subtraction from this article are replaced by the part's logic. The Interface is the "damage entry point" and the Component handles "storing and computing health." Adding the part does not auto-forward Messages addressed to the Actor.

Interfaces can define return values too

We left Outputs empty here because we only send a request. Give GetInteractionText a Text return value, for example, and each target can return display text such as "Open" or "Inspect." With a return value, the receiver implements the body as a function.

But if the Message's target does not support it, the logic does not run. Do not judge support from the returned value alone; use Does Implement Interface where it matters.

Choose the types the request form actually needs

Make the Interface's input a BP_Enemy-specific reference type and the request form itself has to know that Blueprint. Here a Float damage amount is enough. When you need a reference to a target of any kind, consider the Actor type, and think about whether there is a reason to use a concrete Class.

C++ can also separate entry point from implementation

In C++ you can define a shared entry point with UInterface. There is no need to move to C++ from the start; going to first steps from Blueprint into C++ once the roles are clear in Blueprint is plenty.

Summary: choosing between Cast and Interface

What you want to doHow to choose
Use variables or functions specific to that ClassCast and confirm it can be treated as the specified Class
Ask targets of different kinds for a shared featureStandardize the entry point and passed values with an Interface
Tell several listeners something happenedUse Event Dispatcher registration and notification

As you saw with the enemy and crate, an Interface lets the sender pass a shared request without deciding "whose internals to change and how." When adding a receiver, add the Interface and prepare a reaction appropriate to that Actor.

When inspecting references, do not make reducing the Cast count the goal — confirm whether you are connected to the targets you need. The mechanism for telling several handlers about an occurrence can be tried in the Event Dispatcher article.

Further Reading

Unreal Engine Notes in this section98