UE4の勉強記録

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

「Unreal Engine 4.xを使用してRPGを作成する」の足りない部分を作成する Bug直しとSave Part 2

f:id:kazuhironagai77:20210124230308p:plain

<前文>

HxH式操作系念能力者識別方法

U.S. capitolに侵入した人たちは、最低でも10年位の懲役を食らうらしいです。最近の捜査では彼らを手引きした議員か職員が居る事が明らかにされ、捜査関係者やその場にいた議員から、計画的なクーデターであったと、認識され始めています。ネットでも彼らの側に立っていた保守派、トランプ支持派のInfluencer達も急速にトークダウンして今までの自説を引っ込めて、黙るか、平然とU.S. capitolに侵入した奴らとは関係ないと開き直るかしています。

まだ、日本にはこのアメリカの空気の変化が微妙に伝わってはいませんが、日本におけるオ〇ムのサリン殺人事件の様な扱いになって来ている気がします。

トランプ大統領を含めたこの暴動をincitement(扇動?)した人達は、もう完全に自分だけが助かるのが目的になっていて、特にトランプ大統領に関しては、中で暴動を起こした人達が恩赦を求めても完全に無視しています。

可愛そうと言えば甘いと言われてしまうかもしれませんが、保守派の扇動に騙されてU.S. capitolに突撃した人は、多分、国内テロリストとして残りの人生を生きていかなければならなくなりました。飛行機に乗る事すら出来なくなるかもしれません。トランプ大統領とその支持者たちは「今回の大統領選挙が、不正によって本当は選挙に勝っているにも関わらず、負けてしまった。」と一見、誰にでも分かるような嘘をネットで何百回も繰り返し主張し、実際に極僅かですが、真面目なアメリカ人を騙す事に成功しました。

これほど騙され損な事はないですが、先週述べた理由によりこのような事件はこれから沢山起きてくると思われます。

その理由とは「ネットのAIが同じような事を言うサイトやビデオばかり薦めてくる。」事です。それによって「今回の大統領選挙が不正である。」の様な骨董無形な話にも視聴者や読者には真実に映ってしまいます。

私はこれに気が付いたのは、Epic Game社とAppleとの裁判の時です。YouTubeのお勧めに出てくるサイトの全てがEpic Game社が悪いとしか言わないんです。後で自分で検索したら、沢山の人がEpic Game社の味方をしているにも関わらず、お勧めに出て来るビデオは全てEpic Game社が悪いで統一されていたんです。

今回のU.S. capitolにおける暴動の後に、私自身で確認しましたが「今回の大統領選挙が不正によって本当は選挙に勝っているにも関わらず負けてしまった。」と主張している人のビデオを一個見たら、立て続けに似たようなビデオが表示されました。その中には、弁護士などが作成したビデオがありました。一般人の立場なら、そんな人たちが言っているなら正しいのだろうとなっちゃいますよ。

だから今回の事件の主犯は、ネットのAIなんです。

ここを直さない限り、同じような事件は必ず起きます。それまでは、我々に出来る対策は、このような扇動をあおる詐欺に引っかからない様に気を付ける事だけです。具体的に言うと、彼らの主張に対して科学的に正しいのか検証する事です。しかし常識的に考えれば、一般人には、そんな事が出来る時間も、予算も、そして専門的な知識もあるわけないです。

そういう時間もない、予算もない、そして専門的な知識もない状況で最適な判断を下すために、先週、思いついたHxH式操作系念能力者識別方法をここに紹介します。

前に書きましたが、HxHの念能力者のタイプ分類に沿ってプログラマーを分類すると結構当たっています。このHxHの念能力者のタイプの一つが操作系で、このタイプは何かを操作する事に長けているタイプです。この分類方法は、実際にはプログラマーだけでなくあらゆる専門職にも使えて、今回の事件に当てはめると、ネットで扇動していた人達は操作系に当てはまります。

彼らは、色々言っていますが、やっている事は、扇動(操作)する事だけです。このタイプが指示する側にいたら、間違いなく自分は扇動(操作)されていると考えるべきです。この操作系を見つける方法の一つは寄付の支払い方を確認する事です。寄付をする段階になった時に操作系は絶対しないです。騙されている側の人は飯を抜いてでも寄付します。しかし扇動(操作)する側は絶対に寄付しません。

