UMG を使ったユーザー インターフェース

UMG を使ったシンプルなメニュー システム

Windows
MacOS
Linux

このチュートリアルでは、UMG を使って複数のスクリーンやボタンを表示する基本的なメニュー システムを構築する方法を学びます。

1. UMG のモジュールの従属関係を設定する

Unreal Engine 4 にまだ慣れていない場合は、最初に プログラミング クイック スタート ガイド tutorial を確認してください。このチュートリアルの対象者は、プロジェクトの作成、プロジェクトに C++ コードを追加、またコードをコンパイルできる方を想定しています。ブループリント に関数やプロパティもエクスポーズします。さらに学習する場合は、変数、タイマー、イベント tutorial から始めると良いでしょう。

  1. プロジェクトの新規作成から始めます。

    • 新しいプロジェクト カテゴリ Games をクリックして [Next (次へ)] をクリックします。

    • 「Blank (ブランク)」テンプレートを選択して [Next] をクリックします。

    • C++Desktop/ConsoleWith Starter Content のそれぞれの設定が有効であることを確認します。

    • このページでは「HowTo_UMG」という名前を使用します。

    Unreal Motion Graphics (UMG) を使用するので、デフォルトでサポートしていないいくつかの モジュール に対応している Visual Studio へ移動します。

  2. メイン エディタ画面の [File] ドロップダウン メニューから Open Visual Studio コマンドでプロジェクトのコードを使用することができます。

    OpenVisualStudio.png

  3. UMG はいくつかのモジュールと依存関係があるため、これらのモジュールを "HowTo_UMG.Build.cs" に追加しなくてはいけません。

    BuildCS.png

    "HowTo_UMG.Build.CS" で、同梱されているパブリックモ ジュールのリストに "UMG" を追加して、同梱されているプライベート モジュールのリストに "Slate" と "SlateCore" を追加します。HowTo_UMG のコンストラクタの 1 行目を以下のように変更します。

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

    次に、以下のコメント行を外します。

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

    ソース コード全体は以下になります。使用するコードをダブルチェックしてください。


UMG を設定したら、ゲームのメニューを作成および表示するために、プロジェクトのカスタム Game Mode にコードを追加することができます。

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

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

2. ゲーム モードの拡張

  1. これから作成するメニューは User Widgets (ユーザー ウィジェット) から作成します。新規の User Widget を作成したら表示する関数を記述して、ゲームが開始したらこの関数を呼び出します。作成したものを追跡して、後で取り除くことができるようにします。それぞれのプロジェクトはカスタム Game Mode クラスと一緒に提供されるため、 "HowTo_UMGGameMode.h" に定義されているこのクラスを開きます。以下の関数とプロパティをこのクラスの下部に追加する必要があります。

    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;
  2. コードで User Widgets を使用するために、"#include" セクションの上に次の行を追加します。

    #include "Blueprint/UserWidget.h"
  3. ここで "HowTo_UMGGameMode.cpp" へ移動して、宣言した 2 つの関数のボディにコードを記述します。BeginPlay() のオーバーライドから始めます。

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

    この時に BeginPlay をオーバーライドするように、親クラスから関数をオーバーライドする時は (「Super」が参照)、この関数の親クラスを呼ぶことが重要になります。ここでの関数バージョンは、既存プロシージャーの終わりに手順を 1 つだけ追加するだけなので、関数の 1 行目で 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();
            }
        }
    }

    このコードは、提供するすべての ウィジェット のインスタンスを生成して、それらをスクリーンに配置します。Unreal Engine は一度に多数のウィジェットの表示とインタラクションを処理しますが、コードはウィジェットの除去も行うため、一度に 1 つのウィジェットのみがアクティブになります。Unreal Engine のガーベジ コレクション システムはウィジェットをビューポートから除去したり、ウィジェットが参照するすべての変数をクリア (または変更) するため、ウィジェットを直接破棄する必要はありません。

  5. 最後に、Player Controller クラスの入力モードを設定する必要があります。これを行うには、Player Controller に基づきプロジェクトに新規 C++ クラスを追加します。このクラス内でゲーム開始時にもうひとつ関数を呼び出して、UI エレメントとインタラクションできるようにする必要があります。

    NewClass.png PlayerController.png

    HowTo_UMGPlayerController.h で、以下のオーバーライドをクラスに追加します。

    public:

        virtual void BeginPlay() override;

    HowTo_UMGPlayerController.cpp で、オーバーライドした関数を追加します。

    void AHowTo_UMGPlayerController::BeginPlay()

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

