UE4の勉強記録

UE4の勉強の記録です。個人用です。

第9章2節 SlateWidgetをスクリーンに追加します

<前文>

f:id:kazuhironagai77:20180507110030p:plain

で勉強しています。今回は、「9章2節 SlateWidgetをスクリーンに追加します」を勉強します。

<本文>

<目的>

SlateWidgetをスクリーンに追加します。Slatewidgetとは何でしょうか?HUDのデザインをC++側から行う事でしょうか?良く分かりませんと思っていたら9章2節の序文に詳しく説明されていました。要約しますと、

  1. 前回はFcanvasのAPIを使用して描いたが、Fcanvasは不便。
  2. HUDをslateを使って作成すればいろいろな事が出来る。
  3. Slateの使い方をここで習う。

とありました。HUDのデザインをC++側から行う事で間違いないようです。

<方法>

Step 0.

新しいプロジェクトを作成します。プロジェクト名はChapter9part2_0606としました。SlateとSlate Coreのモジュールが使用出来るようにしないといけないので、以下に示すようにBuild.csファイルからアンコメントします。

f:id:kazuhironagai77:20180610090611p:plain

Step 1.

f:id:kazuhironagai77:20180610090658p:plain

特に作り方の指定はないので、前回と同じようにクラスウィザードから作成します。

f:id:kazuhironagai77:20180610090729p:plain

ファイル名はCustomHUDPlayerControllerとします。これでACustomHUDPlayerControllerクラスが作成されるはずです。更にprivateを選択します。この教科書ではどちらを選択せよとは言っていませんが、このクラスを他のモジュールに公開する必要はないのでprivateを選択します。「C++でつくるUnreal Engineアプリ開発」のP48に一般的なprivateとpublicの選択についての解説がありそれを参考にしています。

f:id:kazuhironagai77:20180610090929p:plain

以下にヘッダーファイルを示します。ACustomHUDPlayerControllerクラスが出来ているのが確認できると思います。

f:id:kazuhironagai77:20180610091002p:plain

Step 2.

f:id:kazuhironagai77:20180610091033p:plain

しました。

f:id:kazuhironagai77:20180610091103p:plain

Step 3.

f:id:kazuhironagai77:20180610091142p:plain

f:id:kazuhironagai77:20180610091157p:plain

しました。

f:id:kazuhironagai77:20180610091231p:plain

がエラー表示がすごいです。

Step 4.

f:id:kazuhironagai77:20180610091320p:plain

f:id:kazuhironagai77:20180610091333p:plain

以下に示すように上記のヘッダーをCustomHUDPlayerControllerのソースファイルにインクルードしました。更にEngine.hも加えました。ビルドした時に余計な エラーが出ないようにインクルードする順番もCumstomHUDPlayerController.hの下にしています。

f:id:kazuhironagai77:20180610091407p:plain

ついでにビルドを試してみました。

f:id:kazuhironagai77:20180610091432p:plain

Step 5.

f:id:kazuhironagai77:20180610091509p:plain

Step1.と同じように、クラスウィザードを使用してGameModeクラスのサブクラスであるSlateHUDGameModeクラスを作成します。

f:id:kazuhironagai77:20180610091535p:plain

前回はここで間違えてGameModeBaseクラスから作成してしまい最初からやり直さなければならなくなりました。今回は注意してGamemodeから作成します。

f:id:kazuhironagai77:20180610091602p:plain

ファイル名をSlateHUDGameModeとします。

f:id:kazuhironagai77:20180610091627p:plain

Publicが既に選択されているのですが、Gamemodeのサブクラスは他のモジュールが使用するのでpublicでないといけないのでしょうか?良く分かりません。ので、とりあえずprivateでやってみます。

f:id:kazuhironagai77:20180610091652p:plain

以下に示すようなヘッダーファイルが出来ました。

f:id:kazuhironagai77:20180610091738p:plain

Classの宣言部分が、PacketPublish社の提供するサンプルコードと僅かに違うのですが、これがPublicとprivateの差なんでしょうか?

f:id:kazuhironagai77:20180610091811p:plain

Step 6.

f:id:kazuhironagai77:20180610091848p:plain

f:id:kazuhironagai77:20180610091903p:plain

以下に示すように追加しました。

f:id:kazuhironagai77:20180610091929p:plain

Step 7.

f:id:kazuhironagai77:20180610092001p:plain

f:id:kazuhironagai77:20180610092019p:plain