あなたを扇動する操作系が見つかったなら、あなたは操作されている事は確認出来たわけです。そして操作されている間は最適な答えを見つける事は出来ないと自覚しましょう。なぜなら操作されている間は、あなたは操作している人の望み通りに動いているだけだからです。この操作されている状態を外すだけで、最適解を見つける確率が0ではなくなります。

ではどうやって外すかと言う事なんですが、これもHxHの中に答えが既に提示されています。操作系は別の操作系がコントロールしている人は操作出来ないんです。つまり既に誰かに操作されている状態の人を操作する事は出来ません。これってかなり真実でしょう。今回の暴動に参加した人の中に、イスラム教の人や、日本のアニメやゲームが好きな層、更に言えば白人以外の人っていますか?私が見た限りでは一人もいませんでした。例え居ても極少数でしょう。(何故か、ロシア訛りの英語を話す人やPCゲームのファンは居たみたいです。これは本筋から離れるのでここでは述べません。)

先程述べたEpic Game社とAppleとの裁判の例でも、口の悪い言い方をすれば、私自身が既にUE4の信者であったので「Epic Game社が悪い」と言う扇動(操作)に罹らなかったんです。だから、何かの信者(アニメでも、ゲームでも、スポーツでも、そして勿論、宗教も)に前もって成っていればいいんです。

そこで私のお勧めは、プログラミング教の信者になる事です。プログラミングの勉強を一生続けると、死後天国に行けると言う信仰です。一定のレベル以上のプログラマーは休みでも何かしらの勉強をしています。これは普通の人から見ると大変きつそうですが、天国に行くための修行と捉えればきつくても納得です。

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

<本文>

1.今週の作業

今週はUE4_AIについての勉強をします。

  1. TaskクラスのAbort、ExecuteとTick関数とdecoratorクラスのObserver abortsの設定の関係について
  2. 先週やったTutorialの続き
  3. 実際に使用するモンスター様のAIの作成

を行います。

2. TaskクラスのAbort、ExecuteとTick関数とDecoratorクラスのObserver abortsの設定の関係について

先週「Unreal Engine 4で極めるゲーム開発」を読んでいたらTaskクラスのAbort()関数は、Observer abortsでLower Priorityのような設定でAbortされた時に発動すると書かれていました。目から鱗です。これを確認します。

2.1 SequenceノードとSelectorノードの復習

ですが、全てのノードの機能についての確認を最初にやっておきます。まずSequenceノードとSelectorノードについての確認です。

まずはSelectorノードのテストです。

以下のコードを作成しました。

f:id:kazuhironagai77:20210124230449p:plain

実行されるのはどのTaskでしょうか?もしSelectorのChildの一つでもSucceedしたらそこで止まります。

ので、PrintStringのみが実行されるはずです。

テストしてみます。

f:id:kazuhironagai77:20210124230511p:plain

PrintStringのみが実行されました。ここまでは予測通りです。

次にこのゲームを終了します。どのTaskのAbortが実行されるのでしょうか?

実行されているのは、PrintStringノードのみです。だからPrintStringのAbortのみが実行されるはずです。

テストして試してみます。

f:id:kazuhironagai77:20210124230528p:plain

その通りでした。

今度は以下の様にSequenceノードを代わりに使用します。

f:id:kazuhironagai77:20210124230545p:plain

SequenceはFailureするまでChildノードを次々に実行するはずです。ので

  • PrintString
  • PrintString1
  • PrintString2
  • PrintString3

が表示されるはずです。

f:id:kazuhironagai77:20210124230622p:plain

あれ?

PrintString Task内でFinish Executeノードを追加するのを忘れていました。

f:id:kazuhironagai77:20210124230643p:plain

PrintString1、PrintString2、PrintString3にもFinish Executeノードを追加しました。

もう一度テストします。

f:id:kazuhironagai77:20210124230702p:plain

なんと永遠にPrintされています。

Selectorの場合ももう一度試してみます。

f:id:kazuhironagai77:20210124230721p:plain

Selectorも永遠に実行されていました。しかもこの場合、終了した後、Abortが呼ばれません。

Successのチェックを外してみます。

f:id:kazuhironagai77:20210124230738p:plain

最後まで全てのTaskを実行して、その後また最初のtaskに戻って実行しています。

f:id:kazuhironagai77:20210124230755p:plain

この場合も終了した後、Abortは呼ばれません。

うーん。なるほど。Abortは途中で収容した時に呼ばれるのかもしれませんね。

2.2 Abort Eventを呼ぶ

検証のために以下のコードを作成しました。

