UE4の勉強記録

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

「Unreal Engine 4.xを使用してRPGを作成する」の足りない部分を作成する ターン制戦闘の改良 Part5

f:id:kazuhironagai77:20200405201137p:plain

<前文>

英語の正しい発音が聞き取れるようになるゲームの開発が順調に進んでいるのですが、発音よりもっと大切な事がある事を伝えるのを忘れていました。これは私には当たり前過ぎて説明する必要があるとは思わなかったのですが、どうもほとんどの日本人は日本でのニュースや常識は世界と同じと思っていてその日本語で得た世界観を元に英語でも会話しようとします。これは実は発音よりたちが悪くて全く会話が通じなくなります。

はっきり言って日本での常識やニュースと英語圏の常識やニュースは全く違います。普段から英語のニュースを見て、全世界の人々がどんな議論をどんな事実に基づいてしているのかをしっかり認識した上で、英語で会話しなければ、どんなに発音が良くても通じません。逆に発音が悪くても、その部分がしっかりしていればはっきり言えば英語でのコミュニケーションは何の問題もなく出来ます。

それを分かり易く伝える例として今回は、今世界中をパニックにしているc-何とかウィルスに対しての英語圏における考え方を紹介します。私は普段アニメや漫画の話ばかりして、こんな真面目な話はしませんし専門外の話は真面目な時でもしません。それは専門外の話は必ず間違えて伝わるからです。ので結構ぼやかして書きますが、以下に日本内での考え方や常識と違うかにについて雰囲気だけでも伝えようと思います。

*以下の文章は先週既に書いていたので、今日では内容が変わってしまった部分もありますが、言いたい事の本質は伝わるのでこのまま掲載します。

SIRモデルと言う考え方。

別に日本以外の全ての人が英語をしゃべっていると言うわけではないですが、世界中の政府の代表は英語で会話するので便宜上そうなってしまいます。SIRモデルとはその中で頻繁に出てくるパンデミックのモデルの事で、susceptible(これから病気にかかる可能性のある人)、infectious(今、病気に感染している人)、そしてRecoveredもしくはRemoved(病気から直った人、もしくは死んだ人)となります。これらの3つの要因がどのように変化するかでパンデミックになるかを計算で予測するモデルをSIRモデルと呼ぶそうです。これが英語圏での、c-何とかウィルスを語るための必須の知識になります。

普通の日本人はこんなモデル初めて聞いたよ。と思うでしょうが、大卒レベルの知性があると英語圏の人に思われたければこのSIRモデルに基づいて会話しなければなりません。

検査、検査、そして検査

このSIRモデル、基本は単純ですが、それに色々な要素を追加して現実に即した形に変化してシミュレーションするらしいです。しかしどんなに変化しても検査を完璧に行ってinfectious(今、病気に感染している人)を隔離しつづけると感染者数は0に収束するらしいです。これは検査の精度が悪くて2割ぐらい逃しても計算によっては収束するらしいです。

今、世界中のほとんどの国がこれを行っています。だから日本で症状が重い人に限って検査するのとは根本的に考え方が違います。これを理解している日本人見た事ありません。英語圏で行っている大規模な検査は隔離が必須なんです。私が知る限りでは、日本語で大規模な検査と隔離を同時に議論した例はないように思えます。

これを成功させたのが韓国と中国です。どちらもある時期を越えると感染者の数が急激に減少しました。のでこの2つの国は既にc-何とかウィルスの感染を防いだと考えられています。

アメリカはまだ検査数が足りない状態みたいです。ビルゲイツ氏が、自宅で患者自身が検査出来て、精度は医者が行ったのと同じ程度の検査キットを開発したと言っていました。

本題から外れるかもしれませんが、英語圏では日本の対策は、全員に感染させて免疫をつけさせる方法を選択していると思われています。あるイギリスの試算によるとこの方式を採用した場合、人口の半分が感染するまで収束はしないそうです。このc-何とかウィルスの場合、それが達成されるためには最低でも数年が必要で人口も相応に減るそうです。

