はじめに
この記事は UE4 でブロック崩しを作るシリーズ の続きになります。
今回はゲームにスコアを表示する UI を追加します。
UI の表示には UMG (Unreal Motion Graphics) を使用しますが、表示処理には BP のイベントグラフは使わず C++ で実装してゆきます。
完成ゲーム
環境
Windows 10
Unreal Engine 4.27.1
エディタ言語 英語
目次
スコア表示用の WBP を作成
WBP を操作する UUserWidget(C++) の作成
WBP と UUserWidget(C++) を繋げる
WBP を配置
実行
次回
おまけ
スコア表示用の WBP を作成
スコアを表示する WBP(Widget Blueprint) を作成します
Content Browser で右クリック
開いたメニューから User Interface → 「Widget Blueprint」を選択
作成された NewWidgetBlueprint を「WBP_Score」にリネームします
WBP 編集
「WBP_Score」をダブルクリックして BP 編集画面を開きます。
下記の UMG UI デザイナ が開きます
左にある Palette から「Text」を選択してメインのビューにドラッグ&ドロップ
この UI にテキスト表示が追加されます
- 一番上の TextBlock_0 はデフォルトでつけられたこのテキストアイテムの名前です
- 位置を左上に変更します。画面上でドラッグして移動も出来ます
- 表示する内容を「SCORE 0」に変更します
- フォントサイズを 50 くらいにしておきます
WBP を操作する UUserWidget(C++) の作成
上部メニューから File → New C++ Class.. を選択
開いたウィンドウから
① 右上の Show All Classes にチェックを入れ
② UUserWidget を検索して選択
③ Next をクリック
名前を「UW_Score」として Create Class をクリック
Visual Studio が起動して プロジェクトに UW_Score.h /.cpp が追加されています
UUserWidget(C++) 編集
作成された UW_Score.h / .cpp を編集します
#pragma once
#include "CoreMinimal.h"
#include "Blueprint/UserWidget.h"
#include "Components/TextBlock.h" // 追加
#include "UW_Score.generated.h"
UCLASS()
class BREAK_BLOCK_API UUW_Score : public UUserWidget
{
GENERATED_BODY()
protected:
UTextBlock* m_pTextBlock;
public:
UUW_Score(const FObjectInitializer& ObjectInitializer);
protected:
virtual void NativeOnInitialized() override;
public:
void UpdateScore(int score);
};
-
UTextBlock m_pTextBlock* を追加
- 使う度に取得する必要のないように WBP に追加したテキスト表示のポインタを記録する変数
- コンストラクタ 追加
-
void NativeOnInitialized() を override;
- 初期化時に呼ばれるので、初期化用に使用
-
void UpdateScore(int score) を追加
- 外部からスコアをセットしてもらいその数値に表示を更新する関数
#include "UW_Score.h"
// コンストラクタ
UUW_Score::UUW_Score(const FObjectInitializer& ObjectInitializer)
: UUserWidget(ObjectInitializer)
, m_pTextBlock(nullptr)
{
}
// 初期化、Text へのポインタを記録
void UUW_Score::NativeOnInitialized()
{
Super::NativeOnInitialized();
UTextBlock* pTextBlock = Cast<UTextBlock>(GetWidgetFromName("TextBlock_0"));
ensure(pTextBlock != nullptr);
m_pTextBlock = pTextBlock;
}
// スコアUI の Text を更新
void UUW_Score::UpdateScore(int score)
{
FString str = TEXT("Score") + FString::FromInt(score);
ensure(m_pTextBlock != nullptr);
if(m_pTextBlock)
{
m_pTextBlock->SetText(FText::FromString(str));
}
}
-
void NativeOnInitialized()
- テキストの名前を TextBlock_0 にしていたので、その名前でテキストを取得
- 毎回取得する必要のないように m_pTextBlock に保存
-
void UpdateScore(int score)
- m_pTextBlock のテキスト表示を更新するには FText の文字列をセットする必要がある
- FText は文字列の加工処理が苦手なので、一旦 FString で文字列を加工して最後に変換してセットしている
WBP と UUserWidget(C++) を繋げる
- WBP_Score の編集画面を開きます
- 右上の「Graph」を選択します
- 上部の「Class Settings」を選択します
- Details から Parent Class を**「UW_Score」**に変更します
WBP を配置
WBP を配置するには誰かが CreateWidget で実体を作り AddToViewport で画面に表示させる必要があります。今回はそれを行う専用の「Actor」を作成し、WBP が配置されるようにします。
WBP を配置する Actor を作成
- 上部メニューから File → New C++ Class.. を選択
- Actor を選択して Next をクリック
- Name を「AUWScoreController」として Create Class をクリック
- Visual Studio を reload して「AUWScoreController.h / .cpp」が追加されているのを確認
WBP を配置する Actor の編集
AUWScoreController.h / .cpp を編集します
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "UW_Score.h" // 追加
#include "AUWScoreController.generated.h"
UCLASS()
class BREAK_BLOCK_API AAUWScoreController : public AActor
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
AAUWScoreController();
protected:
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UMG_Game")
TSubclassOf<UUserWidget> WBP_Score;
UUW_Score* m_pUWScore;
// Called when the game starts or when spawned
virtual void BeginPlay() override;
:
-
TSubclassOf WBP_Score を追加
- 作成する UUserWidget を 編集画面から受け取る用
-
UUW_Score m_pUWScore* を追加
- 配置した UMG のポインタを保存する
:
// Called when the game starts or when spawned
void AAUWScoreController::BeginPlay()
{
Super::BeginPlay();
m_pUWScore = CreateWidget<UUW_Score>(GetWorld(), WBP_Score);
ensure(m_pUWScore);
if (m_pUWScore)
{
m_pUWScore->AddToViewport();
}
}
- WBP_Score には作成すべき UUserWidget が指定されている前提で CreateWidget() で Widget を作成
- 作成した widget を AddToViewport で表示
これで WBP を配置する Actor が作成できました
この Actor を配置すれば BeginPlay() が呼ばれ WBP が表示されます
WBP を配置する Actor を配置
Contents Browser を C++ Classes → BreakBlock の表示に切り替え
中にいる AUWScoreController をビューポートにドラッグ&ドロップで配置します
World Outliner に AUWScoreController が追加されています
それを選択して Details から WBP_Score をセットします
※ この Actor の .h に下記を追加していたので、このように Details から値をセットする事が可能です
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UMG_Game")
TSubclassOf<UUserWidget> WBP_Score;
実行
プレイをするとゲーム画面左上にスコアが表示されるようになりました。
値の変化
この表示を変化させる UpdateScore(int score) を UUW_Scoreクラスに作成しましたが
まだ誰もこの関数を呼んでいませんでした。
下記のように AAUWScoreControllerクラス から関数を呼ぶようにします。
void AAUWScoreController::BeginPlay()
{
:
if (m_pUWScore)
{
m_pUWScore->AddToViewport();
m_pUWScore->UpdateScore(30); // 追加
}
}
次回
スコアUIが表示されるようになりました。
ただ、ブロックを破壊してスコアが加算される、という処理ができておりません。
次回はその処理を作成してスコアUIを完成させます。
おまけ
UMG を C++ から 配置、操作する方法を書きましたが、下記の方法も使うことが出来るようです。
BindWidget
UUW_Scoreクラスで、テキスト表示のポインタを取得するのに下記の様なコードを書きましたが
void UUW_Score::NativeOnInitialized()
{
:
m_pTextBlock = Cast<UTextBlock>(GetWidgetFromName("TextBlock_0"));
}
.h で下記のようにしておくと、この GetWidgetFromName のくだりは不要に出来るようです。
UPROPERTY(EditAnywhere, meta = (BindWidget))
class UTextBlock* TextBlock_0 = nullptr;
- .h で m_pTextBlock の代わりに下記の変数を作成
- 変数名は WBP でテキストにつけた名前 TextBlock_0 を使う必要がある
- .cpp で初期化せずとも TextBlock_0 を使う事ができる
参考リンク
この方法については下記から知る事ができました。
LoadSynchronous
WBP を配置する Actor に WBP を渡すのに Details からセットしましたが
下記のように .cpp からもセットできるようです
void AAUWScoreController::BeginPlay()
{
Super::BeginPlay();
//>>> 追加
FString path = "/Game/WBP_Score.WBP_Score_C";
TSubclassOf<class UUserWidget> WidgetClass;
WidgetClass = TSoftClassPtr<UUserWidget>(FSoftObjectPath(path)).LoadSynchronous();
//<<< 追加
m_pUWScore = CreateWidget<UUW_Score>(GetWorld(), WidgetClass);
ensure(m_pUWScore);
if (m_pUWScore)
{
m_pUWScore->AddToViewport();
}
}
- Content に置いた WBP_Score を読み込む
- /Content の代わりに /Game を使う
- WBP_Score という名前にしたので WBP_Score.WBP_Score_C を使う
参考リンク
この方法については下記の記事から知る事ができました。