Skip to main content

🔗 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:

  1. A reference: "Which door am I talking to?"
  2. A communication method: "How do I tell it to open?"
  3. 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

  1. Open a Blueprint
  2. In My Blueprint panel, click + Variable
  3. Name the variable (e.g., Health)
  4. In Details panel, set the Variable Type (e.g., Integer)
  5. Set Default Value (e.g., 100)
  6. 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
Structural Data Types Visualized Vector X Z Y (X, Y, Z) Rotator Pitch Yaw Roll Transform Location (Vector) Rotation (Rotator) Scale Vector2D X Y (X, Y) Color (RGBA) R G B A (0-1 for each) These types store multiple related values as a single unit

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:

  1. Inside a function, add a node that creates a variable (like "Make Vector")
  2. Or: Right-click → "Promote to Variable" → Choose "Local Variable"
  3. 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?

  • BaseDamage and DamageMultiplier are instance variables—they persist and can be configured per weapon
  • RandomBonus and FinalDamage are local—temporary calculations, no need to store
  • LastDamageDealt is 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)

  1. In BP_Lever, create a variable: DoorToControl
  2. Set type to Actor → BP_Door (object reference)
  3. Check "Instance Editable"
  4. Place both lever and door in your level
  5. Select the lever instance
  6. In Details panel, you'll see "Door To Control"
  7. 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)

  1. Create variable: PlayerReference (Actor → Character)
  2. In Event BeginPlay:
    • Use "Get Player Character" node
    • Store result in PlayerReference variable
  3. Now you can access player from anywhere in the Blueprint

Method 3: Collision/Overlap Detection

  1. OnBeginOverlap event provides "Other Actor" pin
  2. This is a reference to whatever touched you
  3. You can store it or use it immediately

Method 4: Spawning

  1. When you spawn an Actor, the Spawn node returns a reference to it
  2. 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

  1. Have a reference (e.g., from OnBeginOverlap's "Other Actor" pin)
  2. Right-click in graph → search "Cast to [BlueprintName]"
  3. Example: "Cast to BP_Player"
  4. Connect the reference to the cast node's Object input
  5. The cast has two execution outputs:
    • Cast Succeeded: It was that type—proceed
    • Cast Failed: It wasn't that type—handle error
  6. 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:

  1. OnBeginOverlap (CollisionComponent) → Other Actor pin
  2. Cast to BP_Player → Object = Other Actor
  3. If cast succeeds → Player stepped on plate → Trigger door
  4. 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:

  1. Drag the DoorReference variable into the graph (Get)
  2. Drag from its output pin → search "OpenDoor"
  3. Unreal shows all functions available on that Blueprint
  4. 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

  1. Content Browser → Right-click → Blueprint Interface
  2. Name it (e.g., BPI_Damageable)
  3. Open it
  4. Add functions (e.g., "TakeDamage")
    • Define inputs (DamageAmount, DamageType)
    • Define outputs (if needed)
    • No implementation—just signatures
  5. Save and close

Implementing an Interface

  1. Open a Blueprint (e.g., BP_Player)
  2. Class Settings → Interfaces → Add → Choose your interface
  3. In Event Graph or Functions, you'll see interface functions listed
  4. Right-click → Implement event "TakeDamage"
  5. Add your custom logic (for player: reduce health, play sound, etc.)

Calling Interface Functions

Instead of casting, you call the interface directly:

  1. Have a reference to an Actor (any Actor)
  2. Drag from it → search "TakeDamage" (the interface message)
  3. Choose the interface version (blue icon)
  4. Connect inputs (DamageAmount, etc.)
  5. If the Actor implements the interface, it receives and handles the message
  6. 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

  1. Open the broadcasting Blueprint (e.g., BP_Boss)
  2. My Blueprint panel → Event Dispatchers → + Event Dispatcher
  3. Name it (e.g., OnBossDeath)
  4. In Details, add inputs if needed (e.g., DeathLocation, LootToSpawn)
  5. Compile

Broadcasting (Calling) the Dispatcher

  1. In the broadcaster's Event Graph, when the event occurs:
  2. Drag the Event Dispatcher into the graph
  3. Choose "Call [DispatcherName]"
  4. Connect execution flow
  5. 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):

  1. Get a reference to the broadcasting Actor (Boss)
  2. Drag from that reference → search for the dispatcher name
  3. Choose "Bind Event to [DispatcherName]"
  4. This creates a custom event node
  5. 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

  1. Create Blueprint Class → Actor → BP_MultiButtonDoor
  2. Add Static Mesh Component (door visual)
  3. Create variables:
    • bIsOpen (Boolean) = false
    • RequiredButtons (Integer) = 3
    • PressedButtons (Integer) = 0
  4. 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

  1. Create Blueprint Class → Actor → BP_Button
  2. Add Static Mesh Component (button visual)
  3. Add Box Collision Component
  4. Create variable:
    • DoorToControl (Object Reference → BP_MultiButtonDoor)
    • Check "Instance Editable"
  5. 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

  1. Place BP_MultiButtonDoor in level
  2. Place 3 instances of BP_Button around the level
  3. For each button:
    • Select it
    • In Details → Door To Control → Use eyedropper to select the door
  4. Play (Alt+P)
  5. 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
You've built a complete multi-Blueprint interaction system!

Challenge: Add Event Dispatcher

Enhance the system with a dispatcher:

  1. In BP_MultiButtonDoor, create Event Dispatcher: OnDoorOpened
  2. When door opens, call the dispatcher
  3. 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:

  1. What's the difference between Get and Set variable nodes?
  2. Name three primitive data types and their uses.
  3. What are the three levels of variable scope?
  4. Why do you need references to communicate between Blueprints?
  5. What does casting do and when do you use it?
  6. When should you use a Blueprint Interface instead of casting?
  7. What's the advantage of Event Dispatchers?
📝 Show Answers
  1. Get reads the current value (pure function, no execution pins). Set writes a new value (requires execution).
  2. Boolean (true/false for states like bIsOpen), Integer (whole numbers for health/ammo), Float (decimals for speed/damage), String (text for names/messages).
  3. Local (function-only), Instance (entire Blueprint, unique per instance), Class/Static (shared across all instances).
  4. 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.
  5. 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.
  6. 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.
  7. Event Dispatchers allow one-to-many broadcasting without the sender needing references to listeners—decouples sender from receivers and allows dynamic binding.