<前文>
で勉強しています。今回は、「9章1節 キャンバスを利用して描く」を勉強します。9章における最初の節です。
前の日曜日に、私のパソコンにある2つのHDDの内の一つが突然死んでしまいました。ブログの原稿は既に書き終わっていたのですがそのブログを保存したHDDが死んでしまったのでもちろん更新はできませんでした。
色々調べてみると、HDD内にデータは残っているのですがHDD内にどんなデータがどこにあるかを示したテーブルが壊れてしまったらしいのでした。
途方に暮れていたのですが、シャットダウンした時に、実際のPCの電源が10分ぐらい落ちないので、もう壊れてもいいやと覚悟を決めてPC本体の電源ボタンを長押ししてPCの電源を切って、もう一度起動したら、死んだHDD内のデータを開く事は出来ないのですが、エクスプローラからデータにアクセスは出来るようになりました。そこで、外付けHDDを繋げて死んでいるHDD内のデータを全て外付けHDDにコピーしました。
一日と一晩かかりましたが、そのコピーしたデータの方を開いて見たら、ブログの原稿も見る事が出来ました。それでこのブログも無事に復活しました。
<本文>
<目的>
キャンバスを利用して何かを描きます。キャンバスとはUE3で作られた簡単なHUDの実装だそうです。今はほとんど使われていないそうです。今回習うキャンバスに利用方法は歴史的な価値はありますが実用性はなさそうです。
<方法>
Step 0.
途中までやったのですがGameModeクラスを作成するところでGameModeBaseクラスを作ってしまいそれが原因でエラーを吐いていたので新しいプロジェクトを作成してやり直しました。バージョンは4.19.2を選択しました。プロジェクト名は、Chapter9_0528としました。
Step 1.
Sourceファイル内のChapter9_0528にBuild.csファイルはありました。
Build.csを開いて見ると
コメントになっていたので、アンコメントしました。
Step 2.
エディターからクラスウィザードを開きます。
GameModeを選びます。昨日途中までやった時ここでGameModeBaseを選んでしまい間違えました。
名前はCustomHUDGameModeとしました。Pathはそのままです。C++でつくるUnreal Engineアプリ開発を読んでいたら通常のクラスはPrivateにするとあったので、privateを選択しました。
Step 3.
加えました。
Step 4.
加えました。
今度は、AGameModeの処にエラー表示はありません。ACustomHUDのエラー表示は、次に作成するクラスを加えると消えるはずなのでこのままでいきます。
Step 5.
加えました。
エラーが出ました。
エラーを消すためにCustomHUDGameMode .cppファイルにCustomHUD.hをインクルードしました。
もう一度ビルドしてみます。
今度は成功しました。
Step 6.
以下に示したように加えました。
Step 7.
加えましたが
思い切りエラーを吐いています。Canvas のUE4のAPIによるとCanvasのヘッダーはEngine.hなのでEngine.hをインクルードしてみます。
綺麗にエラー表示が消えました。
<結果>
Step 8.
ビルドしました。
エディターも順調に起動しました。
Step 9.
しました。
Step 10.
選択しました。
Step 11.
現れました。
<考察>
今回も、How it works…を読んでいきます。
では、1.の解説の考察から行っていきます。1.の解説では以下の事が述べられています。
(a) UIは描画のためにSlateモジュールを使用します。
(b) 我々のモジュールとSlateモジュールの間に依存関係を加える必要があります。
(c) そうすれば我々はそのモジュール内の宣言されたクラスにアクセス出来ます。
とあります。(a)は「Slateモジュールを使用してUIのための描画をします。」ということです。そのために、Build.csファイル内でSlateモジュールが使用出来るようにアンコメントしました。
ここで(b)と(c)についてですが良く分かりません。Slateモジュールに関しては依存関係を指定しましたので、slateモジュール内のクラスがこのプロジェクト内から使用可能になりましたが、(b)と(c)は「我々のモジュール内のクラスとSlateモジュールの依存関係を指定すると我々のクラスに我々がアクセス出来るようになる。」と言っています。しかし我々のモジュールが何なのかが不明です。更にそのモジュールとSlateモジュールの依存関係を指定するとありますが、Build.csファイルで指定したのはSlateモジュールの依存関係だけです。かなり不明です。とりあえず無視して次にいきます。
2.の解説の考察を行います。2.の解説では以下の事が述べられています。
(a) AHUDのサブクラスからcanvasを呼び出します。
AHUDのサブクラスであるCustomHUDクラスのメソッド*にDrawHUD()があります。そしてその実装部を以下に示します。
確かにキャンパスを呼び出しています。
*C++でつくるUnreal Engineアプリ開発を読んでいたら、P.44にUE4のC++で作成するクラス内のメンバー関数はメソッドと呼ぶと書かれていました。それでこの教科書でも関数と読んだりメソッドと読んだりしていたのですね。勉強になりました。
では、3.の解説の考察を行います。3.の解説では以下の事が述べられています。
(a) 新しいGameModeを作成する事が必要です。
(b) 我々のカスタム化したクラスのタイプの特定が必要です。
(c) 我々のカスタム化したサブクラスを使用するとエンジンに告げるためには、(a),と(b)が必要です。
まず、「(a) 新しいGameModeを作成する事が必要です。」はCustomHUDGameModeクラスの作成の事です。CustomHUDGameModeクラスはGameModeクラスのサブクラスでその作成は新しいGameModeの作成に当たります。以下にCustomHUDGameMode.hの一部を示します。
CustomHUDGameModeクラスの実装部を以下に示します。
HUDClassがCustomHUDクラスであると特定しています。これが「(b) 我々のカスタム化したクラスのタイプの特定が必要です。」なのでしょうか?HUDClassは何なんでしょうか?HUDClassはCustomHUDGameModeクラスで宣言した変数ではありません。GameModeクラスが元々もっている変数かと思いGameModeクラスのUE4のAPIを見てみるとHUDClassという変数はありません。一つ上の継承ヒラレルキーであるGameModeBaseクラスのUE4のAPIを見てみると、HUDClassの変数がありました。そこでは、HUDClassは、
このゲームで使用するHUDクラス
と説明されていました。ここはむしろ「(c) 我々のカスタム化したサブクラスを使用するとエンジンに告げる。」の部分でした。「(b) 我々のカスタム化したクラスのタイプの特定が必要です。」はそれならばStaticClass()メソッドしかないですね。StaticClass()のUE4のAPIを見てみると
実行中のこのクラスを表現するUClassのオブジェクトを返す
とあります。オブジェクトのタイプを特定してはいませんでした。となるとHUDClassがCustomHUDクラスであると特定し、かつ「エンジンに我々のカスタム化した(この)サブクラスを使用するとエンジンに告げる。」の(b)と(c)の部分の両方を担当していると考えられます。しかしタイプを特定するという言い回しにはHUDClassクラス以外のタイプも特定出来るというニュアンスが含まれていると考えられます。GameModeBaseクラスのUE4のAPIを見てみると以下に示すようにHUDClass以外のタイプも特定出来るみたいです。
では、4.の解説の考察を行います。4.の解説では以下の事が述べられています。
(a) UClassをHUDClassの変数に任命する。
これだけです。ただしこの(a)についての解説は沢山しています。まずこの(a)の部分ですが3.で散々考察した以下に示す部分のコードについての解説です。
4.では更に、この部分のコードは。
(ア) このUClassはそれぞれのプレイヤーコントローラーが生成された時にそれぞれのプレイヤーコントローラーにパスされる。
(イ) そしてそれぞれの(プレイヤー)コントローラーが生成されたAHUDのインスタンスを担当する。
と解説しています。何の事か分かりませんね。マルチプレイの場合の例を述べているのでしょうか?にしても唐突です。このHUDは体力ゲージのようなものを表示するのでマルチプレイならばプレイヤー一人一人の値が違ってくるはずです。それが可能です。と言いたいのでしょうか。にしても話が唐突です。
では、5.の解説の考察を行います。5.の解説では以下の事が述べられています。
(a) 実際にカスタム化したHUDクラスの作成が必要です。
これだけです。CustomHUDクラスの作成が実際にカスタム化したHUDクラスの作成に当たります。
では、6.の解説の考察を行います。6.の解説では以下の事が述べられています。
(a) DrawHUD()というバーチャル関数をAHUDが定義している。
(b) DrawHUD()はフレーム毎に要素をスクリーンに描く事が出来る。
まずDrawHUD()を関数と呼んでいるじゃないですか!UE4のC++で作成するクラス内のメンバー関数はいつもメソッドといつも呼ぶ訳ではないようですね。大学の教授が言っていたセリフを思い出しました。メソッドとか関数の使い方は人それぞれで偉い先生ほど独自な使い方をする。あんまりこだわらないほうがいい。と。とりあえず、DrawHUDメンバー関数を持つAHUDのUE4のAPIをみてみましょう。
HUDのためのメインの描画ループ
サブクラスされるべき
「HUDのサブクラスでDrawHUDメンバー関数をオーバーライドして描画する。」との解釈でいいみたいです。ところでこのAPIでもDrawHUD()を関数と呼んでいますね。
7.で述べられている内容はすでに6.で考察されていますね。ここはスキップします。
以下に示すコードについての解説のようです。
しかも今度はメソッドと書いています。DrawText()はメソッドなんでしょうか?DrawText()にカーソルを重ねてUE4のAPI を表示させると以下の表示となりました。
8.で表示されているメソッドと全く同じですね。UCanvasのUE4のAPIも見てみましょう。
二つ全く同じパラメーターのDrawText()があってどっちか分からないので両方載せました。よく見ると二番目のパラメーターが最初のはFStringで次のはFTextになっていました。一番目のDrawText()を使用しているみたいです。
更に、DrawText()はUCanvasの関数の処で説明されていました。UCanvasのメソッドとは書いてませんでした。やはりこの教科書のメソッド、メンバー関数の使い分けは適当みたいですね。
9.では結構いろいろな事が述べられています。ので9.の解説の考察を行います。9.の解説では以下の事が述べられています。
(a) DrawTextは書くためのフォントを必要とします。
(b) Statとエンジンコード内の他のHUD描画用のコマンドに使用されているデフォルトのフォントは、実際はGEngineクラスに保存されています。
(c) そしてGEngineクラスは、GetSmallFont関数を使用する事でアクセスされる事が可能です。
(d) GetSmallFont関数はUFontのインスタンスをポインターとして返します。
これらは全てDrawText()関数の最初のパラメータ―GEngien->GetSamllFont()についての解説です。
「DrawText()メンバー関数はフォントの指定が必要なのでGEngineクラスに保存されているデフォルトのフォントを使用します。GEngineクラスのデフォルトのフォントへのアクセスはGetSmallFont関数で行えます。」と言う事ですね。これ以上無いくらい簡潔かつ丁寧にDrawItem()メンバー関数の最初のパラメーターについて解説されています。何も考察しなくても意味が完璧に理解出来ました。
10.はDrawText()関数の2番目のパラメーターの解説のようですね。では10.の解説の考察を行います。10.の解説では以下の事が述べられています。
(a) DrawText()メンバー関数の次のアギュメントは実際のテキストです。
(b) そのテキストはそのテキストが持っているオフセット込みでピクセル化されて描かれます。
アギュメントは実際のデータでパラメーターは変数名です。よってDrawText()メンバー関数の2番目のアギュメントはTEXT("Test string to be printed to screen")です。ので(a)で述べているように実際のテキストです。(b)の部分は10.をかなり意訳したと言うか意味を推測して書きました。多分(b)の解釈であっているでしょう。
11.に関しては英訳が分からない部分がありました。Allows you to directly pass in the dataの部分ですが、in the dataなので「あなたがデータ内を直接横切る事(パスする事)を許可する」が正しい訳だと思います。しかし前後関係から考えると「データを直接パスする」になるはずなんですね。Allow you to directly pass the dataなら「あなたがデータを直接パスする事を許可する」になるんですが…。
11.はスキップします。
12.からはDrawItem()メンバー関数についての解説です。以下にDrawItem()メンバー関数とそのパラメーターであるProgressBarを以下に示しています。
では12.の解説の考察を行います。12.の解説では以下の事が述べられています。
(a) 一般的なDrawItem関数はVisitorの実装です。
(b) Visitorの実装はあなたがある情報をカプセル化したオブジェクトを作成する事を許可します。
(c) ある情報とは、そのオブジェクトは描画されるオブジェクトと、何回も描画呼び出しをするそのオブジェクトを再利用する事についてです。
(a)のVistorの実装とは何でしょうか?それを知るためには、DrawItem()メンバー関数のUE4のAPIを見てみましょう。
与えられた座標にキャンバスアイテムを描画します
特にvisitorについての解説は載っていませんでした。更に調べましたがvisitorについての解説は見つかりませんでした。(b)と(c)もvisitorについての解説です。ウーン…。Visitorが分からない以上12.の解説の考察は一端中止にしますか。
13.の解説の考察を行います。13.の解説では以下の事が述べられています。
(a) まずプログレスバーを描画するのに使用される要素を作成します。
(b) 我々はFCanvasBoxItem内でボックスの幅と高さに関する情報をセットします。
(c) FCanvasBoxItemのインスタンスProgressBarをDrawItem関数にパスします。
(a)から(c)についての解説は以下に示したコードの説明です。
FVector2Dが長方形の2つの対角な頂点を指しているはずです。大体の2D画面の座標は左上が(0,0)ですので、上記のボックスの場合、高さと幅は以下のようになると考えられます。
では試してみましょう。ボックスの高さと幅を以下の様に変えます。
非常に縦長なボックスになるのでしょうか?
全然違う形になりました。この結果から推測するに、最初のVectorがボックスの左上の座標、次のvectorが幅と高さを決定してるみたいです。
ので以下に示すように変えてみました。
今度こそ、非常に縦長なボックスになってくれるのでしょうか?
なりました。もう一回テストしてみます。
最初のVectorがボックスの左上の座標、次のvectorが幅と高さで間違いないですね。
14.は以下のコードについて解説しています。
14.の解説の考察を行います。14.の解説では以下の事が述べられています。
(a) 我々が描画する三番目のアイテムは中の詰まった長方形です。
(b) この関数はキャンバスそのものではなくHUDクラス内で定義される便利なメソッドを使用します。
(c) その中の詰まった長方形は我々のFCanvasBoxItemと同じ場所に配置されます。
(d) それで詰まった長方形はプログレスバー内側の現在の値を表現出来ます。
考察の必要のない完璧な解説ですね。しかし、テストだけは必要です。色と位置とサイズを変更してみましょう。以下の条件に変えています。
これも、最初のVectorがボックスの左上の座標、次のvectorが幅と高さで間違いないですね。
<まとめ>
今回のレシピは、キャンバスを使用して簡単な2Dイメージをゲーム画面上に表示する方法を習いました。以下の簡単なやり方を示します。
- 2つの新しいクラス(一つはgame modeを継承し、もう一つは、AHUDクラスを継承)を作成します。
- ゲームモードクラスを継承したクラスにAHUDクラスを継承したクラスをHUDクラスとして使用する事を告げます。
- AHUDクラスを継承したクラス内にDrawHUD()メンバー関数をオーバーライドして、その中でキャンバスを使用する事で簡単な2Dのイメージを表示します。
この方法が、歴史的な価値以上があるのかどうか、現在も使用する必要があるのかは不明だが使い方は理解出来ました。
<おまけ>
GameModeのクラスを作成する際、GameModeBaseのクラスを間違えて作成してしまいエラーが消せず最初からやり直した。以下にその時の失敗した手順を残しておきます。
――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
<失敗例>
<方法>
Step 0.
新しいプロジェクトを作成しました。バージョンは4.19.2を選択しました。プロジェクト名は、Chapter9_0526としました。
Step 1.
Sourceフォルダー内にあるChapter9_0526フォルダーにあるChapter9_0526.Build.csを開きます。
以下にBuild.csを示します。PrivateDependencyModuleNames.AddRange(new string[] { "Slate", "SlateCore" });がコメントアウトされているので、アンコメントします。
以下に結果を示します。
Step 2.
エディタークラスウィザードって何でしたっけ?4章に書いてあるそうなので見てみましょう。…見つからなかったです。しかし、GoogleするとC++ Class Wizardに説明されていました。エディターにあるクラスウィザードを使用してと言う意味でした。
以下に示すAddC++Classがクラスウィザードらしいです。
保存するフォルダーをどこにすべきかが分かりません。PuckePublish社のサンプルコードを先に見てみましょう。サンプルコードでは、CustomHUDGameModeはSourceフォルダー内のChapter9フォルダー内に保存されていました。よってPathはこのままでいきます。
出来ました。
Step 3.
加えました。
Step 4.
以下に示すようにcppファイルに加えましたが、エラーになりました。
AGameModeはEngine.hをインクルードすればいいらしいので、
としたら
エラー表示は消えませんがAGameModeの色が青に変わったのでとりあえずこれでやって見ます。