以下に示すように追加しました。エラーが表示されています。がstep8.で直すようなのでこのままにしておきます。

f:id:kazuhironagai77:20180610092044p:plain

Step 8.

f:id:kazuhironagai77:20180610092115p:plain

f:id:kazuhironagai77:20180610092131p:plain

しました。エラー表示も消えました。

f:id:kazuhironagai77:20180610092154p:plain

Step 9.

f:id:kazuhironagai77:20180610092237p:plain

しました。

f:id:kazuhironagai77:20180610092312p:plain

エラーもなくビルド出来ました。

<結果>

Step 10.

f:id:kazuhironagai77:20180610092350p:plain

開きました。

f:id:kazuhironagai77:20180610092419p:plain

Step 11.

f:id:kazuhironagai77:20180610092505p:plain

f:id:kazuhironagai77:20180610092630p:plain

しました。

Step 12.

f:id:kazuhironagai77:20180610092711p:plain

しました。

f:id:kazuhironagai77:20180610092749p:plain

<考察>

我々が作成したゲームモードクラスはprivateでしたが何も問題なかったですね。「C++でつくるUnreal Engineアプリ開発」のprivateとpublicの選択についての解説から、「他のモジュールが作成したクラスにアクセスする場合はpublicにしなければならない、それ以外はprivateにする。」と理解したのですが実際のそれぞれのクラスが他のモジュールからアクセスされるかどうかをどう判断すれば良いか分からないです。この本によるとプラグインなどを作成する場合はpublicにしなければならない場合が多いが普通はprivateと書いてあります。ので何か問題が起きるまでは、クラスウィザードを使用してクラスを作成する場合は必ずprivateを選択していきます。

Build.csクラスで使用するモジュールを指定する場合、PublicDependencyModuleNamesとPrivateDependencyModuleNamesがありますが、それぞれの違いについて調べた事がなかったので、今回調べました。

このサイトの解説によると、そのモジュールを使用するクラスがPublicフォルダーとPrivateフォルダーにある場合は、PublicDependencyModuleNamesで使用するモジュールを指定しなければならず、そのモジュールを使用するクラスがPrivateフォルダーのみにある場合はPrivateDependencyModuleNamesでいいそうです。

f:id:kazuhironagai77:20180610093040p:plain

それではHow it works…を見ていきましょう。

f:id:kazuhironagai77:20180610093116p:plain

以下の事が1.では述べられています。

     (a) 我々のモジュールとSlateやSlateCoreモジュールをリンクする必要がある。
     (b) のでSlateモジュールとSlateCoreモジュールを従属関係に追加する必要がある。

この解説はbuild.csファイルにおける以下の部分のコードについての解説です。

f:id:kazuhironagai77:20180610093236p:plain

前回も説明しましたが、このコードを足すことでSlateモジュール、SlateCoreモジュールの両方を我々のモジュールから使用出来るようになります。前回、不明だった我々のモジュールが具体的に何を指すのかについてですが、我々が作成したこのプロジェクトが我々のモジュールに当たります。何故こんな簡単な事に前回気が付かなかったのでしょうか? ちょっと抜けてました。とにかく、一つのモジュール内に一つだけあるbuild.csファイルが、他のモジュールとの従属関係を設定するのです。まとめると、このコードは、我々のモジュールとSlateモジュールやSlateCoreモジュールをリンクし従属関係を設定する事で我々がSlateモジュールやSlateCoreモジュール内のクラスや関数を使用出来るようになるコードなのです。

f:id:kazuhironagai77:20180610093455p:plain

以下の事が2.では述べられています。ちなみに2.の解説文の訳はちぐはぐですがこれ以上どう直せばいいのか分からないのでこのままにしておきます。2.で述べられている意味は以下に示す通りです。

     (a) UIを初期化する必要がある。
     (b) そのためにはカスタム化したPlayerControllerが必要。
     (c) PlayerControllerクラスのBeginPlay関数内でを行う。

この解説は我々が作成したAPlayerControllerクラスのサブクラスであるACustomHUDPlayerControllerクラスについての解説です。以下にACustomHUDPlayerControllerクラス内のBeginPlay関数の実装部を示します。

f:id:kazuhironagai77:20180610093620p:plain

この関数の実装部でUIを初期化する必要があると解説しています。最初のコードであるSuper::BeginPlay()がそれを行っているのか、次のSVerticalBoxクラスがそれを行っているのかが不明ですがとにかくここで行っています。

