5. Build A Second Menu

Choose your OS:
  1. In the Content Browser, find and open the NewGameMenu asset we created earlier. This menu will contain a name-entry Text Box, a Button to play the game that cannot be pressed until a name is entered, and a Button to return to the main menu.

  2. To create the name entry box, we'll drag a Text Box (not a Text Block) into the layout.

    CreateTextEntryBox.png

  3. The Text Box should be configured with the following values:

    • Change the name to NameTextEntry

    • Position is (325, 200). This leaves room for a Text Block placed to the left of the Text Box.

    • Size is 250x40.

    • Font Size (under the "Style" heading) is 20.

    TextBoxDetails.png

  4. We can create the Play Game Button with a Text Block label the same way we created the Buttons on the previous menu.

    • For the Button: Change the name to PlayGameButton, Position to 200, 300, Size to 200, 100

    • For the Text Block: Change the name to PlayGameText, set Visibility to Hit Test Visible, and drag it on top of the PlayGameButton

  5. The Play Game Button will have a special feature - it will be enabled only when the name entered in the Text Box is not empty. We can use Unreal Motion Graphics' (UMG) bind feature to create a new function for the Is Enabled field (under the Behavior section).

    PlayGameButtonDetails.png

    If there were complex rules for determining what constitutes a valid player name in our game, or if we needed to save the name to a C++ variable, we might expose a UFUNCTION on our GameMode or as a static function somewhere within our project. However, since we only care that the name string is not empty, we can script it right here in our Widget.

  6. To ensure that the Button is enabled if and only if the Text Box is not empty, we can convert the text from the Text Box to a string and then check that its length is greater than zero. Here is how that logic would appear:

    PlayGameButtonEnableFunction.png

  7. Let's add one more Button so we can back out and get to our Main Menu from here. This will be just like the Play Game Button from our Main Menu, but it will be positioned relative to the lower-right corner instead of the upper-left. To accomplish this, click the Anchors dropdown in the Details Panel for the Button and find the appropriate graphical representation in the pop-up menu.

    • Change the name to MainMenuButton

    • Set the Position to -400, -200

    • Set the Size to 200x100

    SelectAnchor.png

    Positioning our anchor at the lower-right corner does not change how size and position values work, so we'll need to make our position values negative in order to be on the screen. Size values will remain positive.

  8. We will now add scripting to our new Buttons by once again adding OnClicked events. The Main Menu Button will simply reload the Main Menu Widget, while the Play Game Button will deactivate our menu entirely by having no new Widget provided in the call to our ChangeMenuWidget function. This is shown by the phrase Select Class being displayed instead of the name of an actual class or asset.

    NewGameButtonBPs.png

    After deactivating the menu with the Play Game Button, we will be unable to do anything further in our game. This is the point at which we would normally load the first level, play an introductory cutscene, or spawn and possess a Pawn.

  9. We should now have two screens that look roughly as follows:

    FinalScreen.png

    FinalScreen2.png


Finished Code

HowTo_UMG.Build.cs

// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved.

using UnrealBuildTool;

public class HowTo_UMG : ModuleRules
{
    public HowTo_UMG(TargetInfo Target)
    {
        PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "UMG" });

        //PrivateDependencyModuleNames.AddRange(new string[] {  });

        // Uncomment if you are using Slate UI
        PrivateDependencyModuleNames.AddRange(new string[] { "Slate", "SlateCore" });

        // Uncomment if you are using online features
        // PrivateDependencyModuleNames.Add("OnlineSubsystem");
        // if ((Target.Platform == UnrealTargetPlatform.Win32) || (Target.Platform == UnrealTargetPlatform.Win64))
        // {
        //      if (UEBuildConfiguration.bCompileSteamOSS == true)
        //      {
        //          DynamicallyLoadedModuleNames.Add("OnlineSubsystemSteam");
        //      }
        // }
    }
}

HowTo_UMGGameMode.h

// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved.

#pragma once

#include "Blueprint/UserWidget.h"
#include "GameFramework/GameModeBase.h"
#include "HowTo_UMGGameMode.generated.h"

/**
 * 
 */
UCLASS()
class HOWTO_UMG_API AHowTo_UMGGameMode : public AGameModeBase
{
    GENERATED_BODY()

public:
    /** Remove the current menu widget and create a new one from the specified class, if provided. */
    UFUNCTION(BlueprintCallable, Category = "UMG Game")
    void ChangeMenuWidget(TSubclassOf<UUserWidget> NewWidgetClass);

protected:
    /** Called when the game starts. */
    virtual void BeginPlay() override;

    /** The widget class we will use as our menu when the game starts. */
    UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UMG Game")
    TSubclassOf<UUserWidget> StartingWidgetClass;

    /** The widget instance that we are using as our menu. */
    UPROPERTY()
    UUserWidget* CurrentWidget;
};

HowTo_UMGGameMode.cpp

// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved.

#include "HowTo_UMG.h"
#include "HowTo_UMGGameMode.h"

void AHowTo_UMGGameMode::BeginPlay()
{
    Super::BeginPlay();
    ChangeMenuWidget(StartingWidgetClass);
}

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();
        }
    }
}

HowTo_UMGPlayerController.h

// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved.

#pragma once

#include "GameFramework/PlayerController.h"
#include "HowTo_UMGPlayerController.generated.h"

/**
 * 
 */
UCLASS()
class HOWTO_UMG_API AHowTo_UMGPlayerController : public APlayerController
{
    GENERATED_BODY()

public:
    virtual void BeginPlay() override;
};

HowTo_UMGPlayerController.cpp

// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved.

#include "HowTo_UMG.h"
#include "HowTo_UMGPlayerController.h"

void AHowTo_UMGPlayerController::BeginPlay()
{
    Super::BeginPlay();
    SetInputMode(FInputModeGameAndUI());
}