Create and Use Delegates in Unreal Engine 5 Using C++

Just like Event Dispatchers, delegates are a great way to communicate with different actors and classes throughout the program.

Unreal Engine 5 Quinn mannequin standing on the increment mana platform inside the delegate playground
Quinn increasing mana

Software Versions: Unreal Engine 5.4.4 | Rider 2024.2.7

Project Name: MyProject

Similar to event dispatchers, Unreal C++ delegates are used to communicate with other classes, actors, and, objects in the world.

This example branches off the previous post about BP event dispatchers, so rather than health, I updated the W_Health_Mana User Widget with a mana progress bar.

Unreal Engine 5 user widget designer with health and mana progress bars
User Widget with health and mana

Next, in this example I created a component that can be added to any actor to react or bind to the delegate event.

Rider create a new actor component
Rider new actor component class

In an attempt to keep things simple, this component is extremely light and only declares a delegate. Delegates can absolutely be used in a variety of ways, another great delegate example is Epic's First Person Shooter Template PickUp Class. The .cpp file will be empty this example.

MyDelegateComponent.h

#pragma once

#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "MyDelegateComponent.generated.h"

UDELEGATE(BlueprintCallable)
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FUpdateManaCPP, float, ManaValue);

UCLASS(ClassGroup=(Custom), meta=(BlueprintSpawnableComponent))
class MYPROJECT_API UMyDelegateComponent : public UActorComponent
{
	GENERATED_BODY()

public:
	/** Delegate to whom anyone can subscribe to receive this event */
	UPROPERTY(BlueprintCallable, BlueprintAssignable, Category = "Mana")
	FUpdateManaCPP UpdateManaCPP;
};

Above UCLASS we declare one delegate signature called FUpdateManaCPP that accepts one float parameter called ManaValue. Then in the class we declare UpdateManaCPP that can be used throughout the code base.

We can now add this component to any actor. In this example I copied over the Third Person template character Blueprint and added the component to the BP along with the widget.

Unreal Engine 5 third person character template Blueprint with MyDelegate component added
BP_ThirdPersonCharacter_Health

With the component added we can now call it from another actor. Next, we can create a simple actor that when the character overlaps it we can broadcast the event with value that will update the character's total Mana.

MyDelegateActorTrigger.h

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "MyDelegateActorTrigger.generated.h"

class UBoxComponent;
class UTextRenderComponent;

UCLASS()
class MYPROJECT_API AMyDelegateActorTrigger : public AActor
{
	GENERATED_BODY()

public:
	// Sets default values for this actor's properties
	AMyDelegateActorTrigger();

	UPROPERTY(EditAnywhere)
	USceneComponent* DefaultSceneRoot;

	UPROPERTY(EditAnywhere)
	UStaticMeshComponent* MyMesh;

	UPROPERTY(EditAnywhere)
	UBoxComponent* MyBox;

	UPROPERTY(EditAnywhere)
	UTextRenderComponent* MyText;
	
	UPROPERTY(EditAnywhere)
	float ManaValue = -10.0f;

	UFUNCTION()
	void OnBeginOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult);
};

MyDelegateActorTrigger.cpp

#include "MyDelegateActorTrigger.h"
#include "MyDelegateComponent.h"
#include "Components/BoxComponent.h"
#include "Components/TextRenderComponent.h"

// Sets default values
AMyDelegateActorTrigger::AMyDelegateActorTrigger()
{
	DefaultSceneRoot = CreateDefaultSubobject<USceneComponent>(TEXT("DefaultSceneRoot"));
	DefaultSceneRoot->bVisualizeComponent = true;
	RootComponent = DefaultSceneRoot;
	
	MyMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("MyMesh"));
	MyMesh->SetupAttachment(RootComponent);

	MyText = CreateDefaultSubobject<UTextRenderComponent>(TEXT("MyText"));
	MyText->SetupAttachment(RootComponent);

	MyBox = CreateDefaultSubobject<UBoxComponent>(TEXT("MyBox"));
	MyBox->OnComponentBeginOverlap.AddDynamic(this, &AMyDelegateActorTrigger::OnBeginOverlap);
	MyBox->SetupAttachment(RootComponent);
}

void AMyDelegateActorTrigger::OnBeginOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
	if (OtherActor && OtherActor != this)
	{
		UMyDelegateComponent* MyDelComp = OtherActor->FindComponentByClass<UMyDelegateComponent>();
		
		if (MyDelComp != nullptr)
		{
			MyDelComp->UpdateManaCPP.Broadcast(ManaValue);
		}
	}
}

The MyDelegateActorTrigger is a basic actor that has a few components to build it up, but most importantly it has box collision component that on overlap broadcasts to the character's MyDelegateComponent's UpdateManaCPP function and passes along the ManaValue to the event.

Everything can be done in a variety of ways, for simplicity I decided to just quickly update the character's mana value inside the UserWidget. Not the best for long term practice, but I wanted to just quickly bind to an C++ delegate and have the UI react.

Unreal Engine 5 user widget graph with health and mana bindable events
W_Health_Mana graph

With everything in place we can start building the level. I created two Blueprints inheriting from MyDelegateActorTrigger, I only had to update the mesh, change the material, and set the material. I set the first trigger to have a mana value of -10.0f to decrease the player's mana while the second platform has a value of 10.0f to increase the player's mana.

Below is the final result.

Unreal Engine 5 character running to two glowing platforms to decrement and increment the player's mana value
Quinn running to the platforms

I hope this helps. I'm looking forward to using delegate more in the future.

Loading...