UE4の勉強記録

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

「Unreal Engine 4.xを使用してRPGを作成する」の足りない部分を作成する 戦闘システムを完成する3

f:id:kazuhironagai77:20201129200835p:plain

<前文>

グーテンベルグの銀河系とYouTubeのlive

Gundamに出て来るニュータイプって、活版印刷が発明された直後に起きたような人類の意識の進化が宇宙に移民した事で起きると言う意味だったはずなのに、何故か最終的にエスパーみたいな解釈になったんでしょうか。まるで途中から別人が書いたように解釈が変わっていますよね。

それはともかくとして、活版印刷が発明された直後に人類の意識が明白に変化した事を最初に指摘したグーテンベルグの銀河系はMcLuhan によって1968年に書かれました。その時代にMcLuhanは視聴者と芸能人の双方向性で進行するテレビ番組の出現を予測してそれが実現した時、更なる人類の意識の進化が起きると宣言していました。この視聴者の意見を聞きながら進行するテレビ番組って今、2020年のYouTubeのliveそのものですよね。

ただ人気のliveでは、視聴者の意見が多すぎてとても生主は全ての意見を聞く事は出来ませんね。だからまだグーテンベルグの銀河系で予測されていたほど双方向性ではありません。

それであくまでグーテンベルグの銀河系の予測が正しいと言う前提で考察すると次世代の動画サイトは以下の様になるんじゃないでしょうか?

  • コメントを書く一般視聴者側もレベルによって色分けされ、超人気生主のLiveにコメントを書くためには、最高レベルになった人だけがコメント出来る。
  • 低レベルの視聴者は、超人気生主のLiveは見るだけ。ただし一般人とほとんど変わらない人気のない生主には低レベルの視聴者でもコメントを書く事が出来る。
  • 視聴者はコメントを書いて評価される事でレベルを上げる事が出来る。書かれたコメントの評価は他の視聴者が行う。
  • 今のスパチャは、低レベルの視聴者が特別に超人気生主のLiveにコメントするために使用される。

こうなる事で、人気のliveでも生主と視聴者の双方向性が確立出来ますし、人気のない生主のliveでも視聴者の双方向性が確立出来ます。

こういうシステムを持つ動画サイトはまだ誰も作成していませんね。ひょっとしたら一攫千金のビジネスになるかもしれません。誰かが出資してくれるなら自分で作ってみてもいいかなと思います。

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

<本文>

今週は以下の事をやって行きます。

  • Hierarchical Instanced Static Meshを使用して戦闘システムのマップを改良する

それぞれの戦闘シーンでも直しを加えます。

  • 戦闘マップへの移動->キーボードのIを押したら、戦闘マップに移動するのではなく、徘徊するモンスターに捕まったら戦闘マップに移動するようにする。

こんな感じでやっていきます。

. Hierarchical Instanced Static Meshを使用して戦闘システムのマップを改良する

先週、作成したHierarchical Instanced Static Meshの実装を適用して骸骨の星を浮かべます。

f:id:kazuhironagai77:20201129201044p:plain

f:id:kazuhironagai77:20201129201052p:plain

全体的に暗いのでGoodSkyの設定を昼にしました。

後、UE4.24では、Hierarchical Instanced Static Meshに自転を追加するのにMark Render State Dirtyをチェックする必要がありました。

f:id:kazuhironagai77:20201129201115p:plain

UE4.26と全く同じ実装をしたのにHierarchical Instanced Static Meshが全く自転しないのでかなり悩みました。1時間位費やした上に正直クタクタになりました。

後、今のHierarchical Instanced Static Meshの実装方法が正しいのかもうちょっと確認した方がいい気がしてきました。

後でもう一回勉強します。

2. 戦闘シーンの直し

2.1 戦闘マップへの移動

モンスターに捕まったら戦闘画面に移動するようにします。

今週は動けば良い作戦で以下の様に実装してみました。

MonsterBPにboxを追加します。

f:id:kazuhironagai77:20201129201159p:plain

RPGGameModeBaseBPクラスにEvent Dispatchers、CombatBeginを作成します。

f:id:kazuhironagai77:20201129201216p:plain

このEvent DispatcherをMonsterBPとLevelBPからcallしたりbindしたりする事でMonsterBPとLevelBPの間で連絡を取り合います。

MonsterBP内でBoxにプレイヤーが操作するキャラが侵入したら、RPGGameModeBaseBPのEvent Dispatchers、CombatBeginをCallします。

f:id:kazuhironagai77:20201129201241p:plain

今度は、LevelBP内のEventBeginPlay()関数にRPGGameModeBaseBPのEvent Dispatchers、CombatBeginとEvent CombatBeginsをbindします。

f:id:kazuhironagai77:20201129201257p:plain

