Trending
Opinion: How will Project 2025 impact game developers?
The Heritage Foundation's manifesto for the possible next administration could do great harm to many, including large portions of the game development community.
Topic: Static delegate trick
Source for UE4.23: https://github.com/klauth86/UE4Cookery/tree/main/CPP002
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_GameMenuWidget_Graph
And that's it! And here is raw 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:
BlogsYou May Also Like