2. 扩展游戏模式
我们创建的菜单来自于 User Widgets(用户控件) 。 我们需要写一个创建和展示新 User Widgets(用户控件) 的函数,然后在游戏启动时调用该函数。 我们还需要追溯已经创建的内容,这样我们可以在稍后移除它。 由于每个项目已经有了自定义的 Game Mode(游戏模式) 类,我们可以打开自己的类,它在
HowTo_UMGGameMode.h
中进行定义。 我们需要添加以下函数和属性到类的底部位置: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;
为了在代码中使用 User Widgets(用户控件) ,我们添加以下行到"#include"部分的顶部位置:
#include "Blueprint/UserWidget.h"
现在在
HowTo_UMGGameMode.cpp
中,我们需要填充两个声明的函数主体。 我们首先从BeginPlay()开始:void AHowTo_UMGGameMode::BeginPlay() { Super::BeginPlay(); ChangeMenuWidget(StartingWidgetClass); }
当我们从父类中覆盖函数时(由Super字符所引用),正如我们在此处使用 BeginPlay 所做的,调用该函数的父类版本一般都很重要。 由于我们的函数版本仅用于对已存步骤的结束处添加一个步骤,我们在函数的第一行中调用 Super::BeginPlay 。
接下来,在
HowTo_UMGGameMode.cpp
中,我们需要定义如何在菜单间进行变更。 我们需要从视口中移除任意激活的 User Widget(用户控件) (如存在的话)。 然后我们可以创建新的 User Widget(用户控件) 并将其添加到视口中。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(); } } }
这个代码将会创建我们提供的任意 Widgets(控件) 的实例,并将其放置于屏幕上。 它也可以用来移除实例,所以即使 Unreal Engine(虚幻引擎) 可以同时处理许多 Widgets(控件) 的显示和互动,一次也只能激活一个实例。 我们不需要直接销毁 Widgets(控件) ,因为将其从视口中移除并清除(或者变更)引用它的所有变量将会导致其被 Unreal Engine's(虚幻引擎的) 垃圾收集系统清除。
我们已经构建了代码的框架以创建和显示菜单,并在不需要它们时移除它们。 我们可以返回 Unreal Editor(虚幻编辑器) 并设计菜单资源了!
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();
}
}
}