私の理解しているC++の範囲では、Super::BeginPlay()関数は、親クラスのBeginPlay関数を呼び出すので、この場合カスタム化する前のAPlayerControllerクラスのBeginPlay関数が呼ばれると考えられます。正直、これを何でここで呼ぶ必要があるのかが、C++の知識が限定的な私にはよく分からないです。UIを初期化しているんでしょうか?

f:id:kazuhironagai77:20180610093753p:plain

以下の事が3.では述べられています。

     (a) SNew関数を使用してSVerticalBoxを作成します。
     (b) ウィジットのためのスロットをボックスに加えます。
     (c) スロットの水平と垂直の中心を設定します。

以下にACustomHUDPlayerControllerクラスのBeginPlay関数の実装部で3.で解説している部分を示します。

f:id:kazuhironagai77:20180610093853p:plain

もうそのままなのでこの解説に対する考察は必要ないです。

f:id:kazuhironagai77:20180610094139p:plain

以下の事が4.では述べられています。

     (a) テクストブロックを持つボタンを作成する。
     (b) (a)はスロットの後の角括弧内に作成する。

以下に実際のコードを示します。

f:id:kazuhironagai77:20180610094233p:plain

これも3.と同じSlateモジュールにおける文法そのままのコードですね。

f:id:kazuhironagai77:20180610094257p:plain

String literal値とは”Test button”の事だと思います。

f:id:kazuhironagai77:20180610094344p:plain

BeginPlay関数内の最後のコードであるAddViewportWidgetForPlayer関数についての解説です。6.では

     (a) AddViewportWidgetForPlayer関数を呼び出す。
     (b) ローカルなプレイヤーのスクリーンに、我々が作成したUIを表示するために、(a)をする。

とだけ述べられています。実際のコードを以下に示します。

f:id:kazuhironagai77:20180610094437p:plain

UE4のAPIにおけるAddViewportWidgetForPlayer関数を以下に示します。

f:id:kazuhironagai77:20180610094524p:plain

ウィジットをSlateの特定なZ‐オーダーのViewportのオーバーレイ(例えば、ゲーム内のUIやツール)に追加します。

特定のプレイヤーに対してそれを関連づけます。そしてsub-rect内でそれをキープします。

ウーン…。良く分からないですね。パラメーターに関しては以下に示します。

f:id:kazuhironagai77:20180610094647p:plain

f:id:kazuhironagai77:20180610094710p:plain

Player                    ウィジェットを加えるプレイヤー

ViewportContent:    追加するウィジェット。妥当なものを追加しなければならない。

ZOrder:                      ウィジェットのためのZオーダーのインデックス。大きな値のウィジェットの方が小さい値のウィジェットより上に現れる。

ウーン。一応上記の説明を読むと、AddViewportWidgetForPlayerの使い方は理解しました。

f:id:kazuhironagai77:20180610094828p:plain

これ以降は、カスタム化したゲームモードの解説のようです。以下の事が7.では述べられています。

     (a) 我々のカスタム化したゲームモードを作成します。
     (b) そこで、我々のカスタム化したPlayerControllerを使用すると設定します。

新しいゲームモードクラスで追加したコードは以下に示したPlayerControllerClassだけです。

f:id:kazuhironagai77:20180610094923p:plain

UE4C++APIによると、PlayerControllerClassは、

f:id:kazuhironagai77:20180610095003p:plain

ログインしたプレイヤーのためにPlayerControllerクラスを生み出す

と解説されています。その生み出されたPlayerControllerクラスを我々がカスタム化したPlayerControllerに指定しているのでしょう。

f:id:kazuhironagai77:20180610095051p:plain

確認しました。

f:id:kazuhironagai77:20180610095123p:plain

次回、UIのサイズの変更方法を勉強するそうです。

<まとめ>

Slateモジュールを使用してUIを作成するには、カスタム化したPlayerControllerクラスを使用します。それによってそれぞれのプレイヤーに対してのUIが表示できるからです。更に、UIの指定は、PlayerControllerクラス内のbeginPlay関数内で行います。UIの形状の指定方法は、我々が今まで勉強して来たSlateの方法と同じです。最後にカスタム化したPlayerControllerを使用せよと指定するのに新しいゲームモードクラスを作成します。

<おまけ>

今回は特にないです。Super::BeginPlay()についての勉強は時間があるときにします。