3. 创建菜单控件蓝图

  1. Unreal Editor(虚幻编辑器) 中,我们可以按下 Compile(编译) 按钮来编译新代码。 这样我们就可以把 User Widgets(用户控件) 来作为菜单使用。

    CompileFromEditor.png

  2. 现在我们创建了 User Widgets(用户控件) 以供 Game Mode(游戏模式) 作为菜单使用。 这是使用 Content Browser(内容浏览器) 中的"Add New"(添加新控件)按钮来完成的。 您可以在 User Interface(用户接口) 分类下找到 Widget Blueprint(控件蓝图 类。 我们需要创建两个这样的类,一个名称为"MainMenu",一个名称为"NewGameMenu"。 我们的游戏开始于主菜单,而且可以通过一个选项进入New Game Menu(新游戏菜单)。

    CreateWidgetBP.png

  3. 双击我们刚创建的"MainMenu" Widget(控件) ,进入 Blueprint Designer ,我们可以在其中创建菜单布局。

  4. 让我们从 Palette Panel(Palette面板) 的"Common"(通用)部分拖曳 Button(按钮)Graph(图表) 中。 这个 Button(按钮) 最终会被用于打开New Game Menu(新游戏菜单)。

    AddButtonAndTextBlock.png

  5. 为了让布局看起来正常,第一步是调整 Button(按钮) 的位置和大小。 我们应进行如下变更:

    • 设置大小为200x200。

    • 设置位置为(200, 100)。

    • 将其重命名为"NewGameButton",从而让我们在稍后绑定功能到其上时能更为方便。

    ButtonDetails.png

  6. 由于我们没有对 Button(按钮) 描画自定义图像,我们可以通过拖曳 Text Block(文本块) 到其上来进行标记,并进行如下变更:

    • 设置文本为"New Game(新建游戏)"。

    • 变更可见度为Hit Test Invisible。 这样设置可以防止 Text Block(文本块) 中断用于下方的 Button(按钮) 的鼠标点击。

    • 将名称设置为"NewGameText"。 这不是必需的操作,但这是一个命名的好习惯。

    TextBlockDetails.png

  7. 接下来,我们要使用第二个 Button(按钮)Text Block(文本块) 来制作"Quit"(退出)的功能。 我们按照设置 "New Game" Button(按钮)Text Block(文本块) 的相同方法来进行同样的设置。

  8. 在此之后,我们可以添加 Events(事件)Buttons(按钮) 中,这样在我们按下 Buttons(按钮) 时,我们可以运行代码。 我们可以通过找到并按下 Details Panel(详细信息面板) 中的恰当的 Event(事件) 名称旁的"+"来完成。 本例中,"OnClicked"是唯一可用的 Event(事件) 。 对NewGameButton和QuitButton Widgets(控件) 均创建此事件。

    CreateOnClickedEvent.png

    设计师可以使用此处的 Blueprint蓝图 脚本来编译功能,C++程序员也可以连接调用了显示函数的节点。

  9. 对名称为"OnClicked(NewGameButton)"的 Event(事件) ,我们想要进行如下操作:

    • 连接 ChangeMenuWidget 节点以使用我们之前添加到 Game Mode(游戏模式) 的函数。

    • 设置 ChangeMenuWidget 节点的New Widget Class(新控件类)域到"NewGameMenu"资源。

    OnClicked_NewGame.png

  10. 对名称为"OnClicked(QuitButton)"的 Event(事件) ,我们想要进行如下操作:

    • 连接"Quit Game"(退出游戏)节点。

    OnClicked_Quit.png


在编译了主菜单后,我们可以设置 Game Mode(游戏模式) 资源,它会在关卡开始时进行载入。

完成的代码

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[] {  });

        // 如果您正在使用Slate UI则取消注释
        PrivateDependencyModuleNames.AddRange(new string[] { "Slate", "SlateCore" });

        // 如果您正在使用在线功能则取消注释
        // 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/GameMode.h"
#include "HowTo_UMGGameMode.generated.h"

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

public:
    /** 在游戏开始时调用。 */
    virtual void BeginPlay() override;

    /** 移除当前菜单控件并且如果可能,从指定类中创建新控件。 */
    UFUNCTION(BlueprintCallable, Category = "UMG Game")
    void ChangeMenuWidget(TSubclassOf<UUserWidget> NewWidgetClass);

protected:
    /** 在游戏开始时我们将作为菜单使用的控件类。 */
    UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UMG Game")
    TSubclassOf<UUserWidget> StartingWidgetClass;

    /** 用作为菜单的控件实例。 */
    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();
        }
    }
}