メニューを作成し表示し、不要になったら取り除くためのコードのフレームワークを構築しました。Unreal Editor へ戻る準備が整ったので、メニュー アセットをデザインします。

完成コード

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

        // 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-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:
    /** 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-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. Menu Widget ブループリントの作成

  1. Unreal Editor[Compile (コンパイル)] ボタンを押して新規コードをビルドします。ビルドすると、ユーザー ウィジェット をメニューとして使用できるようになります。

    CompileFromEditor.png

  2. Game Mode でメニューとして使用する ユーザー ウィジェット を作成します。コンテンツ ブラウザ[Add New (新規追加)] ボタンを使用します。Widget Blueprint クラスは User Interface カテゴリにあります。ウィジェットを 2 つ作成し、それぞれに「MainMenu」と「NewGameMenu」と名前を付けます。メイン メニューでゲームが開始して、New Game Menu へ進むオプションが表示されます。

    CreateWidgetBP.png

  3. 作成したばかりの MainMenu の ウィジェット をダブルクリックすると、メニュー レイアウトを作成することができる ブループリント デザイナ へ移動します。

  4. [Palette] パネル[Common (コメント)] セクションから [Button][Text]グラフ へドラッグします。このボタンは最終的に New Game Menu を開くために使用します。

    AddButtonAndTextBlock.png

  5. レイアウトを正しく表示するために、最初にボタンの位置とサイズを調整します。以下の変更を加えます。

    • [Size (サイズ)] を -200 by -100 に設定します。

    • [Position (位置)] を (-200, -200) に設定します。

    • 後で機能を接続する時に分かりやすいように名前を「NewGameButton」に変更します。

    ButtonDetails.png

  6. ボタン用に画像のカスタムセットを描画しないため、テキスト ブロックをドロップして名前をつけて、以下の変更を行うこともできます。

    • 「New Game」と入力します。

    • 「Visibility」を「Hit Test Invisible」に変更します。テキストブロックが下のボタンに対するマウスクリックを邪魔しないようにします。

    • 名前を「NewGameText」に設定します。必須ではありませんが、習慣にするとよいです。

    TextBlockDetails.png

  7. 次に 2 番目のボタンとテキストブロックで "Quit" 機能を作成します。New Game のボタンとテキストブロックと同じ方法で設定します。以下の点が異なります。

    • ボタンの名前を「QuitButton」に設定します。

    • [Position (位置)] を (-200, -400) に設定します。

    • テキストブロックの名前を「QuitText」に設定します。

  8. その後、ボタンをクリックするとコードを実行するようにボタンに イベント を追加することができます。[Details (詳細)] パネルで、適切なイベント名の横にある "+" を検索し、クリックして追加します。この例では、OnClicked が唯一使用できるイベントです。このイベントを [NewGameButton] ウィジェットと [QuitButton] ウィジェットの両方に作成します。

    CreateOnClickedEvent.png

    デザイナーはここで ブループリント スクリプティングを利用して機能を構築することができます。もしくは、 C++ プログラマーは公開された関数を呼び出すノードを接続することも出来ます。

  9. OnClicked(NewGameButton) という名前のイベントに以下の設定を行います。

    • 以前 Game Mode に追加した関数を使用するために ChangeMenuWidget ノードを接続します。

    • ChangeMenuWidget ノードの [New Widget Class] 入力フィールドに "NewGameMenu" アセットを設定します。

    OnClicked_NewGame.png

  10. OnClicked(QuitButton) Event に以下を設定します。

    • Quit Game ノードに接続します。

    OnClicked_Quit.png

メインメニューを作成したら、レベルが開始すると同時にロードを行う Game Mode アセットを設定することができます。

4. ゲーム モードの設定

  1. プロジェクトの Game Mode に基づいて、コンテンツ ブラウザBlueprint クラス を追加します。このクラスを追加することにより、この 2 つのクラスに公開された変数に値を自由に設定することができるようになります。以下の方法で行います。

    • コンテンツ ブラウザ[Add (追加)] ボタンをクリックします。

    AddNewBPClass.png

    • 親クラスに HowTo_UMGGameMode を選びます。クラスが [All Classes (すべてのクラス)] セクションにリスト表示されます。

    PickParentClassForGameModeBP.png

    • 生成された Blueprint アセットに「MenuGameMode」と名前を付けます。

  2. ゲーム内にマウスカーソルを表示するには、Game Mode で作成したように、Player Controller のブループリントを作成しなくてはいけません。

    • コンテンツ ブラウザ で再度 [Add (追加)] ボタンをクリックします。

    • [Common Classes] セクションから [Player Controller] を選びます。

    • ブループリントに「MenuPlayerController」と名前を付けます。

  3. MenuPlayerController を編集します。

    • [Show Mouse Cursor (マウスカーソルを表示)] ボックスをチェックします。

    GamePlayerController.png

  4. MenuGameMode を編集します。

    • ゲームを開始したらメニューが開くように、Starting Widget クラス を MainMenu アセットに設定しなくてはいけません。

    • メニュー内をプレイヤーが飛び回らないように、Default Pawn クラスDefaultPawn ではなく Pawn に設定しなくてはいけません。

    • ゲーム内にマウスカーソルを表示するために、Player Controller クラス を既に作成した MenuPlayerController アセットに設定しなくてはいけません。

    ConfigureGameMode.png

  5. ブループリント を使用するには、[Level Editor] ウィンドウへ戻って、Setting (設定) ボタンで現在の レベルWorld Settings (ワールド設定) に変更しなくてはいけません。

    WorldSettingsBar.png

    デフォルトの ゲームモード は、[Maps and Modes] セクションの [Project Settings (プロジェクトの設定)] メニューからも設定出来ます。この設定方法を使用した場合、個別にオーバーライドしない限り、すべてのレベルは選択したゲームモードがデフォルト設定となります。どの方法を使用するかは、プロジェクトをどのように設定するかによって決まります。

  6. [World Settings (ワールド設定) パネルが開きます。デフォルトでは [Details (詳細)] パネルにドッキングしますが、別の場所へ移動することも出来ます。[Game Mode Override] フィールドを MenuGameMode アセットに設定します。

    WorldSettings.png

カスタムの Game Mode アセットがレベルで有効になって、メインメニューをロードするようになります。マウスカーソルを表示するプレイヤー コントローラーを使用します。ここでゲームを実行すると、[Quit] ボタンが設定通り機能して、[New Game] ボタンは空のメニュー スクリーンへ移動します。次に、New Game メニューを設定します。

5.セカンド メニューを構築する

  1. コンテンツ ブラウザ で以前に作成済みの "NewGameMenu" アセットを検索して開きます。このメニューには、名前を入力する テキストボックス、名前を入力するまでクリックできないゲームプレイ用の ボタン、メインメニューに戻るボタンがあります。

  2. 名前の入力欄を作成するには、Text Box (Text Block ではありません) をレイアウトへドラッグします。

    CreateTextEntryBox.png

    1. Text Box は以下の値で設定します。

    • [NameTextEntry] の名前を変更します。

    • Position は (325, 200) に設定。この値に設定することで、Text Block を Text Box の左に配置するための余白ができます。

    • [Size] は 250x40 に設定。

    • ([Style] ヘッダの下) の [Font size] は 20 に設定。

    TextBoxDetails.png

  3. 前回のメニューに作成したボタンと同じ方法で Text Block ラベルを使用してプレイゲーム ボタンを作成することができます。

    • Button の設定値PlayGameButton 名を変更し、[Position (位置)] を「200」と「300」、[Size] を「200」、「100」に設定します。

    • Text Block の設定値PlayGameText の名前を変更し、Visibility を [Hit Test Invisible] に設定し、PlayGameButton の一番上にドラッグします。

  4. プレイゲーム ボタンには特別な機能があります。これは、Text Box に入力した名前が空白でない場合のみ有効になります。Unreal Motion Graphics (UMG) のバインド機能を使って [Is Enabled] フィールド ([Behavior (ビヘイビア)] セクション配下) に新機能を作成することができます。

    PlayGameButtonDetails.png

    ゲームで有効なプレイヤー名であることを判断するために複雑なルールがある場合、またはプレイヤー名を C++ 変数に保存する必要がある場合は、Game ModeUFUNCTION として公開するか、プロジェクト内のどこかで静的関数として公開します。ただし、名前文字列が空白ではないことだけが重要であるため、ここで ウィジェット にスクリプトを記述することができます。

  5. Text Box が空白でない場合に限りボタンを有効にするために、Text Box のテキストを文字列に変換し、その後文字列の長さがゼロ以上であることを確認します。ロジックはこのように表示されます。

    PlayGameButtonEnableFunction.png

  6. ボタンをもう一つ追加して、メニューをキャンセルしたり、メニューへ戻れるようにしましょう。メイン メニューの [Play Game] ボタンと同じですが、左上ではなく右下の隅に対して相対的な位置に置かれます。これを実現するためには、ボタン用の [Details (詳細)] パネル[Anchors (アンカー)] ドロップダウン メニューをクリックして、ポップアップ メニューから適切なグラフィック表示を検索します。

    • [MainMenuButton] の名前を変更します。

    • [Position (位置)] を ( -400, -200) に設定します。

    • [Size (サイズ)] を 200x100 に設定します。

    SelectAnchor.png

    右下隅にアンカーを配置するとサイズと位置の値を変えても変わりません。そのため、スクリーン上に存在するためには位置を負の値にする必要があります。サイズの値は正のままです。

  7. OnClicked イベントを再度追加して、新規ボタンにスクリプトを追加していきます。Main Menu Button は単に Main Menu Widget を再ロードするだけですが、Play Game Button は ChangeMenuWidget 関数の呼び出しに新規ウィジェットを使用せずにメニュー全体を非アクティブにします。実際のクラスやアセット名の代わりに、Select Class と表示して表されます。

    NewGameButtonBPs.png

    Play Game Button でメニューを非アクティブにしたら、ゲーム内でそれ以上何かをすることはできません。この時点で、一般的に最初のレベルをロードし、紹介カットシーンを再生、または ポーン をスポーンしたり、所有したりします。

  8. 概ね、以下の 2 つの画面のようになります。

    FinalScreen.png

    FinalScreen2.png

6. 応用編

ここまでで学んだ知識を活かして、以下を行ってみましょう。

  • 同時に複数のメニューを開く。

  • 単に表示させるのではなく、ウィジェット を画面上にスライド、または画面上からフェードさせる。

  • ウィジェットでサポートするさまざまなサウンド、スタイル、カラーのプロパティを見る。

  • メニューから難易度やキャラクター クラスなど、Game Mode に変数を設定する。

  • プレイヤーがキーを押すとポップアップし、ゲームを一時停止させ、メニューを閉じたらゲームプレイを再開するインゲームメニューを作成する。

  • これまでに構成した機能や、前回のチュートリアルで学んだ機能を Unreal Motion Graphics で作ったメニューに接続する。

以下はこのチュートリアルの内容の詳しい情報のリンク先です。

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