It's tough to know where to start when setting up the UI for your game. There are a lot of existing Unreal classes that are suitable for housing your UI-related code. I'll describe what has worked for me so far.
- First, we will create some base C++ classes from which our Blueprints will derive.
- Then we will create the Blueprint subclasses, and make Unreal use them.
- We will add example functions to create a widget on calling
ShowMenu()
, and hide on callingHideMenu()
.
Create C++ Subclasses
A lot of Unreal setup boils down to subclassing existing classes to specify
custom behaviour. In this case we will need to subclass AGameModeBase
and
AHUD
in order to set up our custom UI manager.
Create C++ Subclass of AGameModeBase
If you haven't done it already, create a C++ or Blueprint subclass of
AGameModeBase
. We will need to use this to specify which HUD class is used
in our levels. It's useful in general for choosing custom subclasses of
APlayerController
, AGameState
and other core classes.
I recommend creating a C++ base class, and then a Blueprint subclass of that. I prefer to write logic in the C++ class so debugging and breakpoints are all available from C++ and then use Blueprint-exposed properties to connect things together and set gameplay variable values.
For this example we will be using the naming conventions described in UI Best Practices.
The easiest way to create a new C++ subclass is under File > New C++ Class
Class diagram for our game mode class and Blueprint
The default generated C++ is fine for what we need. We will be specifying our
custom AHUD
subclass in the blueprint.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/GameModeBase.h"
#include "BUIGameModeBase.generated.h"
UCLASS()
class EXAMPLE_API ABUIGameModeBase : public AGameModeBase
{
GENERATED_BODY()
};
As a side-note there is also a built-in Unreal class named AGameMode
, but
I would recommend using AGameModeBase
. AGameMode
is somewhat of a relic
Unreal Engine's past as an engine that focused on match-based shooters, and
comes with a lot of built-in functionality that is not always useful.
Create C++ Subclass of AHUD
In the same way we created a subclass of AGameModeBase
, now we will create
a C++ subclass of AHUD
. AHUD
is a class that is created by and owned by
APlayerController
. For our purposes it will do fine.
Class diagram for our custom subclasses of AHUD.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/HUD.h"
#include "BUIHUD.generated.h"
UCLASS()
class EXAMPLE_API ABUIHUD : public AHUD
{
GENERATED_BODY()
};
The default BUIHUD.h
and BUIHUD.cpp
are OK, we will be adding functionality
to it after we have hooked them up in Unreal.
Create Blueprint subclasses
Now that we have created C++ classes ABUIGameModeBase
and ABUIHUD
, we can
re-start Unreal and create our Blueprint subclasses.
Right-click in the Content Browser, and choose Blueprint Class from the pop-up menu. See the diagram below
- We will now need to set the C++ parent class for this Blueprint. Choose
BUIGameModeBase
and name your blueprintBP_GameMode
. - Do the same for
BUIHUD
, creating a Blueprint calledBP_HUD
.
Creating Blueprint subclass of ABUIGameModeBase
With both Blueprints created, we can now set BP_GameMode
to use BP_HUD
as
its HUD class.
World Settings
In order for our custom BP_GameMode
Blueprint to be used, we must set it in
the World Settings for our level. This window can be opened with:
Window > World Settings.
Then choose BP_GameMode
from the GameMode Override dropdown.
Set the custom BP_GameMode in World Settings
Using HUD Subclass to Create Example Main Menu
Phew, that was a lot of set-up, but thankfully we only have to do it once. Adding functionality from now on will be much easier.
We can now use our ABUIHUD
class as the manager for our UI.
Let's add an example function that creates a MainMenu widget when a function is called.
BUIHUD.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/HUD.h"
#include "BUIHUD.generated.h"
UCLASS( Abstract )
class EXAMPLE_API ABUIHUD : public AHUD
{
GENERATED_BODY()
// Make BlueprintCallable for testing
UFUNCTION( BlueprintCallable )
void ShowMainMenu();
UFUNCTION( BlueprintCallable )
void HideMainMenu();
protected:
UPROPERTY( EditDefaultsOnly )
TSubclassOf<class UUserWidget> MainMenuClass;
// Keep a pointer to be able to hide it
UPROPERTY()
class UUserWidget* MainMenu;
};
BUIHUD.cpp
#include "BUIHUD.h"
#include <GameFramework/PlayerController.h>
#include <Blueprint/UserWidget.h>
#include <Kismet/GameplayStatics.h>
void ABUIHUD::ShowMainMenu()
{
// Make widget owned by our PlayerController
APlayerController* PC = Cast<APlayerController>( GetOwner() );
MainMenu = CreateWidget<UUserWidget>( PC, MainMenuClass );
MainMenu->AddToViewport();
}
void ABUIHUD::HideMainMenu()
{
if ( MainMenu )
{
MainMenu->RemoveFromViewport();
MainMenu = nullptr;
}
}
If we create a test main menu UUserWidget
Blueprint, and set the
MainMenuClass
property in BP_HUD
, we can spawn it when the ShowMainMenu()
function is called.
Showing Main Menu from C++
From C++ showing the main menu would look like this:
APlayerController* PC = UGameplayStatics::GetPlayerController( GetWorld() );
ABUIHUD* HUD = PC->GetHUD<ABUIHUD>();
HUD->ShowMainMenu();
Showing Main Menu from Blueprints
From Blueprints showing the main menu would look like this:
Simple test Blueprint to show and hide the main menu
Final Result
Look, we have a menu, managed in a AHUD
subclass, and created via C++!