Cast, Interface, or Dispatcher?¶
Blueprint communication gets easier when you separate two questions: how do I get the object, and what kind of relationship should this call create?
The one-minute version¶
- First solve the reference problem. Casts, interfaces, and dispatchers do not magically find actors.
- Use a direct function call when you already have a variable typed as the object you mean to talk to.
- Use Cast To X when you have a broad reference and honestly need one specific class's variables or functions.
- Use a Blueprint Interface when you have one target object and only care
whether it supports a shared contract, such as
Interact. - Use an Event Dispatcher when one object says "this happened" and zero, one, or many listeners may react.
- Coupling is different for each tool: casts name concrete classes, interfaces name a contract asset, and dispatchers make listeners depend on the broadcaster instead of the broadcaster depending on listeners.
The decision rule¶
Start here:
1. Do I have a real object reference?
No -> solve that first: overlap, trace, spawn return value, owner,
controller, editable variable, widget owner, saved variable, etc.
Yes -> continue.
2. Do I need members from one known class?
Yes -> direct typed call, or Cast To that class if the pin is broad.
No -> continue.
3. Do I have one target that should answer a shared verb?
Yes -> Blueprint Interface.
No -> continue.
4. Am I announcing a state change to whoever cares?
Yes -> Event Dispatcher.
flowchart TD
Ref[Do you have an object reference?] -->|No| Find[Get the reference first]
Ref -->|Yes| Known{Need one known class?}
Known -->|Yes| Cast[Direct call or Cast To X]
Known -->|No| Contract{One target, shared contract?}
Contract -->|Yes| Interface[Blueprint Interface]
Contract -->|No| Broadcast{Unknown or many listeners?}
Broadcast -->|Yes| Dispatcher[Event Dispatcher]
Broadcast -->|No| Simpler[Use the simpler direct relationship]
That last box matters. Many beginner graphs use a dispatcher because it sounds advanced when a direct function call would be clearer. Complexity is a cost even when the node is powerful.
Reference first, communication second¶
These tools answer "how do I talk once I have a target?" They do not answer "which object should I talk to?"
Common reference sources:
| Source | Good for | Watch out |
|---|---|---|
Overlap event Other Actor |
Trigger volumes, pickups, hazards. | Filter the actor before using it. |
Line Trace By Channel Hit Actor |
Looking at doors, buttons, interactables. | Branch on the trace return value first. |
| Spawn Actor from Class return value | Binding to or configuring the actor you just spawned. | The return value can be None. |
| Editable actor variable | Designer-wired door, light, or target in the Details panel. | It can be left unassigned. |
| Owner / Instigator / Controller / Pawn | Framework relationships. | Each word means a specific relationship, not "who I want." |
| Widget owning player | UI connected to the player/controller that created it. | Recreated widgets need fresh setup. |
If the reference is wrong, changing from cast to interface to dispatcher will not fix the graph. Debug the reference first with Breakpoints and watch values.
Cast when you know the class¶
A cast asks: "is this object really this class, or a child of this class?"
Use a cast when the caller is intentionally coupled to that class:
Try Get Pawn Owner
-> Cast To BP_PlayerCharacter
-> read GroundSpeedSource or WeaponState
That is honest. The Animation Blueprint is designed for that character class, so exposing character-specific variables is exactly the point.
Do not use casts as a list of guesses:
Hit Actor
-> Cast To BP_Door
-> Cast Failed -> Cast To BP_Chest
-> Cast Failed -> Cast To BP_NPC
-> Cast Failed -> Cast To BP_Pickup
That graph is really asking "does this thing support Interact?" The better tool is an interface.
Interface when you know the contract¶
A Blueprint Interface asks: "does this target implement this shared function?"
Use it when many unrelated classes should answer the same verb:
Input Interact
-> Line Trace By Channel
-> Hit Actor
-> Interface Message: Interact
The player character does not need to know whether the hit actor is a door, chest, dialogue NPC, or pickup. Each target owns its own implementation.
An interface is still a one-target call. If the player wants to interact with the one thing under the crosshair, that is an interface shape. If a character dies and the HUD, music, quest, and door systems might all care, that is a dispatcher shape.
Dispatcher when you do not know the listeners¶
An Event Dispatcher asks: "whoever is listening, this happened."
Use it when the broadcaster should not know every receiver:
BP_PlayerCharacter:
Health changed
-> Call OnHealthChanged(CurrentHealth, MaxHealth)
WBP_HealthBar:
Bind to OnHealthChanged
-> update bar
Audio manager:
Bind to OnHealthChanged
-> start low-health sound
The broadcaster owns the dispatcher. The listeners find the broadcaster and bind. That direction prevents the character from growing references to every UI widget, sound actor, quest script, and level rule that might care about health.
Dispatchers are especially good for:
- UI updates from gameplay state changes,
- spawned actor notifications, such as
OnDied, - level reactions to an actor event,
- reusable actor components that report changes to their owning actor or UI,
- avoiding "call every possible listener" code inside the broadcaster.
They are not good for asking one target to do one command. Use an interface or direct call for that.
Coupling and hard references¶
Communication nodes also shape asset dependencies.
Beginner-safe rule: if a Blueprint asset names a concrete Blueprint class in a node, variable type, component class, or parameter type, assume it can create a dependency on that class until the Reference Viewer proves otherwise.
| Tool | What the caller names | Coupling shape |
|---|---|---|
Direct variable BP_Door |
Concrete Blueprint class | Strong one-to-one dependency. Clear and fine when intentional. |
Cast To BP_Door |
Concrete Blueprint class | Caller depends on that class to access its members. |
BPI_Interactable message |
Interface asset | Caller depends on the contract, not on every implementing class. |
| Event Dispatcher binding | Broadcaster object/type and dispatcher signature | Broadcaster does not know listeners; listeners depend on the broadcaster they bind to. |
Dispatcher parameter BP_PlayerCharacter |
Concrete Blueprint class in the signature | Every binder now sees that concrete type; use simple values or broader types if you want looser coupling. |
Hard references are not automatically wrong. A player Animation Blueprint
casting to its own player character is normal. A small door button holding an
editable BP_Door variable is normal. The smell is a generic object, like the
player interaction trace, accumulating casts to every possible target class in
the project.
Use the Reference Viewer when load size or dependency chains matter. The point of the rule is to make the tradeoff visible early.
Worked example: the health bar¶
The health bar is the classic case where all three tools show up, but only one should drive the update.
Good shape:
BP_PlayerCharacter
owns Health and MaxHealth
owns Event Dispatcher OnHealthChanged(CurrentHealth, MaxHealth)
calls OnHealthChanged whenever health changes
PlayerController
creates WBP_HealthBar
gets controlled pawn
casts once to BP_PlayerCharacter
gives the widget the character reference or binds the widget event
WBP_HealthBar
updates progress bar when OnHealthChanged fires
does an initial refresh after binding
flowchart LR
Damage[Damage arrives] --> Character[BP_PlayerCharacter changes Health]
Character --> Dispatch[Call OnHealthChanged]
Controller[PlayerController creates widget] --> Cast[Cast once to BP_PlayerCharacter]
Cast --> Bind[Bind health widget to dispatcher]
Dispatch --> Widget[WBP_HealthBar updates percent]
Why this shape works:
- The character owns health, so it owns the dispatcher.
- The widget is a listener, so the character does not need a widget reference.
- The controller can cast once because it really is setting up its known player character and HUD.
- The widget does not poll health every frame through a binding.
- The initial refresh handles the fact that dispatchers do not replay old values.
Bad shapes and the better tool:
| Bad shape | Why it hurts | Better shape |
|---|---|---|
| Widget casts to player every Tick and reads health. | Repeated work and a noisy dependency hidden in UI. | Bind once to OnHealthChanged. |
Character casts to WBP_HealthBar and sets the bar directly. |
Gameplay class now knows a specific UI class. | Character broadcasts; widget listens. |
| Health bar uses an interface to ask the character for health every frame. | Still polling; interface did not solve timing. | Dispatcher on change plus initial refresh. |
Character dispatcher passes the whole WBP_HealthBar as a parameter. |
Broadcaster is now coupled to the listener type. | Pass health values, not listener objects. |
Failure shapes¶
| Tool | Failure looks like | Debug first |
|---|---|---|
| Cast To X | Cast Failed path runs; As X is empty. |
Is the input reference None or a different class? |
| Interface Message | Non-implementers do nothing; execution continues. | Does the target implement the interface? Is the target the actor you think? |
| Event Dispatcher Call | Empty listener list does nothing; execution continues. | Did the bind path run on the same broadcaster instance before the call? |
| Dispatcher Bind | Nothing later receives the call, or an empty broadcaster reference warns. | Is the broadcaster reference valid at bind time? |
| Direct function call | Empty object reference can produce an Accessed None warning. | Who was supposed to assign the reference? |
The debugging order is nearly always:
1. Breakpoint where the reference is produced.
2. Watch the object reference.
3. Breakpoint on cast/interface/bind/call.
4. Print self names for broadcaster and listener if instances are confusing.
Common decision mistakes¶
"I used a dispatcher but nothing happened"¶
You probably called it before anything bound to it, bound to the wrong instance, or expected the dispatcher to find listeners. Put a breakpoint on the bind path and the call path.
"I used an interface but it hit every actor"¶
An interface message only targets the object you send it to. If many actors responded, your graph looped over many targets, used a multi trace, or called the message from several places.
"I used casts and my interaction graph is huge"¶
The graph is asking a contract question. Make BPI_Interactable, implement it
on the target classes, and send one Interact message to the hit actor.
"I used an interface for my health bar"¶
An interface is for asking one target to do or answer something. A health bar usually wants to react when state changes. That is a dispatcher.
"I want this to work in multiplayer"¶
None of these tools bypass networking rules. A cast, interface call, or dispatcher call runs where that Blueprint graph runs. Use server/client remote procedure calls and replicated variables for network authority, then use these tools locally on the machine that should update its UI or gameplay state.
What these tools do not decide for you¶
- They do not choose where the variable should live.
- They do not find the correct actor instance.
- They do not fix lifetime. A destroyed or replaced actor still needs a fresh reference and fresh binding.
- They do not automatically reduce dependencies if your pins still name concrete Blueprint classes.
- They do not make UI, level script, pawn, controller, and component ownership interchangeable.
Start by asking who owns the state. Then ask who needs to know. The answer usually makes the communication tool obvious.
Lookalikes - which one do I want?¶
| Tool | Use when | Usually avoid when |
|---|---|---|
| Direct function call | You already have a typed reference to the one target. | You are guessing among many possible target classes. |
| Cast To X | A broad pin is carrying a specific class you genuinely need. | You only need a shared verb or many unrelated targets. |
| Blueprint Interface | One target should answer a shared contract. | The sender should not know or care who all the listeners are. |
| Event Dispatcher | One broadcaster announces to zero, one, or many listeners. | You need an immediate answer from one target. |
| Actor Component | Several actors need shared state and implementation. | You only need a callable contract. |
| Base class / inheritance | The classes are truly the same kind of thing. | They only share one optional behavior. |
| Get All Actors Of Class | One-off setup or editor-like discovery where cost and order are acceptable. | Per-frame communication or normal gameplay references. |
Rule of thumb: know the class -> cast or direct call; know the contract -> interface; do not know the listeners -> dispatcher.
Going deeper¶
- Cast To X - what casts check and what the failed path means.
- Blueprint Interfaces -
interface message behavior and
Does Object Implement Interface. - Event Dispatchers - Bind, Assign, Call, Unbind, and binding lifecycle.
- Ownership and lifetime - why object references and lifetime matter before any communication node can work.
- Accessed None trying to read property - the reference failure that often gets misdiagnosed as a communication-tool problem.
- Official docs: Blueprint Communication Usage, Blueprint Communications, Casting Quick Start Guide, Blueprint Interface, Event Dispatchers, Referencing Assets, and Reference Viewer.
- Engine source (requires engine access - we do not reproduce it here):
casts are represented by
UK2Node_DynamicCastinEngine/Source/Editor/BlueprintGraph/Private/K2Node_DynamicCast.cpp; interface messages byUK2Node_MessageinEngine/Source/Editor/BlueprintGraph/Classes/K2Node_Message.h; dispatcher bind/call nodes by theUK2Node_*Delegateclasses underEngine/Source/Editor/BlueprintGraph/Classes/; Blueprint dependency collection starts fromUBlueprint::GatherDependenciesinEngine/Source/Runtime/Engine/Private/Blueprint.cpp.