使用UMG的用户界面

使用UMG创建简易的菜单系统

Windows
MacOS
Linux

在本教程中,可学习使用虚幻示意图形(UMG)构建具有多屏幕和按钮的基本菜单系统。

1.设置UMG的模块依赖性

如首次使用 虚幻引擎4,建议先阅读编程快速入门 tutorial。本教程将假设您已熟悉项目的创建、向其中添加C++代码,以及编译代码。同时也会向 蓝图 公开函数和属性。如欲了解更多信息,可从变量、定时器和事件 tutorial入手。

  1. 将从新建项目开始:

    • 选择“C++”选项卡。

    • 选择“基础代码”。

    • 保留“桌面/主机平台机(Desktop/Console)”和“使用初学者内容包(With Starter Content)”的默认设置。

    • 将项目命名为HowTo_UMG。

    UMG_ProjectSetup.png

    由于要编写使用 虚幻运动图形(UMG) 的代码,因此需进入 Visual Studio,获取部分默认不可用的模块。

  2. 使用主编辑器界面上 文件 下拉菜单中的 打开Visual Studio 命令来获取项目代码。

    OpenVisualStudio.png

  3. UMG依赖于模块,因此需将此类模块添加至HowTo_UMG.Build.cs中。

    BuildCS.png

    在HowTo_UMG.Build.cs中,需将UMG添加到包含的公共模块列表中,并将Slate和SlateCore添加到包含的私有模块列表中。需对HowTo_UMG的构造函数首行进行如下修改:

    PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "UMG" });

    然后将以下行取消注释:

    PrivateDependencyModuleNames.AddRange(new string[] { "Slate", "SlateCore" });

    完整源代码提供如下,以便仔细核对代码。


设置UMG后,可在项目的自定义 游戏模式 中添加代码,以创建和显示游戏菜单。

半成品代码

HowTo_UMG.Build.cs

// Copyright 1998-2018 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");
        //      }
        // }
    }
}

2.扩展游戏模式

  1. 创建的菜单将由 用户控件 组成。需编写函数以新建并显示用户控件,然后在游戏开始时调用该函数。同时还需追踪创建内容,以便之后进行删除。各项目已有自定义 游戏模式 类,可直接打开,其在HowToUMGGameMode.h中被定义。需将以下函数和属性添加到类的底部:

    public:
        /** 移除当前菜单控件,并在指定类(如有)中新建控件。*/
        UFUNCTION(BlueprintCallable, Category = "UMG Game")
        void ChangeMenuWidget(TSubclassOf<UUserWidget> NewWidgetClass);
    
    protected:
        /** 游戏开始时调用。*/
        virtual void BeginPlay() override;
    
        /** 游戏开始时,用作菜单的控件类。*/
        UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UMG Game")
        TSubclassOf<UUserWidget> StartingWidgetClass;
    
        /** 用作菜单的控件实例。*/
        UPROPERTY()
        UUserWidget* CurrentWidget;
  2. 为在代码中使用用户控件,需在#include部分的顶部添加以下行:

    #include "Blueprint/UserWidget.h"
  3. 现在开始处理HowTo_UMGGameMode.cpp,需填充声明的两个函数的主体。将从覆盖 BeginPlay() 开始:

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

    覆盖父类(由单词Super引用)中的函数时,正如现在覆盖BeginPlay,务必调用该函数的父类版本。由于函数版本仅意图在现有过程的最后增加步骤,因此在该函数首行中调用 Super::BeginPlay

  4. 接下来,同样在HowTo_UMGGameMode.cpp中,需定义菜单间的变化。如视口中存在活跃的用户控件,需将其移除。然后可新建用户控件,并将其添加到视口中。

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

    此代码将创建所提供 控件 的实例,并将其放置在屏幕上。该代码同样可将其移除,以便每次仅有一个活跃控件,尽管 虚幻引擎 可同时处理显示多个控件并与之交互。由于在视窗中将其移除和清除(或修改)引用其的所有变量,都将导致虚幻引擎的垃圾回收系统将其清除,因此无需直接销毁控件。

  5. 最后,需要在 玩家控制器(Player Controller) 类上设置输入模式。为此,在项目中添加基于 玩家控制器 的新C++类。游戏开始时,只需在此类中调用一个额外函数,便能确保与UI元素进行交互。

    NewClass.png PlayerController.png

    在HowTo_UMGPlayerControlle.h中,将向该类添加以下覆盖:

    public:
        virtual void BeginPlay() override;

    在HowToUMGPlayerController.cpp中,将添加被覆盖的函数:

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

代码框架已构建完毕,以创建和显示菜单并在无需要时将其删除。现在返回 虚幻编辑器,开始设计菜单资源吧!

成品代码

HowTo_UMG.Build.cs