こんなに考え方が違っていたら、英語の発音が上手くても会話にならないのは分かりますよね。

Social distancingという考え方

この感染した人を全員捕獲して隔離が完了する間、人々が日常生活を送っていたら、どんどん感染が広がってしまいます。ので健康な人も移動しないで家で待機してくれ。というのが第一の定義です。この考え方、英語圏では滅茶苦茶徹底されていてます。それはこれが経済活動を完全に停止するからです。これもビルゲイツ氏の受け売りなんですが、速く取り掛かかれば取り掛かるほど、時間も短くて済み結果的に損害も少なくて済むそうです。だからさっさとやってさっさと済まそうと言う事のようです。

もう一つの定義は、人と人が合う時も2m以上離れましょう。というものです。SIRモデルでこの2番目の定義を語る時に大切な要素が二つあるそうです。まずRとかR0とか言われる感染者が人に病気を移す数と、うーん。すいません。度忘れしてしまいましたが、感染率を表す言葉です。この二つの要素が人と2m離れると凄く低くなるそうです。

でもマスクして手洗いする方が、Rとか感染率とか下げれるんじゃないのと思いますが、今世界中の人がパニクッていますのであんまり突っ込まない方が無難ではあります。

ここまでが英語圏でも大卒レベルの議論でこの下からは高卒レベルの議論になります。大体の日本人も今までの話は大多数の部分は納得したと思いますが、以下の話はどうでしょうか?

マスクはいらない

マスクをつけるな。とはっきり言っていますがその理由は、日本人が使って自分たちが罹る医者が使用するマスクが足りなくなると信じているからです。日本人が普段使っているマスクは医療用じゃないですし、上でも述べましたが、どう考えてもマスクは効果があります。

顔を触らない

手でc-何とかウィルスを触った場合、そのままその手で目や鼻を触って感染するそうです。それは分かります。でもその後でだから顔を触るなと言います。これって不可能ですよね。だから普通は手の消毒や洗浄をこまめに行う方を頑張るべきと思います。しかし大半のアメリカ人は他人に見つからない範囲で顔を触らなければOKと思っています。

Fo***wsについて

アメリカ人でも、ある程度以上の学力のある人からはアホだと思われています。絶対に真似しないようにしましょう。中国政府じゃなくて中国人全体が滅茶苦茶怒っているそうです。イギリス人によると完全に戦争コースだそうです。個人的な感想ですが大学の寮でサンダ?を練習している中国人とレスリングと空手をやってたアメリカ人が喧嘩した時を思い出しました。その喧嘩はアメリカ人がMMAばりにタックルをした所を中国人がフロントヘッドロックを極めて一瞬で終わるかと思ったら中国人の方は落とし方は知らないらしくて、そのまま20分ぐらいカメみたく2人して固まっていました。私は、アメリカ人がよくやるブンブン手を振り回すフックを中国人がどうやって躱すのか見たかったので勉強で忙しかったのですが最後まで見てました。

でも一方で、アメリカと中国の両方の医者や学者、エンジニアなんかも、協力してこのc-何とかウィルスに対して戦っています。将来的にはどうなるんでしょうか?

もう一つ分からないのが台湾の態度です。あらゆる意味で中国とアメリカが敵対するのは得なのに、この件ではあまりアメリカと一緒に中国を非難する事はしてませんね。やっぱり礼節は大切と言う事でしょうか?

かなり曖昧な書き方ですが、日本での常識やニュースと英語圏の常識やニュースは全く違うと言う事はそれなりに伝わったかと思います。

それでは今週の勉強を始めます。

<本文>

1. インターフェイスとその派生クラスの使用方法について Part 2

この教科書ではCombat Engineを作成する際にインターフェイスをインクルードした上でそのインターフェイスをForward Declarationをしています。