EventCombatBeginsの実装は、前回作成した戦闘マップに移行するための実装と同じです。

f:id:kazuhironagai77:20201129201315p:plain

テストします。

モンスターに捕まると

f:id:kazuhironagai77:20201129201329p:plain

一瞬で戦闘マップに移動しました。

f:id:kazuhironagai77:20201129201345p:plain

最初は、UE4C++のRPGGameModeBaseクラスのenum、EPlaceForEventsにPE_MonsterAttackedを追加して

f:id:kazuhironagai77:20201129201400p:plain

他のNPCのeventと同じように作成しようとしたのですが、上記のeventはユーザーがeventに参加するかどうかの選択があるのに対して、モンスターに襲われる場合は、ユーザーには拒否権がないので、別な方法で作成しました。

この実装方法がbestではないかもしれませんが、動く事は動くので今週はこれでいきます。来週以降、別なもっと良いやり方を思いついたら変更します。

2.2 新しくマップが開かれるごとにカーソルが表示される問題について

カーソルはウィジェットが開かれた時だけ表示するようにしたいです。逆にウィジェットが開かれた時は、必ずカーソルが表示されるようにしたいです。

Set Input Mode Game And UIノードのIn Mouse Lock Modeについて調べる事でこの問題、解決出来ないかと思っています。

f:id:kazuhironagai77:20201129201438p:plain

因みに最初のスタート画面から

f:id:kazuhironagai77:20201129201454p:plain

「新しく始める」をクリックしてMap1に移動する時は、カーソルは表示されません。

「新しく始める」をクリックして発動されるEventの実装には、以下のノードが使用されていました。

f:id:kazuhironagai77:20201129201513p:plain

f:id:kazuhironagai77:20201129201521p:plain

f:id:kazuhironagai77:20201129201528p:plain

まず、SetInputModeについて調べます。

このノード昔、一回勉強したのですが、今一良く分からなかったんです。今回はきちんと理解したいです。

このビデオに詳しい説明がありました。

所で、ビデオを見ている間に気が付いたのですが、ゲームが完成したらPlay画面にも何らかのUIは表示されるようになるはずです。ので常にカーソルが表示されている方が便利な気がしてきました。さらにPCでゲームをする時に同時にネットで調べものをしたり、友達とチャットしたりする必要もあるはずで、カーソルはそういう意味でも必ず表示すべきでした。

SetInputModeについて簡単にまとめておきます。

公式のサイトか上記のビデオに書かれている事以外について分かった事です。

f:id:kazuhironagai77:20201129201547p:plain

SetInputModeGameOnlyですが、SetInputModeGameAndUIとSetInputModeUIOnlyから推測して、UIへのinputが出来なくなると思いますがそれが出来ます。

このサイトの解説によると、

f:id:kazuhironagai77:20201129201610p:plain

と書かれていました。要するにUIを使用不能にするためにSetInputModeGameOnlyは使えないと言う事ですね。

しかし、この人が解答してくれるまで別な人が訳分からない事を言っていますが、自分が分かってないのに質問に答えていますよね。

もう一つ、これは日本語のサイトで見つけたのですがSetInputModeUIOnlyをキャラが走っている状態で使用するとUIが表示された後もそのキャラが走り続けるらしいです。

試してみます。

f:id:kazuhironagai77:20201129201642p:plain

走り続けています。一端UIを開いたら止められません。凄いですね。こんなの全く気が付きませんでした。

2.2.1 SetInputModeのまとめ

SetInputModeはカーソルの表示とは関係ないと言う事は分かりました。

2.2.2 Set Game Pausedについても調べます。

このビデオに知りたい事はほとんど説明されていました。

ただ一つ分からないのはUIからのInputはGame Paused中でも受け付けるのは分かりましたが、何はpauseされて何がpauseされないのかちょっと不明ですね。

Pause画面を開く時は、このSet Game Pausedをオンにすべきなのかどうか?それが問題ですね。

後でこの問題については考えます。

2.3 ゲームプレイ中は、カーソルは必ず表示する

はい。これで行きます。全部直します。

2.3.1スタート画面

これでカーソルは何時でも表示されるはずです。

f:id:kazuhironagai77:20201129201811p:plain

スクリーンショットにはカーソルは写りませんでしたが、最初から表示されました。更にplay画面を一回クリックしてもカーソルが消える事はありません。

問題も見つかりました。プレイヤーの操作するキャラがこの時点で既に操作出来ます。

f:id:kazuhironagai77:20201129201835p:plain

キャラがどっかに行ってしまいました。これは後で直します。

良く考えたら、cursorが表示していない時だけcursorを表示しろと命令するはずなので、以下の実装に変更しました。

f:id:kazuhironagai77:20201129201903p:plain

これは色々なマップから呼び出されるのでBPFunctionにShowMouseCursorifNot()関数として作成しました。