// Copyright 1998-2018 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-2018 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:
    /** 移除当前菜单控件,并在指定类(如有)中新建控件。*/
    UFUNCTION(BlueprintCallable, Category = "UMG Game")
    void ChangeMenuWidget(TSubclassOf<UUserWidget> NewWidgetClass);

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

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

    /** 用作菜单的控件实例。*/
    UPROPERTY()
    UUserWidget* CurrentWidget;
};

HowTo_UMGGameMode.cpp

// Copyright 1998-2018 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-2018 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-2018 Epic Games, Inc. All Rights Reserved.

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

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

3.创建菜单空间蓝图

  1. 虚幻编辑器 中,可按 编译 按钮构建新代码。利用此操作可将 用户控件 用作菜单。

    CompileFromEditor.png

  2. 现在创建被 游戏模式 用作菜单的用户控件。通过 内容浏览器 中的 新增(Add New) 按钮,即可完成此操作。控件蓝图 类位于 用户界面 类别中。需创建两个控件,并分别命名为MainMenu和NewGameMenu。可主菜单开始游戏,同时拥有可进入新游戏菜单的选项。

    CreateWidgetBP.png

  3. 双击刚刚创建的主菜单 控件,前往 蓝图设计器,可在其中创建菜单布局。

  4. 按钮文本控制板面板常用 部分拖入 图表。该按钮将被用于打开新游戏菜单。

    AddButtonAndTextBlock.png

  5. 创建正确布局的首部,便是调整按钮的位置和大小。应进行以下修改:

    • 将大小设为200x200。

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

    • 将其重命名为NewGameButton,以便之后将其与功能连接时进行识别。

    ButtonDetails.png

  6. 由于未绘制一套按钮的自定义图像,因此可通过将文本块拖放到按钮上并进行以下修改,以标记按钮:

    • 设置“新游戏”的文本显示。

    • 将可见性改为“点击测试不可见”。此操作可防止文本块阻碍鼠标点击下方按钮。

    • 将命名设为NewGameText。此并非必要步骤,而是好习惯。

    TextBlockDetails.png

  7. 接下来,将使用第二个按钮和文本块,创建“退出”功能。其设置方法与新游戏按钮和文本块的设置方法相同,但有以下变化。

    • 将按钮命名设为QuitButton

    • 将按钮的位置设为(600,100)

    • 将文本块命名设为QuitText

  8. 完成后即可将 事件 添加到按钮,以便点击按钮时运行代码。通过在 细节面板 中找到并按下相应事件命名旁的+号,便能完成此操作。而现在,OnClicked 即是要使用的事件。同时创建NewGameButton和QuitButton控件的的该事件。

    CreateOnClickedEvent.png

    设计师可在此使用 蓝图 脚本构建功能,或C++程序员可连接调用公开函数的节点。

  9. 对于名为 OnClicked(NewGameButton) 的事件,需:

    • 连接 ChangeMenuWidget 节点,以使用之前添加到GameMode中的功能。

    • 将 ChangeMenuWidget 节点上的 新控件类** 字段设为NewGameMenu资源。

    OnClicked_NewGame.png

  10. 对于名为 OnClicked(QuitButton) 的事件,需:

    • 连接 Quit Game 节点。

    OnClicked_Quit.png

构建主菜单后,可设置在关卡启动时立即加载主菜单的GameMode资源。

4.配置游戏模式

  1. 基于项目的 GameMode,在 内容浏览器 中添加 蓝图类.利用此操作,可将这两个类上的公开变量设为需要的值。为此,需:

    • 内容浏览器 中点击的 添加 按钮。

    AddNewBPClass.png

    • 选择 HowTo_UMGGameMode 作为父类。其将被列入 所有类(All Classes) 部分。

    PickParentClassForGameModeBP.png

    • 将得到的蓝图资源命名为MenuGameMode。

  2. 为使游戏光标出现在游戏中,需进行GameMode中的相同操作,创建 PlayerController 的蓝图。

    • 内容浏览器 中再次点击 添加 按钮。

    • 常用类(Common Classes) 部分选择 玩家控制器

    • 将该蓝图命名为MenuPlayerController。

  3. 编辑MenuPlayerController。

    • 勾选 显示鼠标光标(Show Mouse Cursor) 复选框。

    GamePlayerController.png

  4. 编辑MenuGameMode。

    • 须将 启动控件类(Starting Widget Class) 设为MainMenu资源,以便在游戏开始时打开菜单。

    • 应将 默认Pawn类(Default Pawn Class) 设为 Pawn 而非 DefaultPawn,玩家便不会在菜单中乱飞。

    • 应将 玩家控制器类 设为创建的MenuPlayerController资源,以便在游戏中显示鼠标光标。

    ConfigureGameMode.png

  5. 为使用蓝图,必返回 关卡编辑器 窗口,并通过 设置 按钮修改当前 关卡场景设置

    WorldSettingsBar.png

    也可在 地图和模式 部分的 项目设置 菜单中,设置默认的游戏模式。如使用此方法,除非进行单独覆盖,所有关卡都将默认使用选定的GameMode。将基于项目设置中的偏好决定使用的方法。

  6. 将打开 场景设置面板。其将默认与 细节面板 停靠,但也可将其移动到其他位置。需将 游戏模式覆盖(Game Mode Override) 字段设为MenuGameMode资源。

    WorldSettings.png