f:id:kazuhironagai77:20200405201449p:plain

この理由が分かりません。先週、ある理由を思いついて生のC++で検証しましたが予想した結果は得られませんでした。その時よく見たら教科書のコードはCircular dependencyにもなっていました。今週はその事を考慮してもう一度考察します。

本当にこのForward declarationが必要なのかまだ試してなかったです。

以下のようにコメントアウトしてビルドしてみます。

f:id:kazuhironagai77:20200405201520p:plain

やっぱりエラーになりました。

f:id:kazuhironagai77:20200405201548p:plain

f:id:kazuhironagai77:20200405201557p:plain

まあ、Circular dependencyになっているんですから、必要なのは当たり前ですね。

では、先週作成したクラスを加工してcircular dependencyを意図的に作成します。

baseInterfaceのヘッダーファイルにexampleクラスから作成する変数を追加することでbaseInterfaceとexampleクラスにcircular dependencyを作成する事にします。

f:id:kazuhironagai77:20200405201623p:plain

baseInterfaceのヘッダーファイルにexampleクラスのforward declarationをします。更にインクルードでexample.hも追加します。

f:id:kazuhironagai77:20200405201651p:plain

これで、baseInterfaceとexampleクラスにcircular dependencyが出来たはずです。

この状態でもう一度、先週のテストをやってみます。

f:id:kazuhironagai77:20200405201716p:plain

今度は、エラーになりました。

一応、教科書の状態は再現出来たようです。

今度は、Forward declarationのclass baseInterfaceの部分をアンコメントしてテストします。

f:id:kazuhironagai77:20200405201743p:plain

f:id:kazuhironagai77:20200405201752p:plain

普通に動きました。

f:id:kazuhironagai77:20200405201821p:plain

これって単なるCircular dependencyを避けるためのForward declarationのような気がしてきました。

そうなるとForward declarationしているクラスのヘッダーを何でインクルードしているのかが分かりません。

今度はインクルードの部分をコメントアウトしてテストしてみます。

f:id:kazuhironagai77:20200405201851p:plain

以下に結果を示します。

f:id:kazuhironagai77:20200405201951p:plain

普通に動いた!

今度は教科書のコードで試してみます。

f:id:kazuhironagai77:20200405202011p:plain

うーん。こっちではエラーになってしまいました。

f:id:kazuhironagai77:20200405202031p:plain

以下の箇所でエラーになっています。

f:id:kazuhironagai77:20200405202100p:plain

これは、GameCharacter.hを通してIDecisionMakerインターフェイスをインクルードするのではなく、このクラスでIDecisionMakerインターフェイスをインクルードすべきでしょう。今回の疑問であるインターフェイスをインクルードした上でそのインターフェイスをForward Declarationとは直接関係ないです。

今度は以下の様にしてテストします。

f:id:kazuhironagai77:20200405202144p:plain

これならさっきのクラスはエラーを吐かないはずです。

f:id:kazuhironagai77:20200405202208p:plain

成功しました。

これで大体謎が解けました。3週間ぐらいかかりましたが。

簡単にまとめます。

以下に示すように、この教科書にはインクルードしているインターフェイスクラスを更にForward declarationしている箇所があります。何故こうなっているのかが分かりません。それを調べました。

f:id:kazuhironagai77:20200405202305p:plain

結論は、単にCircular dependencyを避けるためにForward declarationをしているだけでした。includeはこのクラスになくても普通にビルドします。

このようにIncludeとForward declarationを同時にしてもコンパイラーがForward declarationを先に処理してその後includeを処理しているみたいでエラーにならないです。

それだけでした。

2. ゲームオーバー画面の作成

1. ゲームオーバーの流れの復習

Combat engineで実際のゲーム―オーバーの流れを確認します。

RPGGameModeクラスのTick()関数を見ていきます。

f:id:kazuhironagai77:20200405202453p:plain

