multiplayer game menus (C++ and UMG)

When it comes to creating menus, the official documentation suggests adding a function GameMode::ChangeMenuWidget() which is then called from the UMG widget button’s OnClicked event:


void AHowTo_UMGGameMode::ChangeMenuWidget(TSubclassOf<UUserWidget> NewWidgetClass)
{
    if (CurrentWidget != nullptr)
    {
        CurrentWidget->RemoveFromViewport();
        CurrentWidget = nullptr;
    }
    if (NewWidgetClass != nullptr)
    {
        CurrentWidget = CreateWidget<UUserWidget>(GetWorld(), NewWidgetClass);
        if (CurrentWidget != nullptr)
        {
            CurrentWidget->AddToViewport();
        }
    }
}

It seems this wouldn’t work for a multiplayer game because the GameMode only exists on the server! Isn’t this teaching bad practices since it won’t work for multiplayer game?

What classes would be better candidates for the menu switching logic in C++?

AHUD exists only on client but does menu related functionality typically go there as well? Would GameInstance class also be a candidate for this type of functionality?

I agree that it is not a good practise to add UMG related code to the game mode, may work in the main menu and singleplayer games but not in multiplayer. What I typically do is to have different AHUD derived classes for example for the spawn screen UI and in game UI. The player controller can then switch between those HUD classes as its state changes, you could even have the server do a client RPC to change the HUD for the client. However I usually don’t actually draw anything in the HUD classes, their purpose is just to add a UMG widget in BeginPlay and remove it again in EndPlay. This works very well and efficiently imo, the UMG widgets always get cleaned up nicely when the HUD is changed and the HUD class can have specialized logic to control the “meta” level of the widgets. When it comes to widgets that have to be always visible across different HUD’s, like chat boxes or the in game settings menu, I would manage that on the player controller class (possibly better on ULocalPlayer) because you can listen for input on it and for example prevent the cursor from becoming visible if you know the menu is open.

I do something similar with the HUD class and player controller. I use the HUD class like you said to add and remove UMG widgets only and the player controller interacts with it when the state is changing. But I only figured this out after a lot of research because some of the official documentation and training videos I saw try creating and adding widgets to viewport in Character blueprint BeginPlay which seems like another bad practice because they exist on clients & server.

So for in game pause menu you might have something like this in PlayerController when player hits a key:


void AMyPlayerController::ShowPauseMenu()
{
  if(IsLocalPlayerContoller())
  {
    SetInputMode(...);
    MyPauseMenuWidget->AddToViewport();
  }
}

Do you usually manage your main menu system fully in Blueprint or do your OnClicked button events call into a C++ functions to manage switching between the menus and adding widgets to viewport?

I never heard of ULocalPlayer class but it looks promising… I wonder if it’s common to use this class for managing UMG widgets.

ULocalPlayer exists through the entirity of the game afaik, so also across loading new levels. I just threw it in there because it is something to maybe consider, but actually thinking about it the player controller is probably the better place for this after all :slight_smile: In terms of blueprints I try to do everything design related in Blueprints and everything that actually does stuff in C++. So for example I would do switching between audio and video menus fully in blueprints, but dragging any settings slider calls a C++ function to apply the setting. Generally I would consider anything above like 3-5 nodes for one blueprint event too much :stuck_out_tongue:

Thanks for the response… you confirmed a couple of design decisions I made in my project. The only thing you didn’t mention was GameInstance class which persists for entire game and through loading new levels.

In the ‘Blueprint Multiplayer’ training video series they use GameInstance for functions like ‘ShowMainMenu’ and ‘ShowOptionsMenu’:https://youtube.com/watch?v=78XJYBfWXAA
So maybe GameInstance would also be good to consider for any C++ related menu logic. The PlayerController still seems like a good place for the in game menus (like Pause menu) because we need to respond to player input to toggle the menu in game. PlayerController gets the input and it has to somehow call “Show Pause Menu” or “Hide Pause Menu” when responding to player input.

Maybe it’s possible to have a function like this in PlayerController:


void AMyPlayerController::PauseButtonPressed()
{
  GetWorld()->GetGameInstance()->ShowPauseMenu();
}

This seems like a good design to me because then our PlayerController still responds to player input but all of our menu-related logic is contained within our GameInstance (which is persistent throughout the entire game). And our state-related UMG (like health bars or gameplay screens) is still handled through AHUD. What do you think?

I appreciate your commitment to writing nice code :slight_smile: I think doing UMG related code on the game instance does make sense in a way considering you can create widgets with a game instance as argument. However personally I feel like the game instance isn’t really player or user interface related. Also considering that for example if you were to make a splitscreen game there would still be only one game instance for all players, so it wouldn’t really work to have individual widgets UNLESS you needed shared widgets in that case it could be nicer. Another argument would be that you are making your life harder by controlling the UI with the player controller but over the game instance, a step which you could avoid. One thing that is a slight caveat of handling it on the player controller is that it also exists on the server and therefore kinda unnecessarily uses memory for pointers etc that only the client needs, but really it does the same thing for other features by default and the technical disadvantage is beyond tiny :stuck_out_tongue:

Also keep in mind that official Epic tutorials or even the documentation are not always the definitive answer. Often there are more than one solution and the guys doing these might cut some corners to make it shorter, or sometimes it just isn’t their greatest field of expertise.

As you said gamemode won’t work once you are in Game :frowning: It will only work during mainmenu.

In my opinion HUD class are there to handle that.

HUD class will work for single/local split screen & multiplayer. I think this is the best class for this. Take care that it is only Local so in multiplayer game you need to send RPC from the server if you want some HUD screen to be driven by the server.
Like start a “count down” before starting a match.

Hud can also draw information in the canvas if needed.