f:id:kazuhironagai77:20201129201940p:plain

こんな感じに実装し直しました。

f:id:kazuhironagai77:20201129202005p:plain

テストします。

cursorはスクリーンショットに写りませんがキチンと表示されていました。一回クリックしてもcursorは消えませんでした。

2.3.2 その他のマップやwidget

Map1の開始時にもCursorが表示されるようにしました。

f:id:kazuhironagai77:20201129202029p:plain

Map2やMap3も同じようにしました。

Pause画面が閉じた後もcursorが消えないようにしました。

NPCとの会話後もcursorが消えないようにしました。

全員と会話してcursorが消えてない事を確認しました。

f:id:kazuhironagai77:20201129202049p:plain

半分くらいのNPCは会話が可能な状態でも(!!)マークが表示されていませんでした。

f:id:kazuhironagai77:20201129202110p:plain

f:id:kazuhironagai77:20201129202120p:plain

後で直します。

Shopから出る時もcursorが消えないように変更します。

道具屋、武器屋、宿屋から出た時もcursorが消えない様にしました。

Narrationが表示される時とitemを拾う時も直します。

直しました。

これで大体全部直したはずです。

確認のためにShow mouse cursor nodeを使用している箇所を検索してみます。

f:id:kazuhironagai77:20201129202142p:plain

うわ。全然直し切っていませんでした。

最初のShow mouse cursorですが、ThirdPersonCharacterクラス内でkeyboardのMを押すと地図を開くように実装されている箇所でした。

f:id:kazuhironagai77:20201129202208p:plain

しかしMap1のLevelBPで

f:id:kazuhironagai77:20201129202230p:plain

keyboardのMを押すと魔法を習得するように実装したため、既に機能していません。

このような現在使用していない機能を実装した箇所が結構沢山残っている様です。それの整理をする必要がありますね。これも後でやります。

2.3.3 キャラの視点をマウスで操作する時にカーソルが消える時と消えない時がある

視点を操作する時だけ、カーソルが消える場合と消えない場合があります。カーソルが消えている時の方が視点がスムーズに動きます。視点を操作する時はカーソルが表示されないようにします。

これこそSet Input Modeの問題でしょう。

確認のためTestGameModeプロジェクトで試してみます。

まずはcursorだけ表示してみます。

f:id:kazuhironagai77:20201129202253p:plain

Screenshotには撮れないですがcursorが映っています。カメラの視点に合わせてcursorが動きます。大変見にくいです。

SetInputModeGameAndUIをセットします。

f:id:kazuhironagai77:20201129202314p:plain

InWidgettoFocusは開いているwidgetがないので無視します。

テストします。

Screenshotには撮れないですがcursorが映っています。カメラの視点に合わせてマウスを動かす時はcursorが消えます。大変見やすいです。

はい。確認とれました。

SetInputModeGameAndUIを使用すればこの問題は解決します。

2.3.4 キャラの視点をマウスで操作する時にカーソルを消す。

ShowMouseCursorIfNot()関数にSetInputModeGameAndUIを追加しました。

f:id:kazuhironagai77:20201129202347p:plain

ここでもInWidtettoFocusには何もセットしていません。

テストします。Map1を開きます。

Screenshotには撮れないですがcursorが映っています。カメラの視点に合わせてマウスを動かす時はcursorが消えます。

出来ました。

3. まとめと感想

もう精も根も尽きました。今週はこれでお終いです。

BPで実装するのは思っていたより複雑な事が出来る事が分かりました。プロのプログラマーからはあまり人気のないVisual programming languageであるBPですが、本格的に使用してみるとかなり面白いです。

普通のプログラミングを文章を書く事に例えるなら、Visual programming languageはブロックを組み立てて何かを作成する感じに似ています。

ただBPの問題点も同時に分かりました。カプセル化のやり過ぎで中身がどうやって実装しているのか全く分かりません。UE4C++ならばLibraryの関数を使用する時でも、その関数のコードを読む事でどんな事が起きているのか大体は理解出来ましたが、BPは完全なブラックボックスです。

例えばあるmeshにAddRotationノードを使用した後でAddTransformノードを使用した場合と、AddTransformノードを使用した後でAddRotationノードを使用した場合は、3次元における移動、回転の行列に素直に従うならば全く違う結果になるはずなのですが、UE4BPでは同じ結果になります(100%断言は出来ませんが、少なくとも私が先週と今週試した限りではそうなりました。)。この辺は素直にmeshの行列の計算結果を見せてほしいと思いました。

仕方がないので、そのmeshに親meshを追加して望みの回転と移動を追加しましたが、この方法で回転させるとGimbal lockが発生して折角quaternionで計算している意味が無くなるんじゃないと思いました。

以上です。