How did I deal with…?

Using Delegates to Establish Communication between User Interface and Gameplay

The goal of this project is to make a video game, reusing a single C++ template in each level for the most relevant actors. Using Blueprints to solve level‑specific situations enables the single C++ programming, to keep working on all levels. That's also true for future low level programming changes. This is what the basic programming looks like in the prototype:

Collecting item Collecting item Collecting item
Delegates trigger events, updating text in UI panels and modifying geometry and materials on the level.

The User Interface (UI) reacts to the overlapping on the pickup, telling you to click on “E” key, in order to:

  • Pick up the element
  • While collecting the item
  • Updating the pickup counter, and
  • Sending hints about what to do next.

When all items are collected, the UI tells you that the exit gates are unlocked and you can go through them to the next level:

Collecting last item Collecting last item Collecting last item
Delegates coordinating the interface with the messages in the UI.

These are the steps of the Delegates' implementation:

C++ logic schematics

The UI is constantly telling you what you are interacting with. Instead of casting every time to new actors – which may end up putting a strain on the CPU – my solution consists of:

  • Using events to broadcast Delegates, and
  • Changing text in UI.

First I'm making a prototype using Blueprints and Event Dispatchers (That's what Delegates are called in Blueprints). Once this prototype is functional, I'm in the position to draw a schematic for Interaction:

C++ logic schematic C++ logic schematic C++ logic schematic
C++ logic schematic.

Delegates declaration

With this schematic in mind and my functional Blueprint prototype, I can start translating to C++. This is what my Delegates declarations look like in the header of my Player Character (most of the UI updates come from the Interaction function):


DECLARE_DYNAMIC_MULTICAST_DELEGATE(FMission);
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FCounter);
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FHint);
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FMessage);

And this is what their definitions look like:


public:
	ASciFiProjCharacter();

	//************ Delegates
	UPROPERTY(BlueprintAssignable)
	FMission StartMission;

	UPROPERTY(BlueprintAssignable)
	FMission Mission_Accomplished;

	UPROPERTY(BlueprintAssignable)
	FHint Interact_Empty;

	UPROPERTY(BlueprintAssignable)
	FHint Interact_OneToGo;

	UPROPERTY(BlueprintAssignable)
	FHint Interact_Finished;

	UPROPERTY(BlueprintAssignable)
	FCounter Add_Item;

	UPROPERTY(BlueprintAssignable)
	FMessage Overlapping_Pickup;

	UPROPERTY(BlueprintAssignable)
	FMessage All_Pickups_Collected;

Broadcasting

I just have to broadcast them in the source file whenever an event happens to send a message to the UI, for instance, when you're overlapping a pickable object inside the OnOverlapBegin function:


Overlapping_Pickup.Broadcast();

Listeners in Blueprints

Here is the Listener in the UI Blueprint's Event Graph:

Overlapping listener Overlapping listener Overlapping listener
Listener to overlapping events.

Updating UI

Updating Messages Panel:

Updating messages panel Updating messages panel
Nodes updating the Messages panel.

I'm solving the text‑replacing operation with a macro (Showing Message) and reusing it every time an event takes place:

Macro showing message Macro showing message Macro showing message
Macro "Showing Message"

Event Dispatchers

This method allows to automate the visibility of the messages and let designers update the texts manually in Blueprints, instead of trying to hard code the messages in C++.
Almost every element in this level has its own delegates. I am using a couple of Event Dispatchers for the sake of efficiency, meaning, solving in C++ only what is repeating in every possible level and leaving local changes to Blueprints. Here is an example:

Local Event Dispatcher Local Event Dispatcher
Local Event Dispatcher for invisible barrier.

This Event Dispatcher sends a message to UI every time the player character collides with the drain system, which exists only in this level:

Invisible barriers Invisible barriers
Using an Event Dispatcher instead of a Delegate, because this Event is exclusive of this level.

This is the listener in Hints Panel UI Event Graph:

Listener in Hints Panel Listener in Hints Panel
Listener in Hints Panel.

And this is the Custom Event updating text:

Custom Event Custom Event
Custom Event updating text for invisible barrier.

There is a lot more about programming UI and Interaction in Real Time. Delegates are just one tool in a big set which happen to work right for this specific project. Take a closer look at other tool‑sets by visiting these case studies:

Programming video game interaction with C++
Programming interaction

The C++ Interface is able to identify when the player picks up an item, adds to the counter, loops remaining and sends delegates when all collected.

Implementing Interface for video game with C++
Implementing C++ Interface

The C++ interface becomes active when overlapping items, sends delegates when the player clicks the “E” key, modifying the environment and other actors.

Adding Input Action from C++ into Unreal Engine
Adding Input Action in C++

Using the existing C++ third person character syntax to create an additional input action binding on UProperties, protected functions, and source.

Programming Gameplay with C++ for Unreal Engine
Programming Gameplay C++

Programming interaction for gameplay in C++ for Unreal Engine, using an interface, delegates and 2 bases for pickups and doors.

Programming automation tool with Python for Maya
Programming Python Tool

Programming an automation tool for Maya using Python to sort unnamed meshes into a conventional hierarchy in outliner by renaming and resetting pivots.

Discover Technical Skills