f:id:kazuhironagai77:20210124230817p:plain

ChooseNumberは0に指定しています。

Finish Executeは全部Trueに変更しました。

テストします。

f:id:kazuhironagai77:20210124230834p:plain

想像していた通りの結果がプリントされています。

今度は、ChooseNumbarを途中で2に指定してみます。

f:id:kazuhironagai77:20210124230925p:plain

PrintString1(Execute)が終了した時にChooseNumberが2に成りました。そしてその後にPrintString2(Execute)とPrintString3(Execute)がプリントされています。Abortはプリントされませんでした。

f:id:kazuhironagai77:20210124230949p:plain

Observer AbortがNoneにセットされているからでしょうか?

Selfに変更してみます。

f:id:kazuhironagai77:20210124231005p:plain

今度は、PrintString(Execute)を実行した後、にChooseNumber is set to 2が実行されています。そしてその後で、直ぐにPrintString2(Execute)が実行されています。

これは、先週紹介したサイト

f:id:kazuhironagai77:20210124231023p:plain

この説明に合っているように見えます。

もう少し厳密に検討するためにWait taskを追加します。

f:id:kazuhironagai77:20210124231041p:plain

これでもう一度テストします。

最初はObserver Abort をNoneにセットしました。

f:id:kazuhironagai77:20210124231056p:plain

今度は分かり易いです。PrintString(Execute)が実行した後、Waitノードが実行されている時に、ChooseNumberが2に変更されました。しかしその次のノードであるPrintString1(Execute)は実行されています。全てのノードの実行が終了した後で、ChooseNumberが2である条件に該当するNodeが実行されています。

これはサイトにある説明通りです。

今度はselfに変更します。

f:id:kazuhironagai77:20210124231245p:plain

今度も前回と同じ様に、PrintString(Execute)が実行した後、Waitノードが実行されている時に、ChooseNumberが2に変更されました。今回は次のノードであるPrintString1(Execute)は実行されず、ChooseNumberが2である条件に該当するNodeが実行されています。

これもサイトの説明通りです。

しかしこの時にAbortは呼ばれていません。何故なんでしょうか?

ピンと来ました。Waitノードを外してPrintString1 taskにDelayノードを追加します。

f:id:kazuhironagai77:20210124231335p:plain

これでテストしてみます。

f:id:kazuhironagai77:20210124231352p:plain

出来ました。今度はAbortが呼ばれています。

PrintString1 taskの実行中にChooseNumberの値が2に変化したので、PrintString1の実行をabortして、ChooseNumberが2である条件に該当するNodeを実行しています。

2.3 Observer Abort の確認、None、Self、Lower PriorityそしてBothの違い

2.3.1 None

上記のSelfと同じ条件でNoneをやってみます。サイトの説明通りならNoneの場合は、abortは呼ばれないはずです。

f:id:kazuhironagai77:20210124231425p:plain

PrintString1 taskの実行中にChooseNumberの値を2に変化しましたが、今回はその変化を無視してPrintString1の実行を続行しています。

予想通りでした。

2.3.2 Lower Priority

f:id:kazuhironagai77:20210124231456p:plain

と書かれています。これだとこのテストだとNoneと同じ結果になるのでは?

と思いテストの条件をちょっとだけ変える事にします。

しかしその前に一応確認のテストをしておきます。

f:id:kazuhironagai77:20210124231624p:plain

うん。同じ結果ですね。

一応、Bothの場合もテストしておきました。

f:id:kazuhironagai77:20210124231644p:plain

こちらはSelfと同じ結果です。

それではテスト条件を以下の様に変更します。

f:id:kazuhironagai77:20210124231707p:plain

PrintString1の隣にPrintString2を追加しました。

まずNoneの場合です。

f:id:kazuhironagai77:20210124231737p:plain

PrintString1を実行している途中で、ChooseNumberの値を2に変化しました。しかし最後までPrintString1を実行し、更にPrintString2を実行しています。その後でChooseNumberの値が2の時の条件に合うSequenceのTaskを実行しています。

今度はselfです。

f:id:kazuhironagai77:20210124231831p:plain

PrintString1を実行している途中で、ChooseNumberの値を2に変化しました。PrintString1の実行を中断し、その後でChooseNumberの値が2の時の条件に合うSequenceのTaskを実行しています。PrintString2は実行していません。

Lower Priorityの場合です。

f:id:kazuhironagai77:20210124231953p:plain