戦闘が終わったらcombatOverがtrueになります。それは覚えています。

そしてphaseがCPHASE_GameOverなので以下のコードが実行されます。

f:id:kazuhironagai77:20200405202511p:plain

このコードの最初に注目する個所はRPGGameInstanceクラスの関数、PrepareReset()が呼ばれている所です。

f:id:kazuhironagai77:20200405202539p:plain

この関数の実装部を見てみます。

f:id:kazuhironagai77:20200405202605p:plain

IsInitialized変数は何処で使用されている変数が覚えていませんね。PartyMembersにEmpty()関数を使用していますね。ここで開放しているんですね。

うーん。まだTArrayクラスとempty()関数の使用方法が良く分かりませんね。

以下にPartyMembersの宣言部を示します。

f:id:kazuhironagai77:20200405202644p:plain

UPROPERTY()マクロで修飾しているのでTArrayに指定されているそれぞれの要素は開放されません。しかしempty()関数を使用する事で、TArrayからのポインターが外れて、GCが回収出来るようになる。と言う事でしょうか?

次の行を見てみましょう。

f:id:kazuhironagai77:20200405202711p:plain

うぁあ。いきなり難問が。

このウィジェット、ローカルな変数で初期化されていますが、この関数が呼ばれた後、どうなるんでしょう。メモリーリークしてますよね。

最後のコードです。

f:id:kazuhironagai77:20200405202739p:plain

これは普通ですね。特にコメントはありません。

2. GameOverScreenのBPウィジェットを読む

RPGGameModeのGame Over UIClassを見るとGameOverScreenがセットされています。

f:id:kazuhironagai77:20200405202810p:plain

このBPウィジェットを読んでいきましょう。

f:id:kazuhironagai77:20200405202829p:plain

まず。Event Constructです。C++におけるコンストラクターと同じ役割の箇所です。

カーソルを表示させているだけです。

次に「もう一度ゲームを始める」ボタンを押した場合のコードをみます。

f:id:kazuhironagai77:20200405202849p:plain

f:id:kazuhironagai77:20200405202858p:plain

RestartGame()関数がRPGGameModeクラスから呼ばれています。この関数GameModeクラスから継承した関数のようです。調べて見ます。

ここに解説がありました。

f:id:kazuhironagai77:20200405202922p:plain

あれ、現在のマップから再スタートと書かれていますが、最初からじゃないの?

試してみます。

f:id:kazuhironagai77:20200405202950p:plain

別なマップにテレポートしました。ここで死んでみます。

f:id:kazuhironagai77:20200405203016p:plain

死にました。もう一度ゲームを始めます。

f:id:kazuhironagai77:20200405203041p:plain

ああ、このマップから始まりました。知らなかった。

3. 教科書を読む

やっと、先週の続きになりましたが、教科書の3章の4節の最後の小節、GameOver画面の作成を読んでいきます。

最初に再スタートボタンの実装が載っていますが、私が作ったのと違います。教科書の例を以下に示します。

f:id:kazuhironagai77:20200405203114p:plain

まあ、やっている事は同じなので気にしないで先に行きます。多分私の方はサンプルコードから写したんでしょう。

教科書の説明を一個一個書いても仕方ないので、私が知らない事を説明している箇所だけ以下に書いて行きます。

f:id:kazuhironagai77:20200405203142p:plain

Empty() 関数について以下の様に説明しています。

f:id:kazuhironagai77:20200405203207p:plain

特に、Empty()関数の機能についての説明ではありませんでしたが、一寸は足しになる情報です。

これだけでした。

f:id:kazuhironagai77:20200405203251p:plain

このクラスがメモリーリークにならない理由の説明がほしかったですがここにはありませんでした。

3. まとめと感想

これでcombat engineの復習は終わりました。来週からは、新しいCombat engineを作成するのか、と以下に示した機能の追加をやっていきます。

f:id:kazuhironagai77:20200405203330p:plain