<前文>
で勉強しています。今回は、「9章2節 SlateWidgetをスクリーンに追加します」を勉強します。
<本文>
<目的>
SlateWidgetをスクリーンに追加します。Slatewidgetとは何でしょうか?HUDのデザインをC++側から行う事でしょうか?良く分かりませんと思っていたら9章2節の序文に詳しく説明されていました。要約しますと、
- 前回はFcanvasのAPIを使用して描いたが、Fcanvasは不便。
- HUDをslateを使って作成すればいろいろな事が出来る。
- Slateの使い方をここで習う。
とありました。HUDのデザインをC++側から行う事で間違いないようです。
<方法>
Step 0.
新しいプロジェクトを作成します。プロジェクト名はChapter9part2_0606としました。SlateとSlate Coreのモジュールが使用出来るようにしないといけないので、以下に示すようにBuild.csファイルからアンコメントします。
Step 1.
特に作り方の指定はないので、前回と同じようにクラスウィザードから作成します。
ファイル名はCustomHUDPlayerControllerとします。これでACustomHUDPlayerControllerクラスが作成されるはずです。更にprivateを選択します。この教科書ではどちらを選択せよとは言っていませんが、このクラスを他のモジュールに公開する必要はないのでprivateを選択します。「C++でつくるUnreal Engineアプリ開発」のP48に一般的なprivateとpublicの選択についての解説がありそれを参考にしています。
以下にヘッダーファイルを示します。ACustomHUDPlayerControllerクラスが出来ているのが確認できると思います。
Step 2.
しました。
Step 3.
しました。
がエラー表示がすごいです。
Step 4.
以下に示すように上記のヘッダーをCustomHUDPlayerControllerのソースファイルにインクルードしました。更にEngine.hも加えました。ビルドした時に余計な エラーが出ないようにインクルードする順番もCumstomHUDPlayerController.hの下にしています。
ついでにビルドを試してみました。
Step 5.
Step1.と同じように、クラスウィザードを使用してGameModeクラスのサブクラスであるSlateHUDGameModeクラスを作成します。
前回はここで間違えてGameModeBaseクラスから作成してしまい最初からやり直さなければならなくなりました。今回は注意してGamemodeから作成します。
ファイル名をSlateHUDGameModeとします。
Publicが既に選択されているのですが、Gamemodeのサブクラスは他のモジュールが使用するのでpublicでないといけないのでしょうか?良く分かりません。ので、とりあえずprivateでやってみます。
以下に示すようなヘッダーファイルが出来ました。
Classの宣言部分が、PacketPublish社の提供するサンプルコードと僅かに違うのですが、これがPublicとprivateの差なんでしょうか?
Step 6.
以下に示すように追加しました。
Step 7.
以下に示すように追加しました。エラーが表示されています。がstep8.で直すようなのでこのままにしておきます。
Step 8.
しました。エラー表示も消えました。
Step 9.
しました。
エラーもなくビルド出来ました。
<結果>
Step 10.
開きました。
Step 11.
しました。
Step 12.
しました。
<考察>
我々が作成したゲームモードクラスはprivateでしたが何も問題なかったですね。「C++でつくるUnreal Engineアプリ開発」のprivateとpublicの選択についての解説から、「他のモジュールが作成したクラスにアクセスする場合はpublicにしなければならない、それ以外はprivateにする。」と理解したのですが実際のそれぞれのクラスが他のモジュールからアクセスされるかどうかをどう判断すれば良いか分からないです。この本によるとプラグインなどを作成する場合はpublicにしなければならない場合が多いが普通はprivateと書いてあります。ので何か問題が起きるまでは、クラスウィザードを使用してクラスを作成する場合は必ずprivateを選択していきます。
Build.csクラスで使用するモジュールを指定する場合、PublicDependencyModuleNamesとPrivateDependencyModuleNamesがありますが、それぞれの違いについて調べた事がなかったので、今回調べました。
このサイトの解説によると、そのモジュールを使用するクラスがPublicフォルダーとPrivateフォルダーにある場合は、PublicDependencyModuleNamesで使用するモジュールを指定しなければならず、そのモジュールを使用するクラスがPrivateフォルダーのみにある場合はPrivateDependencyModuleNamesでいいそうです。
それではHow it works…を見ていきましょう。
以下の事が1.では述べられています。
(a) 我々のモジュールとSlateやSlateCoreモジュールをリンクする必要がある。
(b) のでSlateモジュールとSlateCoreモジュールを従属関係に追加する必要がある。
この解説はbuild.csファイルにおける以下の部分のコードについての解説です。
前回も説明しましたが、このコードを足すことでSlateモジュール、SlateCoreモジュールの両方を我々のモジュールから使用出来るようになります。前回、不明だった我々のモジュールが具体的に何を指すのかについてですが、我々が作成したこのプロジェクトが我々のモジュールに当たります。何故こんな簡単な事に前回気が付かなかったのでしょうか? ちょっと抜けてました。とにかく、一つのモジュール内に一つだけあるbuild.csファイルが、他のモジュールとの従属関係を設定するのです。まとめると、このコードは、我々のモジュールとSlateモジュールやSlateCoreモジュールをリンクし従属関係を設定する事で我々がSlateモジュールやSlateCoreモジュール内のクラスや関数を使用出来るようになるコードなのです。
以下の事が2.では述べられています。ちなみに2.の解説文の訳はちぐはぐですがこれ以上どう直せばいいのか分からないのでこのままにしておきます。2.で述べられている意味は以下に示す通りです。
(a) UIを初期化する必要がある。
(b) そのためにはカスタム化したPlayerControllerが必要。
(c) PlayerControllerクラスのBeginPlay関数内でを行う。
この解説は我々が作成したAPlayerControllerクラスのサブクラスであるACustomHUDPlayerControllerクラスについての解説です。以下にACustomHUDPlayerControllerクラス内のBeginPlay関数の実装部を示します。
この関数の実装部でUIを初期化する必要があると解説しています。最初のコードであるSuper::BeginPlay()がそれを行っているのか、次のSVerticalBoxクラスがそれを行っているのかが不明ですがとにかくここで行っています。
私の理解しているC++の範囲では、Super::BeginPlay()関数は、親クラスのBeginPlay関数を呼び出すので、この場合カスタム化する前のAPlayerControllerクラスのBeginPlay関数が呼ばれると考えられます。正直、これを何でここで呼ぶ必要があるのかが、C++の知識が限定的な私にはよく分からないです。UIを初期化しているんでしょうか?
以下の事が3.では述べられています。
(a) SNew関数を使用してSVerticalBoxを作成します。
(b) ウィジットのためのスロットをボックスに加えます。
(c) スロットの水平と垂直の中心を設定します。
以下にACustomHUDPlayerControllerクラスのBeginPlay関数の実装部で3.で解説している部分を示します。
もうそのままなのでこの解説に対する考察は必要ないです。
以下の事が4.では述べられています。
(a) テクストブロックを持つボタンを作成する。
(b) (a)はスロットの後の角括弧内に作成する。
以下に実際のコードを示します。
これも3.と同じSlateモジュールにおける文法そのままのコードですね。
String literal値とは”Test button”の事だと思います。
BeginPlay関数内の最後のコードであるAddViewportWidgetForPlayer関数についての解説です。6.では
(a) AddViewportWidgetForPlayer関数を呼び出す。
(b) ローカルなプレイヤーのスクリーンに、我々が作成したUIを表示するために、(a)をする。
とだけ述べられています。実際のコードを以下に示します。
UE4のAPIにおけるAddViewportWidgetForPlayer関数を以下に示します。
ウィジットをSlateの特定なZ‐オーダーのViewportのオーバーレイ(例えば、ゲーム内のUIやツール)に追加します。
特定のプレイヤーに対してそれを関連づけます。そしてsub-rect内でそれをキープします。
ウーン…。良く分からないですね。パラメーターに関しては以下に示します。
Player: ウィジェットを加えるプレイヤー
ViewportContent: 追加するウィジェット。妥当なものを追加しなければならない。
ZOrder: ウィジェットのためのZオーダーのインデックス。大きな値のウィジェットの方が小さい値のウィジェットより上に現れる。
ウーン。一応上記の説明を読むと、AddViewportWidgetForPlayerの使い方は理解しました。
これ以降は、カスタム化したゲームモードの解説のようです。以下の事が7.では述べられています。
(a) 我々のカスタム化したゲームモードを作成します。
(b) そこで、我々のカスタム化したPlayerControllerを使用すると設定します。
新しいゲームモードクラスで追加したコードは以下に示したPlayerControllerClassだけです。
UE4のC++のAPIによると、PlayerControllerClassは、
ログインしたプレイヤーのためにPlayerControllerクラスを生み出す
と解説されています。その生み出されたPlayerControllerクラスを我々がカスタム化したPlayerControllerに指定しているのでしょう。
確認しました。
次回、UIのサイズの変更方法を勉強するそうです。
<まとめ>
Slateモジュールを使用してUIを作成するには、カスタム化したPlayerControllerクラスを使用します。それによってそれぞれのプレイヤーに対してのUIが表示できるからです。更に、UIの指定は、PlayerControllerクラス内のbeginPlay関数内で行います。UIの形状の指定方法は、我々が今まで勉強して来たSlateの方法と同じです。最後にカスタム化したPlayerControllerを使用せよと指定するのに新しいゲームモードクラスを作成します。
<おまけ>
今回は特にないです。Super::BeginPlay()についての勉強は時間があるときにします。