あれ、PrintString2は実行されないと思ったのですが、想像していたのと違う結果ですね。

ちょっと考えます。

分かりました。Lower Priorityの場合、

f:id:kazuhironagai77:20210124232016p:plain

この右側の部分が全て無視されるはずです。

そしてbothの場合は、Self + Lower priorityとなり、全部中止になるはずです。

これを明確に表示するために、以下のコードを作成しました。

f:id:kazuhironagai77:20210124232256p:plain

このコードの特徴はPrintStringとPrintString3のFinish ExecuteをFailureで返す所です。

これで、実際のコードの流れをもっと細かく見れます。

PrintString1を実行している途中で、ChooseNumberの値を2に変化しました

Noneの場合

f:id:kazuhironagai77:20210124232350p:plain

予測通りですがそのまま実行しています。PrintString2(Execute)を実行した後でSelectorにSuccessを送るので、selectorは最初からやり直しています。

Selfの場合

f:id:kazuhironagai77:20210124232456p:plain

予測通りPrintString1(Execute)の実行を中止してabortを発動しています。その隣のtaskであるPrintString2(Execute)は実行されません。Selectorに戻ると、selectorはSuccessの信号を受け取っていないのでそのまま次のnodeを実行しています。

Lower Priority

f:id:kazuhironagai77:20210124232548p:plain

これでもNoneと同じ結果になってしまいました。

Noneとの違いを確認するために、PrintString2(Execute)のFinish Executeの返しをFailureにします。

Noneの場合です。

f:id:kazuhironagai77:20210124232624p:plain

PrintString3、PrintString4が実行されています。

Lower Priorityの場合です。

f:id:kazuhironagai77:20210124232645p:plain

この場合、PrintString1(Execute)のみ実行されて、PrintString2、PrintString3、PrintString4はabortされると思われるのですがされていませんね。Noneと全く同じ形になってしまっています。

何故なのでしょう?

Both

f:id:kazuhironagai77:20210124232746p:plain

これもSelfと全く同じ結果になっていますね。

2.3.3 Observer Abortまとめ

もし私のObserver Abortのそれぞれの要素に対する理解が100%正しいとしたら、Lower Priorityが効いていないと考えると全部辻褄が合います。

まあ今回は、そういう可能性もある位で、留めておいてObserver Abort はNoneとSelfだけ使用するようにします。

3. 先週勉強したTutorialの続き

3.1 Guard AI

特になしです。単にServiceを使用してNPCの歩くスピードを調節しただけ。しかしNPCとの追いかけっこが結構面白くなってきました。

3.2 Guards Searching

特に新しい関数とかは出て来ませんでした。どうやったらAIが本物のGuardみたく動くのかを勉強する感じです。

f:id:kazuhironagai77:20210124233232p:plain

Abortした時は、failureになると思っていたのです、finish abortで返してもそうなんでしょうか?Loopの下のBlackboard Conditionはselfにセットされているので、途中で条件が変わると行動が変化します。

f:id:kazuhironagai77:20210124233257p:plain

流石に、追い駆けっこそのものは滅茶苦茶面白いです。これだけでゲームに成りそうなくらいの完成度です。

何でこんな面白いんでしょうか?

NPCの反応が、生きた人間そっくりだからでしょうか?

不思議ですね。

3.3 Melee Attacks (Animation)

Meleeってどういう意味だったけ。と調べたらグーグルの一番最初に以下の説明が表示されました。

f:id:kazuhironagai77:20210124233332p:plain

もっと、抽象的な概念を想像してたんでびっくりです。

アニメーションの作成方法で今まで知らない方法を学びました。

まずAnimation Montageです。

f:id:kazuhironagai77:20210124233424p:plain

f:id:kazuhironagai77:20210124233433p:plain

もしかしたら一回位は、作成した事位はあるかもしれませんが、ほとんど初めて聞いたクラスです。使用目的や使用方法などは全く分かりません。

次はAnimationBlueprintクラスのAnimGraphで先程作成したslotとDefaultをblendする方法です。

f:id:kazuhironagai77:20210124233451p:plain

これも初めて勉強する方法でした。

正直、完全に理解したとは言えません。Tutorialに書かれてる通りにやったら動きました。と言う感じです。UE4_animationは一度しっかり勉強する必要がありますね。

f:id:kazuhironagai77:20210124233507p:plain

Blendしたanimationをスクリーンショットで撮ったんですが、動作がほとんど終了していました。

