Sponsored By

UE4Cookery CPP002: Static delegate trick

Topic: Static delegate trick

Source for UE4.23: https://github.com/klauth86/UE4Cookery/tree/main/CPP002

Artur Kh, Blogger

March 5, 2021

3 Min Read

Sometimes we need to implement interaction between classes from different layers. For example, let's take a look at Player class and it's interaction with some UI Widget. Let it be UI Widget for Game Menu with floating Show/Hide mechanic. The main thing - how can we pass some signal from Player to UI Widget. One approach - to include all stuff, use UGameplayStatics to get Player instance and so on. However, this approach make it a little bit too coupled. One trick, that can be used here - static delegate. Let's make it through step by step.

First of all, lets create namespace, that will hold all UI Delegates. Also we add forward declaration for Player class. So that will be

 

UIDelegates.h


#pragma once

#include "Delegates/DelegateCombinations.h"

class AMyDefaultPawn;

namespace UIDelegates {

	DECLARE_MULTICAST_DELEGATE_OneParam(FToggleMenuEvent, AMyDefaultPawn*);

	extern FToggleMenuEvent OnToggleMenu;
};

 

and don't forget to add definition for extern thing in CPP

 

UIDelegates.cpp


#include "UIDelegates.h"

UIDelegates::FToggleMenuEvent UIDelegates::OnToggleMenu;

 

Ok, now we need to see Player class that will use it

 

MyDefaultPawn.h


// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "GameFramework/DefaultPawn.h"
#include "MyDefaultPawn.generated.h"

UCLASS()
class CPP002_API AMyDefaultPawn : public ADefaultPawn {

	GENERATED_BODY()

protected:

	virtual void SetupPlayerInputComponent(UInputComponent* InInputComponent) override;

	void ToggleMenu();
};

 

MyDefaultPawn.cpp


// Fill out your copyright notice in the Description page of Project Settings.

#include "MyDefaultPawn.h"
#include "Components/InputComponent.h"
#include "UIDelegates.h"

void AMyDefaultPawn::SetupPlayerInputComponent(UInputComponent* InInputComponent) {
	Super::SetupPlayerInputComponent(InInputComponent);

	InInputComponent->BindAction("ToggleMenu", IE_Pressed, this, &AMyDefaultPawn::ToggleMenu);
}

void AMyDefaultPawn::ToggleMenu() { UIDelegates::OnToggleMenu.Broadcast(this); }

 

And what about UI Widget? It can be very simple, just like this

 

GameMenuWidget.h


// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "Blueprint/UserWidget.h"
#include "GameMenuWidget.generated.h"

class AMyDefaultPawn;

UCLASS()
class CPP002_API UGameMenuWidget : public UUserWidget {

	GENERATED_BODY()

public:

	UFUNCTION(BlueprintImplementableEvent, category = "Game Menu Widget")
	void OnToggleMenu(AMyDefaultPawn* pawn);

protected:

	virtual void NativeConstruct();

	virtual void NativeDestruct();
};

 

GameMenuWidget.cpp


// Fill out your copyright notice in the Description page of Project Settings.


#include "GameMenuWidget.h"
#include "UIDelegates.h"

void UGameMenuWidget::NativeConstruct() {
	Super::NativeConstruct();
	UIDelegates::OnToggleMenu.AddUObject(this, &UGameMenuWidget::OnToggleMenu);
}

void UGameMenuWidget::NativeDestruct() {
	UIDelegates::OnToggleMenu.RemoveAll(this);
	Super::NativeDestruct();
}

 

Note, that all subscriptions are operated in NativeConstruct and NativeDestruct methods. The first one is called just before Widget is added to Display hierarchy and the second - when it is removed from hierarchy. As for BlueprintImplementableEvent - they are used to implement some logic in BPs for things that have hard dependencies with visual elements.

 

So, let's do the last things - create BP around our UI Widget and put some visual logic to it:

 

BP_GameMenuWidget_Designer

BP in Designer

 

BP_GameMenuWidget_Graph

BP Graph

 

And that's it! And here is raw result

Result

 

So, static delegates can be really helpful in the sense of accessing objects (when it is a problem to access them directly) and resolving class dependencies and coupling...

Read more about:

Blogs

About the Author(s)

Daily news, dev blogs, and stories from Game Developer straight to your inbox

You May Also Like