🔗 Blueprint Communication and Variables
Blueprints don't exist in isolation—they need to communicate with each other to create complex, interconnected gameplay systems. In this lesson, you'll master how Blueprints talk to one another using references, casting, interfaces, and event dispatchers. You'll also dive deep into variables—the data containers that hold everything from player health to enemy positions. By the end, you'll be able to build sophisticated multi-Blueprint systems that work together seamlessly.
🎯 Learning Objectives
By the end of this lesson, you will be able to:
- Understand and use Blueprint variables (local, instance, and class variables)
- Work with all major data types (Boolean, Integer, Float, String, Vector, etc.)
- Create references between Blueprints to enable communication
- Use casting to access specific Blueprint functionality
- Implement direct Blueprint communication patterns
- Understand Blueprint Interfaces and when to use them
- Create and use Event Dispatchers for decoupled communication
- Choose the right communication method for different scenarios
- Manage variable scope and access levels
Estimated Time: 90-105 minutes
Prerequisites: Lesson 3.1 - Introduction to Blueprints
📑 In This Lesson
Why Blueprint Communication Matters
Imagine building a game where:
- A pressure plate needs to tell a door to open
- An enemy needs to know the player's location to chase them
- A UI widget needs to display the player's current health
- A collectible needs to notify the score manager when picked up
- Multiple lights need to turn on when the player flips a switch
Every one of these scenarios requires Blueprint communication—Blueprints sending messages, sharing data, or triggering actions in other Blueprints.
📖 Key Concept
Blueprint Communication: The methods and systems that allow one Blueprint to access, modify, or trigger functionality in another Blueprint. Without communication, every Blueprint would be an isolated island—unable to affect anything beyond itself. Communication is what turns individual Blueprints into cohesive gameplay systems.
The Communication Challenge
Consider this scenario: You have a pressure plate Blueprint and a door Blueprint. The plate needs to tell the door "Player stepped on me—open up!" But how?
flowchart LR
A[BP_PressurePlate] -->|How to communicate?| B[BP_Door]
C[Player Character] -->|Steps on| A
B -->|Opens| D[Door Opens]
style A fill:#ff9800,stroke:#e65100,color:#fff
style B fill:#2196F3,stroke:#1565c0,color:#fff
style C fill:#4CAF50,stroke:#2e7d32,color:#fff
style D fill:#9c27b0,stroke:#6a1b9a,color:#fff
Figure: Blueprints need mechanisms to communicate actions and data between each other.
The pressure plate can't just say "open the door" into thin air. It needs:
- A reference: "Which door am I talking to?"
- A communication method: "How do I tell it to open?"
- Data sharing: "Does it need any information from me?"
This lesson teaches you all the ways Blueprints can communicate, from simple direct references to advanced event dispatching systems.
Communication Methods Overview
| Method | Best For | Complexity |
|---|---|---|
| Direct Reference | One Blueprint controlling another (lever → door) | ⭐ Simple |
| Casting | Accessing specific Blueprint functionality | ⭐⭐ Medium |
| Blueprint Interface | Multiple different Blueprints implementing same action | ⭐⭐⭐ Advanced |
| Event Dispatcher | Broadcasting to multiple listeners (publish-subscribe) | ⭐⭐⭐ Advanced |
We'll cover each method in depth, starting with the foundation: variables.
Variables: Fundamentals
Before Blueprints can communicate effectively, you need to understand variables—the containers that store data.
📖 Definition
Variable: A named storage location that holds a value which can change during gameplay. Think of it as a labeled box: the variable name is the label, the data type is what kind of thing can go in the box, and the value is what's currently inside.
Why Variables Matter
Variables are how Blueprints remember information:
- 💚 Player health: An integer variable (e.g., Health = 100)
- 🚪 Door state: A boolean variable (e.g., bIsOpen = false)
- 🎯 Enemy position: A vector variable (e.g., TargetLocation = (500, 200, 100))
- 📝 Player name: A string variable (e.g., PlayerName = "Hero")
- 🔗 Door reference: An object reference variable (e.g., DoorToOpen = BP_Door_Instance)
Without variables, Blueprints would have amnesia—unable to remember anything from one frame to the next.
Creating a Variable
- Open a Blueprint
- In My Blueprint panel, click + Variable
- Name the variable (e.g.,
Health) - In Details panel, set the Variable Type (e.g., Integer)
- Set Default Value (e.g., 100)
- Click Compile to save
Using Variables in Blueprints
Once created, variables can be accessed in the Event Graph:
flowchart LR
A[Get Variable] -->|Reads current value| B[Use in Logic]
C[Set Variable] -->|Writes new value| D[Variable Updated]
style A fill:#4CAF50,stroke:#2e7d32,color:#fff
style B fill:#2196F3,stroke:#1565c0,color:#fff
style C fill:#ff9800,stroke:#e65100,color:#fff
style D fill:#9c27b0,stroke:#6a1b9a,color:#fff
Figure: Variables have two primary operations—Get (read) and Set (write).
Get Variable:
- Drag variable from My Blueprint panel into Event Graph
- Choose "Get"
- Creates a getter node that outputs the variable's current value
- Getters are "pure" (no execution pins)—they just return data
Set Variable:
- Drag variable from My Blueprint panel into Event Graph
- Choose "Set"
- Creates a setter node with execution pins
- Connect a new value to the input pin
- When executed, updates the variable
Figure: Get node reads variable value (pure function), Set node writes new value (requires execution).
Variable Properties
When you select a variable in My Blueprint, the Details panel shows configuration options:
| Property | Purpose |
|---|---|
| Variable Type | What kind of data (Integer, Boolean, String, etc.) |
| Default Value | Starting value when Blueprint spawns |
| Instance Editable | Can be set per-instance in level (shows in Details panel) |
| Blueprint Read Only | Can only be read, not written (protects from accidental changes) |
| Expose on Spawn | Must be set when spawning the Blueprint |
| Private | Only accessible within this Blueprint (not by others) |
| Category | Organizes variables into groups |
| Tooltip | Description shown when hovering (for documentation) |
Blueprint Data Types
Blueprint variables can hold many different types of data. Understanding data types is crucial for effective communication and data management.
Primitive Data Types
The basic building blocks—simple values:
| Type | What It Stores | Examples | Common Uses |
|---|---|---|---|
| Boolean | True or False | true, false | Switches, states (bIsOpen, bIsDead, bCanJump) |
| Integer | Whole numbers | -100, 0, 42, 1000 | Health, ammo count, level number, score |
| Float | Decimal numbers | 0.5, 3.14, 100.25 | Speed, damage, timer, distance |
| String | Text | "Hello", "Player1", "Victory!" | Names, messages, UI text, tags |
| Name | Lightweight text identifier | 'PlayerTag', 'EnemyType' | Tags, identifiers (more efficient than String) |
| Text | Localized text | Localizable strings | UI text that needs translation |
| Byte | Small integer (0-255) | 0, 128, 255 | Enumerations, small counts, flags |
Structural Data Types
Complex types that hold multiple related values:
| Type | What It Stores | Examples | Common Uses |
|---|---|---|---|
| Vector | 3D coordinate (X, Y, Z) | (100.0, 200.0, 50.0) | Position, direction, velocity, scale |
| Rotator | 3D rotation (Pitch, Yaw, Roll) | (0.0, 90.0, 0.0) | Actor rotation, aim direction |
| Transform | Position + Rotation + Scale | Complete 3D transformation | Full Actor placement, spawn transforms |
| Vector2D | 2D coordinate (X, Y) | (500.0, 300.0) | Screen positions, UV coordinates |
| Color | RGBA color (Red, Green, Blue, Alpha) | (1.0, 0.5, 0.0, 1.0) | Material colors, light colors, UI tints |
Figure: Structural data types combine multiple values into cohesive units.
Reference Types
Variables that point to objects in the world:
| Type | What It References | Common Uses |
|---|---|---|
| Object Reference | Any Unreal object | Base type for all references |
| Actor Reference | Any Actor in the level | Doors, enemies, props to control |
| Class Reference | A Blueprint class (not an instance) | Spawning—"which type to spawn" |
| Component Reference | A specific Component | Accessing mesh, collision, audio components |
| Soft Object Reference | Async-loaded reference | Large assets loaded on demand |
💡 References vs Values
Value types (Integer, Float, Boolean) store the actual data. When you copy them, you duplicate the value.
Reference types (Actor, Object) store a pointer to an object. When you copy them, both variables point to the same object—changing one affects what the other sees.
Think: A locker number (reference) vs. the contents inside (value).
Container Types (Collections)
Types that hold multiple values:
| Type | Structure | Use Cases |
|---|---|---|
| Array | Ordered list of same type | Inventory items, enemy list, waypoints |
| Set | Unordered collection, no duplicates | Unique tags, visited locations |
| Map | Key-value pairs | Player scores (name → score), damage types → multipliers |
Array example: An array of Actor references to store all enemies in a level.
EnemyArray[0] = Enemy_1
EnemyArray[1] = Enemy_2
EnemyArray[2] = Enemy_3
Access by index: EnemyArray[0] gets first enemy.
Choosing the Right Data Type
flowchart TD
A{What data do you need?} --> B{True/False state?}
B -->|Yes| C[Boolean]
B -->|No| D{Whole number?}
D -->|Yes| E[Integer]
D -->|No| F{Decimal number?}
F -->|Yes| G[Float]
F -->|No| H{Text?}
H -->|Yes| I[String/Name/Text]
H -->|No| J{3D position/direction?}
J -->|Yes| K[Vector]
J -->|No| L{Rotation?}
L -->|Yes| M[Rotator]
L -->|No| N{Reference to object?}
N -->|Yes| O[Actor/Object Reference]
N -->|No| P{Multiple items?}
P -->|Yes| Q[Array/Set/Map]
style C fill:#4CAF50,stroke:#2e7d32,color:#fff
style E fill:#2196F3,stroke:#1565c0,color:#fff
style G fill:#ff9800,stroke:#e65100,color:#fff
style I fill:#9c27b0,stroke:#6a1b9a,color:#fff
style K fill:#00bcd4,stroke:#006064,color:#fff
style M fill:#f44336,stroke:#c62828,color:#fff
style O fill:#ff5722,stroke:#d84315,color:#fff
style Q fill:#795548,stroke:#4e342e,color:#fff
Figure: Decision tree for selecting the appropriate data type.
Variable Scope and Access
Not all variables are created equal—where and how they can be accessed depends on their scope.
📖 Key Concept
Variable Scope: Defines where a variable can be accessed and modified. Scope controls whether a variable is visible only within one function, across the entire Blueprint, or even to other Blueprints. Understanding scope prevents bugs and enables proper Blueprint communication.
The Three Levels of Scope
graph TD
A[Variable Scopes] --> B[Local Variables]
A --> C[Instance Variables]
A --> D[Class Variables Static]
B --> B1[Function/Macro only]
B --> B2[Temporary data]
B --> B3[Can't be accessed outside]
C --> C1[Entire Blueprint]
C --> C2[Each instance unique]
C --> C3[Can expose to other BPs]
D --> D1[Shared across all instances]
D --> D2[Class-wide data]
D --> D3[Rarely used in BP]
style A fill:#667eea,stroke:#4527a0,color:#fff
style B fill:#4CAF50,stroke:#2e7d32,color:#fff
style C fill:#2196F3,stroke:#1565c0,color:#fff
style D fill:#ff9800,stroke:#e65100,color:#fff
style B1 fill:#e8f5e9,stroke:#4CAF50
style B2 fill:#e8f5e9,stroke:#4CAF50
style B3 fill:#e8f5e9,stroke:#4CAF50
style C1 fill:#e3f2fd,stroke:#2196F3
style C2 fill:#e3f2fd,stroke:#2196F3
style C3 fill:#e3f2fd,stroke:#2196F3
style D1 fill:#fff3e0,stroke:#ff9800
style D2 fill:#fff3e0,stroke:#ff9800
style D3 fill:#fff3e0,stroke:#ff9800
Figure: The hierarchy of variable scope from local (narrowest) to class (widest).
1. Local Variables
Local variables exist only within a single function or macro. They're created when the function starts and destroyed when it ends.
Creating local variables:
- Inside a function, add a node that creates a variable (like "Make Vector")
- Or: Right-click → "Promote to Variable" → Choose "Local Variable"
- Local variables appear in the function's local variable list
Use cases:
- ✅ Temporary calculations within a function
- ✅ Loop counters
- ✅ Intermediate values you don't need to keep
- ✅ Prevents cluttering the Blueprint with unnecessary variables
2. Instance Variables (Most Common)
Instance variables are what you typically create—they're accessible throughout the entire Blueprint and unique to each instance.
Example: You place 3 doors in your level from BP_Door. Each door has its own bIsOpen variable—one door opening doesn't affect the others.
Use cases:
- ✅ Actor state (health, speed, isOpen)
- ✅ Configuration values (damage, range, color)
- ✅ References to other Actors
- ✅ Data that persists across function calls
3. Class Variables (Static)
Class variables are shared across ALL instances of a Blueprint. Changing one instance's class variable changes it for all.
Use cases:
- ⚠️ Rarely used in Blueprints (more common in C++)
- ✅ Global counters (e.g., total enemies spawned)
- ✅ Shared configuration data
Note: In Blueprints, you typically use a Game Instance or Game Mode for truly global data instead of class variables.
Access Levels
Variables also have access levels that control who can see and modify them:
| Access Level | Who Can Access | Set By |
|---|---|---|
| Private | Only this Blueprint | Check "Private" in variable details |
| Public (Default) | This Blueprint + child Blueprints | Default state |
| Instance Editable | Can be set per-instance in editor | Check "Instance Editable" |
| Blueprint Read Only | Can read, cannot write (get only) | Check "Blueprint Read Only" |
| Expose on Spawn | Must be set when spawning | Check "Expose on Spawn" |
Best Practices for Variable Scope
✅ Do This
- Use local variables for temporary calculations
- Use instance variables for Actor state
- Mark variables Private when they're internal only
- Use Instance Editable for designer-tweakable values
- Group related variables with Categories
- Add tooltips to document purpose
❌ Avoid This
- Making everything Instance Editable (clutters Details panel)
- Using instance variables for temporary values
- Exposing internal implementation details publicly
- Creating variables without descriptive names
- Overusing class/static variables
Example: Variable Scope in Action
Consider a CalculateDamage function in a weapon Blueprint:
Instance Variables (accessible everywhere in Blueprint):
- BaseDamage (Float) = 50.0
- DamageMultiplier (Float) = 1.5
- LastDamageDealt (Float)
Function: CalculateDamage
Local Variables (only exist in this function):
- RandomBonus (Float) = Random between 0 and 10
- FinalDamage (Float) = BaseDamage * DamageMultiplier + RandomBonus
Set LastDamageDealt = FinalDamage
Return FinalDamage
Why this structure?
BaseDamageandDamageMultiplierare instance variables—they persist and can be configured per weaponRandomBonusandFinalDamageare local—temporary calculations, no need to storeLastDamageDealtis instance—we want to remember it for debugging or UI display
Blueprint References
To make one Blueprint control another, you need a reference—a variable that points to the specific Blueprint instance you want to affect.
📖 Key Concept
Blueprint Reference: A variable that holds a pointer to a specific Actor or object in your game. Think of it like a phone number—you need someone's number (reference) to call them (communicate with them). Without a reference, your Blueprint can't interact with another.
Why References Are Necessary
You can't just say "open the door" into the void. You need to specify which door. References solve this:
sequenceDiagram
participant Lever as BP_Lever
participant Door as BP_Door
Note over Lever: Needs reference to Door
Lever->>Lever: Get DoorReference variable
Lever->>Door: Call "Open" function
Door->>Door: Execute open logic
Door-->>Lever: Done
Note over Lever,Door: Communication succeeded because Lever had Door reference
Figure: References enable direct communication between Blueprint instances.
Creating References
There are several ways to establish references between Blueprints:
Method 1: Manual Assignment (Instance Editable)
- In
BP_Lever, create a variable:DoorToControl - Set type to Actor → BP_Door (object reference)
- Check "Instance Editable"
- Place both lever and door in your level
- Select the lever instance
- In Details panel, you'll see "Door To Control"
- Click the eyedropper, then click the door in viewport to assign
Now the lever has a reference to that specific door!
Method 2: Search and Store (BeginPlay)
- Create variable:
PlayerReference(Actor → Character) - In Event BeginPlay:
- Use "Get Player Character" node
- Store result in
PlayerReferencevariable
- Now you can access player from anywhere in the Blueprint
Method 3: Collision/Overlap Detection
- OnBeginOverlap event provides "Other Actor" pin
- This is a reference to whatever touched you
- You can store it or use it immediately
Method 4: Spawning
- When you spawn an Actor, the Spawn node returns a reference to it
- Store this reference to control the spawned Actor later
✅ Best Practice: Validate References
Always check if a reference is valid before using it:
Get DoorReference → IsValid? → If valid, use it
→ If invalid, handle error
References can become invalid if the Actor is destroyed. The "IsValid" node prevents crashes.
Casting: Type-Safe Communication
Having a reference is step one. But what if you have a generic "Actor" reference and need to access specific Blueprint functionality? That's where casting comes in.
📖 Definition
Casting: The process of treating a generic reference (like "Actor") as a more specific type (like "BP_Door") so you can access its unique variables and functions. Think of it like this: you know someone is "a person" (Actor), but casting confirms they're specifically "a doctor" (BP_Door) so you can call doctor-specific functions like "PerformSurgery".
Why Casting Is Necessary
When you get a reference from events like OnBeginOverlap, you often get a generic "Actor" reference. This could be anything—a player, a rock, a light, anything. To access specific functionality, you need to cast:
flowchart LR
A[Generic Actor Reference] --> B{Cast to Specific Type}
B -->|Success| C[Access Specific Functions/Variables]
B -->|Failure| D[Not that type - handle accordingly]
style A fill:#9e9e9e,stroke:#616161,color:#fff
style B fill:#ff9800,stroke:#e65100,color:#fff
style C fill:#4CAF50,stroke:#2e7d32,color:#fff
style D fill:#e74c3c,stroke:#c0392b,color:#fff
Figure: Casting converts generic references to specific types, enabling type-specific access.
How to Cast
- Have a reference (e.g., from OnBeginOverlap's "Other Actor" pin)
- Right-click in graph → search "Cast to [BlueprintName]"
- Example: "Cast to BP_Player"
- Connect the reference to the cast node's Object input
- The cast has two execution outputs:
- Cast Succeeded: It was that type—proceed
- Cast Failed: It wasn't that type—handle error
- From "Cast Succeeded" output pin, you get a typed reference
Casting Example: Pressure Plate
Scenario: A pressure plate should only activate when the player steps on it, not enemies or props.
flowchart TD
A[OnBeginOverlap Event] --> B[Get Other Actor]
B --> C{Cast to BP_Player}
C -->|Success| D[It's the player!]
C -->|Failed| E[Not the player - ignore]
D --> F[Open Door]
E --> G[Do Nothing]
style A fill:#e74c3c,stroke:#c0392b,color:#fff
style B fill:#9e9e9e,stroke:#616161,color:#fff
style C fill:#ff9800,stroke:#e65100,color:#fff
style D fill:#4CAF50,stroke:#2e7d32,color:#fff
style E fill:#9e9e9e,stroke:#616161,color:#fff
style F fill:#2196F3,stroke:#1565c0,color:#fff
style G fill:#757575,stroke:#424242,color:#fff
Figure: Casting filters overlaps to only respond to specific Actor types.
Blueprint nodes:
- OnBeginOverlap (CollisionComponent) → Other Actor pin
- Cast to BP_Player → Object = Other Actor
- If cast succeeds → Player stepped on plate → Trigger door
- If cast fails → Something else → Ignore
Casting Best Practices
✅ Good Casting
- Cast when you need specific functionality
- Use cast failed branch to handle non-matches
- Store successful cast results for reuse
- Cast to interfaces instead of classes when possible (more flexible)
⚠️ Casting Pitfalls
- Don't cast every frame (expensive)
- Don't ignore cast failed branch (can cause bugs)
- Avoid casting chains (A→B→C→D gets messy)
- Consider interfaces for loose coupling
Performance Note
Casting has a small performance cost. If you're casting every frame (Event Tick), consider caching the result:
❌ Bad:
Event Tick
Get Other Actor → Cast to Player → Use Player
✅ Good:
Event BeginPlay
Get Player → Cast to Player → Store in PlayerRef
Event Tick
Use PlayerRef (no casting needed)
Direct Blueprint Communication
Once you have a reference and optionally cast it, you can directly communicate—call functions, access variables, trigger events.
Calling Functions
If BP_Door has a function called OpenDoor(), and you have a reference to it:
- Drag the DoorReference variable into the graph (Get)
- Drag from its output pin → search "OpenDoor"
- Unreal shows all functions available on that Blueprint
- Connect execution flow to call it
The function executes on that specific door instance.
Getting and Setting Variables
If a variable is public or instance editable, you can access it:
- Get variable: Drag from reference → search "Get [VariableName]"
- Set variable: Drag from reference → search "Set [VariableName]"
Example: Check if door is open:
Get DoorReference → Get bIsOpen → Branch (if true, do something)
Common Communication Pattern
sequenceDiagram
participant A as BP_Button
participant B as BP_Door
Note over A: Player presses button
A->>A: OnInteract Event fires
A->>A: Get DoorReference
A->>B: Call OpenDoor()
B->>B: Set bIsOpen = true
B->>B: Play animation
B->>B: Play sound
B-->>A: Function complete
Note over A,B: Direct communication via reference + function call
Figure: Complete direct communication sequence from button press to door opening.
Blueprint Interfaces
What if you want to send the same message to many different Blueprint types without casting to each one? Use Blueprint Interfaces.
📖 Definition
Blueprint Interface: A contract that defines function signatures without implementation. Multiple Blueprints can "implement" the interface, each providing their own version of the functions. This allows you to send messages to diverse objects without knowing their specific types.
The Interface Problem
Imagine a game where explosions should damage nearby objects. But different objects respond differently:
- Player: Reduce health, play hurt animation
- Enemy: Reduce health, ragdoll if dead
- Crate: Break apart, spawn loot
- Door: Take damage, open when health reaches 0
Without interfaces, you'd need to cast to each type and call different functions. With interfaces, you create one "TakeDamage" message that all implement.
flowchart TD
A[Explosion Blueprint] --> B[Send TakeDamage message]
B --> C[Interface: I_Damageable]
C --> D[BP_Player implements]
C --> E[BP_Enemy implements]
C --> F[BP_Crate implements]
C --> G[BP_Door implements]
D --> D1[Reduce health]
E --> E1[Reduce health + ragdoll]
F --> F1[Break apart]
G --> G1[Damage door]
style A fill:#ff9800,stroke:#e65100,color:#fff
style B fill:#2196F3,stroke:#1565c0,color:#fff
style C fill:#9c27b0,stroke:#6a1b9a,color:#fff
style D fill:#4CAF50,stroke:#2e7d32,color:#fff
style E fill:#4CAF50,stroke:#2e7d32,color:#fff
style F fill:#4CAF50,stroke:#2e7d32,color:#fff
style G fill:#4CAF50,stroke:#2e7d32,color:#fff
Figure: Interfaces allow one message to reach multiple Blueprint types, each responding uniquely.
Creating a Blueprint Interface
- Content Browser → Right-click → Blueprint Interface
- Name it (e.g.,
BPI_Damageable) - Open it
- Add functions (e.g., "TakeDamage")
- Define inputs (DamageAmount, DamageType)
- Define outputs (if needed)
- No implementation—just signatures
- Save and close
Implementing an Interface
- Open a Blueprint (e.g., BP_Player)
- Class Settings → Interfaces → Add → Choose your interface
- In Event Graph or Functions, you'll see interface functions listed
- Right-click → Implement event "TakeDamage"
- Add your custom logic (for player: reduce health, play sound, etc.)
Calling Interface Functions
Instead of casting, you call the interface directly:
- Have a reference to an Actor (any Actor)
- Drag from it → search "TakeDamage" (the interface message)
- Choose the interface version (blue icon)
- Connect inputs (DamageAmount, etc.)
- If the Actor implements the interface, it receives and handles the message
- If it doesn't implement it, nothing happens (no error)
Interface vs. Casting
| Aspect | Casting | Interface |
|---|---|---|
| Specificity | Knows exact Blueprint type | Doesn't know or care about type |
| Flexibility | Rigid—only works with that type | Flexible—works with any implementer |
| Use Case | Accessing specific Blueprint variables/functions | Sending common messages to diverse types |
| Coupling | Tight—depends on specific Blueprint | Loose—only depends on interface contract |
| Failure Handling | Cast Failed branch required | Silent if not implemented |
Event Dispatchers
Event Dispatchers are Unreal's publish-subscribe system—one Blueprint broadcasts an event, multiple others can listen and respond.
📖 Definition
Event Dispatcher: A special type of event that can be broadcast to multiple listeners. The broadcaster doesn't need to know who's listening—it just announces "something happened" and all subscribers respond. Think of it like a radio station: it broadcasts, and anyone tuned in receives the signal.
When to Use Event Dispatchers
Perfect for one-to-many communication where the sender doesn't know (or care) who's listening:
- ✅ Player collects a coin → Update UI, play sound, trigger achievement check
- ✅ Boss dies → Close doors, spawn loot, start victory sequence, update quest
- ✅ Button pressed → Open multiple doors, activate lights, trigger cutscene
- ✅ Wave completed → Update score, spawn next wave, display message
flowchart TD
A[Event Dispatcher: OnBossDeath] --> B[Broadcast]
B --> C[Listener 1: UI Widget]
B --> D[Listener 2: Level Door]
B --> E[Listener 3: Quest Manager]
B --> F[Listener 4: Music Controller]
C --> C1[Show Victory Screen]
D --> D1[Open Exit Door]
E --> E1[Complete Quest]
F --> F1[Play Victory Music]
style A fill:#ff9800,stroke:#e65100,color:#fff
style B fill:#e74c3c,stroke:#c0392b,color:#fff
style C fill:#2196F3,stroke:#1565c0,color:#fff
style D fill:#2196F3,stroke:#1565c0,color:#fff
style E fill:#2196F3,stroke:#1565c0,color:#fff
style F fill:#2196F3,stroke:#1565c0,color:#fff
style C1 fill:#4CAF50,stroke:#2e7d32,color:#fff
style D1 fill:#4CAF50,stroke:#2e7d32,color:#fff
style E1 fill:#4CAF50,stroke:#2e7d32,color:#fff
style F1 fill:#4CAF50,stroke:#2e7d32,color:#fff
Figure: Event Dispatchers broadcast to multiple listeners simultaneously.
Creating an Event Dispatcher
- Open the broadcasting Blueprint (e.g., BP_Boss)
- My Blueprint panel → Event Dispatchers → + Event Dispatcher
- Name it (e.g.,
OnBossDeath) - In Details, add inputs if needed (e.g., DeathLocation, LootToSpawn)
- Compile
Broadcasting (Calling) the Dispatcher
- In the broadcaster's Event Graph, when the event occurs:
- Drag the Event Dispatcher into the graph
- Choose "Call [DispatcherName]"
- Connect execution flow
- Provide any input values
Example: Boss death logic:
Health <= 0 → Call OnBossDeath → Pass (DeathLocation, LootType)
Binding to (Listening to) the Dispatcher
In the listening Blueprint (e.g., Level Blueprint, UI Widget):
- Get a reference to the broadcasting Actor (Boss)
- Drag from that reference → search for the dispatcher name
- Choose "Bind Event to [DispatcherName]"
- This creates a custom event node
- Wire your response logic to that custom event
When the broadcaster calls the dispatcher, all bound custom events fire.
Event Dispatcher Example: Collectible System
Scenario: When player collects a coin, multiple systems need to know.
BP_Coin (Broadcaster):
1. Create Event Dispatcher: OnCoinCollected (inputs: CoinValue)
2. OnBeginOverlap (player touches coin):
→ Call OnCoinCollected (Value = 10)
→ Destroy Actor
BP_ScoreManager (Listener 1):
BeginPlay:
Get All Actors of Class (BP_Coin)
For each coin:
→ Bind to OnCoinCollected
→ When fired: Add CoinValue to TotalScore
WBP_HUD (Listener 2 - UI Widget):
Construct:
Get All Actors of Class (BP_Coin)
For each coin:
→ Bind to OnCoinCollected
→ When fired: Update score text display
Result: One coin collection triggers multiple responses—score increases, UI updates, sound plays—without the coin knowing about any of them!
✅ Event Dispatcher Benefits
- Decoupling: Broadcaster doesn't need references to listeners
- Flexibility: Add/remove listeners without touching broadcaster
- One-to-many: Single broadcast reaches unlimited listeners
- Dynamic: Bind/unbind at runtime as needed
Choosing the Right Communication Method
With multiple communication options, how do you choose? Here's a decision guide:
flowchart TD
A{Communication Scenario} --> B{One sender, one receiver?}
B -->|Yes| C{Do you have direct reference?}
C -->|Yes| D[Direct Communication: Call functions/set variables]
C -->|No| E{Can you get reference easily?}
E -->|Yes| F[Get reference + Direct Communication]
E -->|No| G{Same message to different types?}
B -->|No| H{One sender, many receivers?}
H -->|Yes| I[Event Dispatcher]
G -->|Yes| J[Blueprint Interface]
G -->|No| K{Need specific Blueprint functionality?}
K -->|Yes| L[Casting + Direct Communication]
K -->|No| M[Consider redesigning architecture]
style D fill:#4CAF50,stroke:#2e7d32,color:#fff
style F fill:#4CAF50,stroke:#2e7d32,color:#fff
style I fill:#ff9800,stroke:#e65100,color:#fff
style J fill:#9c27b0,stroke:#6a1b9a,color:#fff
style L fill:#2196F3,stroke:#1565c0,color:#fff
Figure: Decision tree for selecting the appropriate Blueprint communication method.
Method Comparison
| Method | When to Use | Pros | Cons |
|---|---|---|---|
| Direct Reference | Simple 1-to-1 relationships | Simple, fast, clear | Requires knowing target, tight coupling |
| Casting | Access specific Blueprint features | Type-safe, full access | Rigid, performance cost, tight coupling |
| Interface | Same message to different types | Flexible, loose coupling, extensible | Setup overhead, can't access variables directly |
| Event Dispatcher | Broadcast to multiple unknown listeners | Decoupled, dynamic, one-to-many | Setup complexity, harder to debug |
Real-World Examples
| Scenario | Best Method | Why |
|---|---|---|
| Lever controls one specific door | Direct Reference | Simple 1-to-1, door is known at design time |
| Pressure plate checks if player stepped on it | Casting | Need to verify it's the player specifically |
| Explosion damages everything nearby | Interface | Damage message to diverse types (player, enemy, props) |
| Boss death triggers multiple systems | Event Dispatcher | One event, many unknown listeners (UI, doors, quests) |
| AI needs player location | Direct Reference (cached) | Get player once, store reference, use repeatedly |
🏋️ Hands-On Exercise: Multi-Button Door System
Build a door that requires multiple buttons to be pressed before opening. This exercises references, variables, and communication.
Part 1: Create BP_Door
- Create Blueprint Class → Actor →
BP_MultiButtonDoor - Add Static Mesh Component (door visual)
- Create variables:
bIsOpen(Boolean) = falseRequiredButtons(Integer) = 3PressedButtons(Integer) = 0
- Create function:
CheckButtonPress()- Increment PressedButtons by 1
- If PressedButtons >= RequiredButtons:
- Set bIsOpen = true
- Print "Door Opening!"
- Move door up (SetRelativeLocation)
- Else: Print "X buttons remaining"
Part 2: Create BP_Button
- Create Blueprint Class → Actor →
BP_Button - Add Static Mesh Component (button visual)
- Add Box Collision Component
- Create variable:
DoorToControl(Object Reference → BP_MultiButtonDoor)- Check "Instance Editable"
- Add OnComponentBeginOverlap event:
- Cast to Player Character
- If success:
- Check if DoorToControl is valid
- If valid: Call DoorToControl → CheckButtonPress()
- Print "Button Pressed!"
- Disable collision (prevent re-pressing)
Part 3: Set Up in Level
- Place
BP_MultiButtonDoorin level - Place 3 instances of
BP_Buttonaround the level - For each button:
- Select it
- In Details → Door To Control → Use eyedropper to select the door
- Play (Alt+P)
- Walk to each button—door opens after all 3 are pressed!
✅ Checkpoint: What did you practice?
This exercise covered:
- Variables: Boolean, Integer for state tracking
- References: Button stores reference to door
- Casting: Verify player triggered button
- Direct Communication: Call door's CheckButtonPress function
- Instance Editable: Assign door per button instance
Challenge: Add Event Dispatcher
Enhance the system with a dispatcher:
- In BP_MultiButtonDoor, create Event Dispatcher:
OnDoorOpened - When door opens, call the dispatcher
- In Level Blueprint:
- Get reference to door
- Bind to OnDoorOpened
- When fired: Print "Victory!" + play sound
Summary
Blueprint communication and variables are the glue that connects individual Blueprints into cohesive gameplay systems. Master these concepts and you can build anything from simple door mechanics to complex multiplayer games.
Key Takeaways
- 📦 Variables store data—from simple booleans to complex object references—with three scope levels (local, instance, class)
- 🔢 Data Types include primitives (Boolean, Integer, Float, String), structures (Vector, Rotator, Transform), references (Actor, Object), and containers (Array, Set, Map)
- 🔗 References are pointers to specific Actors—without them, Blueprints can't communicate
- 🎯 Casting converts generic references to specific types, enabling type-safe access to unique functionality
- 📞 Direct Communication via references allows calling functions and accessing variables on other Blueprints
- 🔌 Blueprint Interfaces define contracts that multiple types implement, enabling flexible messaging without tight coupling
- 📡 Event Dispatchers broadcast events to multiple listeners without the broadcaster needing references—perfect for one-to-many communication
- 🧭 Choosing Methods: Direct reference for 1-to-1, interfaces for same-message-different-types, dispatchers for broadcasting
- ✅ Best Practices: Validate references, cache frequently-used references, use appropriate scope, minimize casting in Tick
What's Next?
Now that you understand how Blueprints communicate, the next lesson explores Lesson 3.3: Blueprint Flow Control and Logic. You'll learn conditionals (Branch, Switch), loops (For, While), sequences, gates, and how to build complex decision-making systems that bring your gameplay to life.
✅ Self-Check Quiz
Before moving on, make sure you can answer these questions:
- What's the difference between Get and Set variable nodes?
- Name three primitive data types and their uses.
- What are the three levels of variable scope?
- Why do you need references to communicate between Blueprints?
- What does casting do and when do you use it?
- When should you use a Blueprint Interface instead of casting?
- What's the advantage of Event Dispatchers?
📝 Show Answers
- Get reads the current value (pure function, no execution pins). Set writes a new value (requires execution).
- Boolean (true/false for states like bIsOpen), Integer (whole numbers for health/ammo), Float (decimals for speed/damage), String (text for names/messages).
- Local (function-only), Instance (entire Blueprint, unique per instance), Class/Static (shared across all instances).
- References are pointers to specific Actors. Without them, you can't specify which Actor to communicate with—like needing a phone number to call someone.
- Casting converts a generic reference (Actor) to a specific type (BP_Player) so you can access type-specific functions and variables. Use it when you need specific Blueprint functionality from a generic reference.
- Use Interfaces when you want to send the same message to multiple different Blueprint types without knowing their specific classes—enables loose coupling and flexibility.
- Event Dispatchers allow one-to-many broadcasting without the sender needing references to listeners—decouples sender from receivers and allows dynamic binding.