3.4 Melee Attacks (Behaviour)

今度は前節で作成した攻撃モーションをNPCが使用します。

以下に示した様に最終的には出来ましたが、結構大変でした。

f:id:kazuhironagai77:20210124233535p:plain

以下に示したtaskのChasePlayerのfinish Executeがfailureで返されていて次のMelee Attackが呼ばれなかったです。

f:id:kazuhironagai77:20210124233557p:plain

このバグに気づかなくて、直すのに30分位かかりました。

新しい関数としてSimple Parallelを習いました。

f:id:kazuhironagai77:20210124233648p:plain

Simple ParallelのFinish Modeには2種類あり、immediateは左に接続したmain taskが終わり次第、終了します。DelayedはBackgroundで実行されている他のTaskが終了するまで待ちます。

f:id:kazuhironagai77:20210124233707p:plain

Get Distance to関数は二つのActorの距離を返します。

f:id:kazuhironagai77:20210124233724p:plain

3.5 Hearing Perception

まず、AIのデバッグをするために ‘を押してくださいとありますが、

f:id:kazuhironagai77:20210124233759p:plain

Shift+7を押しても何も表示されません。

これは日本語キーボードには対応していないのかもしれないと思い日本語でこれについて書いてある記事を探したらここにありました。

その記事を参考にして1を押すとGamePlayデバックが表示されるように設定し直しました。

f:id:kazuhironagai77:20210124233826p:plain

表示されるようになりました。

Perceptionを表示しています。

f:id:kazuhironagai77:20210124233845p:plain

でも何も表示されない時もあります。

f:id:kazuhironagai77:20210124233901p:plain

何も表示されない時は、Debug actorがNoneになっていました。

f:id:kazuhironagai77:20210124233921p:plain

表示される時は、

f:id:kazuhironagai77:20210124233954p:plain

NPC_2になっています。どうやってDebug actorを選択しているのか、今は分かりません。

Hearing Perceptionについて

一応、Tutorial通りに作成しましたが、Hearing Perceptionそのものについては、個別のTutorialで教えてほしかったです。そして今まで作成したSight Perceptionとの結合方法を教えてくれた方が全然分かり易いと思いました。

複数の知覚を設定した時に、どの知覚から信号を受け取ったのか判別する方法は、以下に示しました。

まず、AIPerceptionStimuliSourceのReport Noise EventのTagに名前を追加します。

f:id:kazuhironagai77:20210124234017p:plain

AI_Controller側で刺激を受け取りTagから名前を調べます。

f:id:kazuhironagai77:20210124234105p:plain

3.6 Damage Sensing

このTutorialからコメント欄が文句の嵐になっていてます。多分何か問題があるのでしょう。ここからは軽く見る事にします。

前のtutorialのバグの直しから始まっています。プログラマーなら自分で直せるはずなので直しそのものは重要ではないですが、その後のテストで、

  • NPCがパトロール中にプレイヤーを目撃した場合
  • NPCがパトロール中に何かの音を聞き、プレイヤーを確認した場合
  • NPCがパトロール中に何かの音を聞き、調査に行った途中でプレイヤーを確認した場合

を確認しているのを見て、そう言う事だったのかと思いました。確かに門番がパトロール中に侵入者を目撃したら、追いかけていきます。不審な音が聞こえたらパトロールのルートを外れても確認します。そしてその過程で侵入者を見つけたら追いかけます。

こういう事を真剣に考える事で人間らしく反応するAIが作成できる事が分かりました。

Damageの設定そのものはAction Gameか何かの時に本格的に勉強すると思いますので、今回はUE4にはこんな機能もあるのか位に留めておきます。

3.7 Nav Link Proxy

Nav Link Proxyの使い方の説明で、NPCが高い所から低い所にNav Link Proxyを使用して降りる場合を説明していました。たった5分の説明なのでこれだけでNav Link Proxyを使いこなす事は出来ないと思いますが、大変興味深い機能と思いました。

この次のTutorialでNPCが低い所から高い所に移動する場合について説明するとありましたが、次のtutorialはAI EQSについてでした。

3.8 AI EQS Part 1とAI EQS Part 2

EQSは試験的な部分がまだありますと説明されていたんで、AIの基礎を勉強中の私が特別、積極的にやる必要はないと思い、軽く動画を見るだけにしました。

4.まとめと感想

今週はここまでで時間が無くなってしまいました。モンスターのAIの改良は来週やる事にします。