5. 建立第二菜单

使用新功能建立第二菜单。

Windows
MacOS
Linux
  1. Content Browser(内容浏览器) 中,搜寻并打开我们之前创建的NewGameMenu资源。 这个菜单包含了一个名称条目 Text Box(文本框) ,只有在输入名称后才能通过按下 Button(按钮) 来游玩游戏,还有一个可供点击以返回主菜单的Button(按钮)。

  2. 如需创建名称条目框,我们可以拖曳Text Box(文本框)(而不是 Text Block(文本块) )到布局中。

    CreateTextEntryBox.png

  3. Text Box(文本框)应使用以下值进行配置: 将名字改成NameTextEntry 位置是(325, 200)。 这样可以留出空间以把 Text Block(文本块) 放置于Text Box(文本框)的左侧。 大小是250x40。 字体大小(位于"风格"标题栏下)是20。

    TextBoxDetails.png

  4. 我们可以创建具有Text Block(文本块)标记的Play Game Button(玩游戏按钮),按照我们在上一菜单中创建Button(按钮)的相同方式进行标记。 对按钮来说:将名称变更为PlayGameButton, 位置 变更为200, 300, 大小 变更为200, 100 对于文本块来说: 变更名称为PlayGameText,设置 可见度 为Hit Test Visible,然后将其拖曳到PlayGameButton的顶部位置

  5. Play Game(玩游戏)的Button(按钮)有一个特殊功能 - 它只有在输入Text Box(文本框)的名称为非空时,才会被启用。 我们可以使用 Unreal Motion Graphics'(虚幻运动图形) (UMG)的bind(绑定)功能来为"Is Enabled"域创建新函数(在 操作 部分下方)。

    PlayGameButtonDetails.png

    如果用于确定组成游戏中有效玩家名称的规则很复杂,或者,如果我们需要保存名称到C++变量中,我们可以在 Game Mode(游戏模式) 中显示 UFUNCTION ,或者在我们的项目中的某个位置将其作为静态函数来处理。 但是,因为我们只关心名称字符串是否为非空,我们可以直接在 Widget(控件) 中对其进行脚本处理。

  6. 为确保仅在Text Box(文本框)非空的情况下启用Button(按钮),我们可以转换来自于Text Box(文本框)的文本到字符串中,然后检查其长度是否大于0。 以下是整个逻辑:

    PlayGameButtonEnableFunction.png

  7. 让我们再添加一个Button(按钮),这样我们可以返回并从此处转到主菜单。 它就和主菜单的玩游戏的Button(按钮)一样,但它被放置于靠近右下角而不是左上角的位置。 为完成这个目标,对于Button(按钮),您可以点击 Details Panel(详细信息面板)Anchors(菜单锚点) 下拉框,然后在弹出菜单中找到合适的图表内容。 将名字改成MainMenuButton 设置 位置 为 -400, -200。 * 设置 **大小** 为200x100。

    SelectAnchor.png

    把菜单锚点放置在右下角不会变更大小和位置值,因此我们需要让位置值为负值,从而使之出现在屏幕上。 大小值保持为正值。

  8. 现在我们会通过再次添加 OnClicked 事件来添加脚本到新建Buttons(按钮)中。 主菜单的Buttons(按钮)会直接载入主菜单的Widget(控件),而玩游戏的Buttons(按钮)会因为没有在对 ChangeMenuWidget 函数的调用中提供新的Widget(控件)而完全取消激活菜单。 这是通过显示的 Select Class"(选择类) 来展示出来的,而不是通过实际类或资源的名称来展示的。

    NewGameButtonBPs.png

    在使用玩游戏Buttons(按钮)来取消激活菜单后,我们将无法继续在游戏中执行任何操作。 这个时候我们一般就载入第一个关卡,播放一下介绍性的过场动画、或者生成并放置 Pawn


Finished Code

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/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-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();
        }
    }
}
Select Skin
Light
Dark

Welcome to the new Unreal Engine 4 Documentation site!

We're working on lots of new features including a feedback system so you can tell us how we are doing. It's not quite ready for use in the wild yet, so head over to the Documentation Feedback forum to tell us about this page or call out any issues you are encountering in the meantime.

We'll be sure to let you know when the new system is up and running.

Post Feedback