自定义GameMode资源现已在关卡上生效,并被配置以加载主菜单,同时使用显示鼠标光标的玩家控制器。如现在运行游戏,退出按钮将预期生效,使用新游戏按钮将进入空白菜单。将在下一步中设置新游戏菜单。

5.构建二级菜单

  1. 内容浏览器 中,找到并打开之前创建的NewGameMenu资源。该菜单将包含可输入命名的 文本框、开始游戏的 按钮(输入命名前无法按下),及可返回主菜单的按钮。

  2. 为创建命名输入框,需将文本框(而非 文本块)拖入布局。

    CreateTextEntryBox.png

  3. 应按以下值配置文本框:

    • 将命名改为NameTextEntry

    • 位置(325,200)。此操作可在文本框左侧预留空间,以放置文本块。

    • 尺寸为250x40。

    • 字体大小(在“样式”标头下)为20。

    TextBoxDetails.png

  4. 利用与在上一菜单中创建按钮的相同方式,即可创建带文本块标签的游戏按钮。

    • 对于按钮:将命名改为PlayGameButton,位置 改为(200,300),尺寸 改为(200,100)

    • 对于文本块:将命名改为PlayGameText,将 可见性 设为“点击测试可见”,并将其拖到PlayGameButton的顶部。

  5. “开始游戏”按钮将有一个特殊功能:仅在文本框中输入非空白命名时启用。可使用 虚幻运动图形(UMG)绑定功能新建 已启用(Is Enabled) 字段(在 行为(Behavior) 部分下)的功能。

    PlayGameButtonDetails.png

    如游戏中具有决定有效玩家名称构成的复杂规则,或需将名字保存到C++变量中时,可能需在 GameMode 上公开 UFUNCTION 或在项目中的某处公开静态函数。但由于仅需名称字符串不为空,因此可在 控件 中的此处编写其脚本。

  6. 为确保仅在文本框非空白时启用按钮,可将文本框中的文本转换为字符串,然后检查其长度是否大于零。以下为此逻辑的显示方式:

    PlayGameButtonEnableFunction.png

  7. 再添加一个按钮,以便退出并从此处进入主菜单。添加方式与添加主菜单的“开始游戏”按钮相同,但其位置位于右下角而非左上角。为了完成此操作,点击 细节面板 中的 下拉列表,并在弹出菜单中找到适当的图示。

    • 将命名改为MainMenuButton

    • 位置 设为(-400,-200)

    • 尺寸 设为200x100

    SelectAnchor.png

    将锚放在右下角,此操作不会改变其大小和位置值的工作方式,因此需将位置值设为负值,使其在屏幕中显示。保留尺寸值为正。

  8. 现在再次添加 OnClicked 事件,向新按钮添加脚本。主菜单按钮将简单重加载主菜单控件,在 ChangeMenuWidget 函数的调用中不提供新控件,开始游戏按钮将停止菜单。显示短语 选择类 而非实际类或资产的命名,可对此进行显示。

    NewGameButtonBPs.png

    开始游戏按钮停止菜单后,将无法在游戏中进行任何操作。通常会在此处加载首个关卡、播放开场动画,或生成并拥有 Pawn

  9. 现在应该具备两种屏幕,大致如下:

    FinalScreen.png

    FinalScreen2.png

6.自行尝试!

利用所学内容,尝试以下操作:

  • 同时打开的多个菜单。

  • 在屏幕上滑入或淡入 控件,而非直接显示。

  • 查看控件支持的不同声音、样式和颜色属性。

  • 在菜单中设置 **GameMode 内如难度、角色级别等变量。

  • 创建游戏内菜单,可在玩家按键时弹出并暂停游戏,而在关闭后可继续游戏。

  • 将之前教程中构建或学习的功能关联到在 虚幻示意图形(UMG)中构建的菜单。

本教程中讲解的相关细节:

Select Skin
Light
Dark

欢迎来到全新虚幻引擎4文档站!

我们正在努力开发新功能,包括反馈系统,以便您能对我们的工作作出评价。但它目前还未正式上线。如果您对此页面有任何意见与在使用中遭遇任何问题,请前往文档反馈论坛告知我们。

新系统上线运行后,我们会及时通知您的。

发表反馈意见