UE4の勉強記録

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

「Unreal Engine 4.xを使用してRPGを作成する」の足りない部分を作成する 教科書のサンプルをもう一度作成する3

f:id:kazuhironagai77:20200726221920p:plain

<前文>

UE4でゲームを作るための予備知識はどれくらい必要なのか?

そろそろUE4の勉強記録用のブログを始めて2年半が経ちます。私なりにUE4でゲームを制作するためどれぐらいの勉強が必要なのかとか、その前提としてどれくらいの知識があればUE4を勉強する事が可能なのかが分かって来ましたのでここにまとめようと思います。

まず、私が分かった中で非常に大切な事が、UE4の使用方法を理解する事とUE4を使用してゲームを作成する事は違うと言う事です。車の運転ならば、操作の仕方を覚えるのと路上で運転する事にそんなに違いはありません。しかしUE4は使用方法を覚えるのと実際にUE4を使用してゲームを作成する事には大きな違いがあります。UE4の使用方法を理解する事は割かし簡単で誰でも覚えられます。これは市販されているUE4の教科書を1,2冊勉強すればUE4C++は無理としてもBPとそれぞれの機能の使い方を覚える事は出来るはずです。しかしそれからどうやって自分が作りたいゲームを作成するのかが全く分からない状態になってしまいます。

結論から言えばC++C#のようなオブジェクト指向高級言語で、一からゲームを作れる能力がある人だけがUE4を使用する事でゲームを作成出来ると言う事です。UE4は結局は凄いLibraryでゲームをより速くより良く作る助けには成っても、元々コンピューターゲームを一から作成出来ない人が出来る様になる魔法の道具ではないと言う事です。

更に、数学と英語の問題もあります。仮想空間で3Dのオブジェクトを扱うには厳密に言えばlinear algebraの知識が必要です。UE4ではこれらの行列の計算はBPではノードの関数が行ってくれますが、ちょっと複雑になった場合、本当にこれらの数学の知識なしに望んだ結果が達成出来るのか疑問です。更にエラーが起きた時に解決方法を探す時など英語圏の情報を当たる必要もあり英語の能力もかなり要求されます。

これらから考えると、

1.英語圏の大学のcomputer scienceやcomputer engineering もしくはsoftware engineering の学士以上の学位を持つ人、

2.日本のトップレベルの大学(東大クラス)の情報科の学士以上の学位を持つ人(帰国子女であるとなお望ましい)、

3.日本の中堅レベルでしっかり教育するので有名な大学を優れた成績で卒業した後、理系の修士以上の学位を持ち、更にプログラミングを独自に勉強した人

もしくはそれと同等の非常に高い学力を持っている人だけが、UE4を使用してゲームの作成が出来ると言わざる得ません。かなり専門性の高いツールに当たると思います。

決してUE4を使用すればプラモデルを作成するようにゲームが作成出来る訳ではないと言う事です。

この辺をUE4でゲームの作成方法を教える教材は隠しています。まるで誰でもUE4を使用すればゲームが作れるように歌っています。これははっきり言って私は詐欺だと思います。誰でも出来るのはUE4の使い方を覚える所までです。それ以上は極一部の人だけが先に進めます。

その上でUE4でゲームを制作するためどれぐらいの勉強が必要なのかですが、アセットは全て購入する前提ですが、BPで作成するならば半年位だと思います。

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

<本文>

先週の続きをやって行きます。本来ならば1週間で教科書の内容は全部終わらせるつもりだったのですが、既に3週目です。今週中には終わらせたいです。

1. レベルアップ、アビリティそしてセーブ

1.1 経験値とレベル上げのためのコード

教科書では、CharacterClassInfoクラスにMXPとXP変数を追加しています。私のゲームではCharacterClassInfoクラスはYourHeroClassInfoクラスとEnemyMonsterInfoクラスに分けて作成されているのでそれぞれのケースで考えます。まずYourHeroClassInfoクラスの場合は、MXPもXPも要りません。最初のXPは0ですし、XPがHPやMPのように最大値から減る事もないからです。EnemyMonsterInfoクラスはそのモンスターを倒した時に得られるXPを決めるためにXP変数のみが必要になります。

そしてそれらの変数は以下に示したように既に作成されています。

f:id:kazuhironagai77:20200726222048p:plain

次にLVを表す変数ですが、これもYourHeroClassInfoクラスとEnemyMonsterInfoクラスには必要ないです。勿論、GameCharacterクラスで味方のキャラを作成する場合、以下に示すように

f:id:kazuhironagai77:20200726222110p:plain

LV変数を作成しますが、その値はキャラの作成時は常に1ですし、LVがMPやHPのように下がる事もありません。のでXPと同じ扱いで良いはずです。

既にGameCharacterクラスでもこれらの変数は追加されているのでここで新しく作成する必要はないです。

f:id:kazuhironagai77:20200726222131p:plain

f:id:kazuhironagai77:20200726222141p:plain

次にXPの計算をCombatEngineに追加します。

f:id:kazuhironagai77:20200726222208p:plain

ここは教科書とはかなりやり方が違いますが、私のゲームでは敵のモンスターは常に一体なのでこれでいいはずです。

この後、XPがいくつになったらLVが上がるのかについて考えなければなりません。しかし先にテストをします。

以下に示したようにプレイヤーが操作するキャラのXPをGを押す事で表示出来るようにします。

f:id:kazuhironagai77:20200726222228p:plain

ゴブリンとの戦闘後にGをおしてXPを確認すると

f:id:kazuhironagai77:20200726222245p:plain

と表示されます。

以下に示したように、ゴブリンのXPは50なので合っています。

f:id:kazuhironagai77:20200726222304p:plain

レベルアップなのですが、教科書では単にMXPを超えるとLVが上がる様に成っています。これは余りにも単純で作り直します。

まずTableRowBaseでsoldierのレベルアップ表を作るためのLevelDataを作成します。名前はLevelUpDataとします。

f:id:kazuhironagai77:20200726222322p:plain

ここで又、ULevelUpDataのままでビルドしてエラーになり慌てました。いつもこの部分を直す事を忘れてしまいます。

UE4エディターがクラッシュして再起動する処も同じです。

パラメーターは以下のようにしました。

f:id:kazuhironagai77:20200726222402p:plain

XPは次のレベルに必要なXPの値を表します。LVはそのままレベルを表します。MHPはそのレベルになった時に追加されるMHPの値を示しています。後に続くMMPなどのパラメーターも同じです。

f:id:kazuhironagai77:20200726222424p:plain

ここまで作成して気が付きましたがレベルアップした時に覚える魔法の欄がありませんでした。

作り直します。

f:id:kazuhironagai77:20200726222451p:plain

これを足しました。

うーん。そうすると今度はGameCharacterクラスにも使用出来る魔法の名前を保持する変数が必要になりますね。ただ今週は教科書の内容を終わらせるのが最優先なので、この問題は後で考える事にします。

まずはレベル挙げのためのコードを実装します。

f:id:kazuhironagai77:20200726222522p:plain

簡単に解説するとSoldierLevelUpのRowNameをLVと同じにする事でCharacterのLVからSoldierLevelUpのrowを呼び出せるようにしました。

f:id:kazuhironagai77:20200726222542p:plain

呼び足した後は、経験値が次のレベルに上がるのに十分かどうかチェックします。そしてレベルが上がる場合はそれぞれのパラメーターも上がります。データでは簡単にするために全部1上がるようにしました。

正しレベルの上限は10までで10以上は上がらないようにしました。

後は、経験値を大量に得てレベルが沢山上がる場合にも対応しました。

テスト結果も簡単に紹介します。

ゴブリンのXPを100に変更して一回だけ戦闘しました。レベルは3、MHPは102、MMPは2になるはずです。試しにPause画面を開いて見ると

f:id:kazuhironagai77:20200726222619p:plain

レベルはまだ表示出来るようにしていませんでした。が他の値は正しいのが確認出来ます。

このようなテストを何通りも行いましたが全部予測した結果になりました。

1.2 DataTableの初期値

この部分は散々既に作成しているのでスキップします。

1.3 レベルと経験値の表示

教科書を見ると以下のように表示されています。

f:id:kazuhironagai77:20200726222649p:plain

次のレベルを調べるのは結構大変なので、それ以外を表示させます。データの保存の仕方が既に教科書とは大分違うので自分で作成します。

f:id:kazuhironagai77:20200726222723p:plain

普通に作成しました。結果は以下に示しました。

f:id:kazuhironagai77:20200726222741p:plain

テストはまあ大丈夫でしょう。

1.4 戦闘で正確なダメ―ジを与える

今までは、戦闘では一律、10ポイントのダメ―ジを与えていましたが、それを正確なダメージを与える様にします。

f:id:kazuhironagai77:20200726222805p:plain

と言っても変更したのは、TestCombatActionクラスのBeginExecuteAction()関数のこの部分だけです。

一応テストはします。

うん。正常に動いているみたいです。

1.5 アビリティをセットします。

アビリティ自体を無くしてしまったのでこの部分と次の節は読むだけにします。

1.6 セーブとロード

この部分も自分で作成し直したいので後にします。

一応、これで教科書の内容が終わりました。

2. 直す部分のまとめ

3週間に渡って教科書の内容をch4_3に追加しました。その際に結構な数の問題が出て来ましたが後で直す事にしました。その後で直す箇所をまとめ直します。

先々週の部分

  • 戦闘中はPause出来ないようにする。
  • 教科書ではプレイヤーのキャラの状態値を保持する変数の名前をTargetCharacterと名付けているので、後になると何を指しているのか分かりづらいです。TargetCharacterが指している値はRPGGameInstanceクラスのYourMyHero変数なのでTargetCharacterYourMyHeroに変更します。
  • モデルの入れ替え
  • 教科書ではUE4C++PRGGameInstanceクラスにBoolean変数であるTalkShopを作成し、NPCShopOwnerBoxPlayerの操作するキャラがOverlapしたらTalkShop変数がTrueに成るように作成します。そしてTalkShopTrueの時にEを押すとNPCとの会話が出来るようになっています。何で敢えてUE4C++Boolean変数を作成する必要があるのかが不明ですが、更にその変数の管理をGameInstanceクラスに任せるのは更に不明です。このBoolean変数をどこで管理するかをしっかり考察します。
  • NPCbox内にプレイヤーが操作するキャラがいると、Eを押すとHelloが表示されます。この部分の実装をLevelBP内でしています。別なBPで実装した方がいい気がします。これを考察します。
  • お金の管理をRPGGameInstanceクラスにさせるのか、それともGameCharacterクラスにさせるのか?

先週の部分

  • アイテムを使用した時にHPしか影響されない。
  • 使用したアイテムが消滅しない。
  • 武器を装備した時のATKと外した時のATKの違いが分からない
  • 武器を選んでも防具を選んでも武器に装備される

今日の部分

  • GameCharacterクラスに使用可能な魔法の名前を保持するための変数を作成する。
  • セーブとロード機能の追加

以上です。

3. 直す

3.1 セーブの作成

SaveGameから新しいブループリントNewSaveGameを作成します。

f:id:kazuhironagai77:20200726222935p:plain

ここにRPGGameInstanceクラスの変数を作成します。

f:id:kazuhironagai77:20200726222954p:plain

これをPauseMainで

f:id:kazuhironagai77:20200726223012p:plain

とする事でセーブします。

3.2 ロードの作成

Start_Menuウィジェットを作成します。

f:id:kazuhironagai77:20200726223039p:plain

このLoadボタンを押した時にセーブしたデータをロードするようにします。

f:id:kazuhironagai77:20200726223107p:plain

どうやらGameInstanceは直接コピーする事は出来ないみたいですね。変数一個ずつコピーするしかないみたいです。

f:id:kazuhironagai77:20200726223133p:plain

ああ…。RPGGameInstanceの変数のほとんどはBPからいじれない設定にしていました。

これは、UE4C++から作成する方が良いですね。

ここにUE4C++からsaveGameを利用してデータをセーブしたりロードしたりする方法を説明した詳しいチュートリアルがありました。これを元にして作成します。

まず、SaveGameをPrivateで作成します。

f:id:kazuhironagai77:20200726223155p:plain

多分privateで大丈夫でしょう。

f:id:kazuhironagai77:20200726223211p:plain

f:id:kazuhironagai77:20200726223219p:plain

で、色々試したんですが、RPGGameInstanceそのものをセーブしても、shallow copyみたいな状態になってRPGGameInstanceのそれぞれのオブジェクトが持つ変数の値まで保持してくれないみたいで、仕方ないのでセーブしたい変数の値は全てここに作成する事にしました。

取りあえず、GameGoldで試します。

f:id:kazuhironagai77:20200726223252p:plain

f:id:kazuhironagai77:20200726223300p:plain

f:id:kazuhironagai77:20200726223307p:plain

f:id:kazuhironagai77:20200726223318p:plain

これでセーブとロードが出来るはずです。
試してみます。
2回戦闘してGoldを20貯めました。

f:id:kazuhironagai77:20200726223339p:plain

セーブしました。ゲームを一回終了します。

もう一度ゲームを開始してLoadを選択します。

f:id:kazuhironagai77:20200726223356p:plain

Pauseを開くとGOLDが20になっていました。

f:id:kazuhironagai77:20200726223413p:plain

今度は、NewGameをクリックします。

Pauseを開くとGOLDは0のままです。

f:id:kazuhironagai77:20200726223429p:plain

出来てますね。

追記* GameInstanceクラスの変数や関数を追加した時にGameInstanceBPを作り直す必要がありました。これをしないとエラーになりました

残りはアイテムや武具を保持した状態になってからじゃないと作成出来ないのでここで中止して後でやります。

3.3 GameCharacterクラスに使用可能な魔法の名前を保持するための変数を作成する。

追加しました。

f:id:kazuhironagai77:20200726223504p:plain

レベルが上がった時は以下に示した方法で魔法を追加します。

f:id:kazuhironagai77:20200726223532p:plain

テストします。
以下の方法で、Magicsに保存されている魔法を表示します。

f:id:kazuhironagai77:20200726223552p:plain

因みに、SoldierLevelUpのデータを以下のように変更したのでLv.2ではSmallFire、Lv.3ではBigFireを覚えるはずです。

f:id:kazuhironagai77:20200726223609p:plain

Lv.3の時にSmallFireとBigFireを覚えているのが確認出来ました。

f:id:kazuhironagai77:20200726223629p:plain

3.4 アイテムを使用した時にHPしか影響されない

ItemウィジェットのBPを見たら、MPが上昇する場合を追加すれば良い事が分かりました。

f:id:kazuhironagai77:20200726223654p:plain

のでこんな感じで作成しました。

テストします。

MPが10/50の状態でイーサーを使用します。

f:id:kazuhironagai77:20200726223714p:plain

MPが30/50に成りました。さらに何回もイーサーを使用します。

f:id:kazuhironagai77:20200726223734p:plain

MPが50/50になったらMPの値はそれ以上増えなくなりました。

f:id:kazuhironagai77:20200726223755p:plain

出来ていますね。

3.5 使用したアイテムが消滅しない

Itemウィジェットの最後に以下のコードを追加しました。

f:id:kazuhironagai77:20200726223822p:plain

購入したアイテムの管理をRPGGameInstanceクラスで管理しているとずっと思っていたので、購入したアイテムが消せず凄い苦労しました。後でThirdPersonCharacterクラスで管理している変数はGameInstanceクラスに移します。

テスト結果です。

f:id:kazuhironagai77:20200726224048p:plain

回復薬を使用します。

f:id:kazuhironagai77:20200726224110p:plain

回復薬が消えました。

一度この画面を出て入り直します。

f:id:kazuhironagai77:20200726224130p:plain

回復薬が消費されてイーサーのみが残っている状態になっています。成功です。

3.6 武器を装備した時のATKと外した時のATKの違いが分からない

この問題と次の「武器を選んでも防具を選んでも武器に装備される。」は来週から始める「自分で改良した機能を追加する。」でしっかりやるのでここはパスします。

3.7  戦闘中はPause出来ないようにする

現状、戦闘の時はどうなっているのか確かめます。

f:id:kazuhironagai77:20200726224202p:plain

今のままでも戦闘中はpauseは出来ませんでした。

3.8 TargetCharacterをYourMyHeroに変更します

直しました。

3.9 モデルの入れ替え

来週以降やります。

3.10 UE4C++にBoolean変数であるTalkShopを作成する必要があるのか、更にその変数の管理をGameInstanceクラスに任せる事についての考察

TalkShopはプレイヤーの操作するキャラが店員と会話できるくらい近い位置にいる事を証明するためだけの変数で、店員の数が増える事やそれぞれのレベルに別々に存在している事を考えると、RPGGameModeBaseBPで管理した方がいい気がします。しかしもっと大切な事は店員との会話を一括で管理するシステムを構築してそのシステムを利用してそれぞれの店員の会話を管理する事です。このシステムを構築する事で沢山の店を一括で管理できるからです。

更に、将来的には村や町の住人も作成します。沢山のNPCそれぞれにBoolean変数をつけて会話開始の管理をするのは非効率です。これは次の問題の「 NPCの管理をこの部分の実装をLevelBP内でしています。別なBPで実装した方が良い気がする」とも関連しますが、もしそれぞれのNPCに個別にBoolean変数をつけて会話開始の管理をするならば、それはLevelBPで作成するのもアリと思います。

この辺はRPGにおけるNPCの管理方法についての調査が必要です。沢山のNPCを管理するためのソフトウェアデザインがあるはずです。まずその辺から始めましょう。ただ今週は他にもやる事が沢山あるので、この課題は後で考える事にします。

3.11 お金の管理をRPGGameInstanceクラスにさせるのか、それともGameCharacterクラスにさせるのか?

もうこれは結論が出ました。私のゲームでは主人公が変わったりしませんので、お金がプレイヤーが操作するキャラが変化する事で変わる事はありません。のでRPGGameInstanceクラスに管理させます。

4.まとめと感想

何とか、教科書の内容を追加する事が出来ました。来週からこのプロジェクトに自分で改良した機能を追加します。

「Unreal Engine 4.xを使用してRPGを作成する」の足りない部分を作成する 教科書のサンプルをもう一度作成する2

f:id:kazuhironagai77:20200719225120p:plain

<前文>

GaN半導体

あれ?「中村*二は口先だけの詐欺師で、実際は彼の部下が青色ダイオード作成した。」って日本で散々言ってましたよね。もう日本中のマスコミが彼の事をパッシングして、それまで米国との2重国籍は特に問題視していなかったのに、*民党は彼から無理やり日本国籍取り上げたりしましたよね。この動画、たまたま見たのですが、何か凄い事になっています。近い将来、ほとんどの電子機器でGaNがSiliconにとって代わるんじゃないかって予測してます。そしてその研究の中心人物として紹介されているのが中村*二教授じゃないですか。米国での彼の弟子は、他の大学の教授になってGaNの研究で世界をリードする立場に立っているじゃないですか。

シリコンバレーがITの分野で世界的な存在になったのは別に優れたプログラマーが集まったからじゃないです。Siliconという安価な素材を使って半導体が作れるようになったからですよ。そのGaNがSiliconに代わるとなると、GaNが日本にもたらすはずだった富は、GoogleApple, Facebook そしてMicrosoft時価総額を合わせた分より大きくなるんじゃないんでしょうか?

確か、彼が起こした裁判で、彼の青色ダイオードにおける貢献は3億円程度と判決が出たと思うんですが、本当にその程度なんですか?3兆円の間違いじゃないんでしょうか?こういう問題って、日本ではその場、その場で終りにしてしまうけど後からでも詳しく検討すべきだと思うんですよ。

後、アメリカ国籍を持っている人は海外に在住してもアメリカに税金払わないといけないんです。(ただしある一定以下の収入の人に限ってそれを証明する書類を提出する事で免除されはします。)何が言いたいのかと言うと「知らないけどアメリカ国籍持ってた。」と言う事は絶対ないと言う事です。*民党は、中村*二氏から無理やり日本国籍取り上げたくせに、議員の中に米国との2重国籍な人はいませんよね。と言う事ですよ。

人種差別的な悪口をアメリカで言うと

日本から海外に出る気がない人には関係ない話かもしれませんが、アメリカで勉強や仕事をしたいと思って英語の勉強をしている人は絶対知っていた方が良い話をしますが、人種差別的な悪口、いわゆるNワードを言って喧嘩になった場合、警察は出て来ませんよ。これは黒人だけじゃなくて日本人に*apと言ってもです。私が住んでいた州は、喧嘩で胸倉掴んだくらいでも、警察に見つかったら即逮捕なくらい厳しいのに、人種差別的な悪口を言っていたと分かると、警官たちは殴られていても無視してました。

今、日本でもBLM運動に反対している人達は軽率に人種差別的な言葉をネットに書いていますが、その言葉の重さを知らないで真似ると大変な事になります。ここで特に気を付けてほしいのがall lives matterのような一見差別用語に思えない差別用語です。

突然ですが、以下に示す英文の意味分かりますか?

f:id:kazuhironagai77:20200719225324p:plain

最近The Political Compassと言う自分の政治的な立ち位置を測るテストをやったのですが、この英文が質問として出ていました。

因みにDeepLで翻訳すると以下のようになりました。

f:id:kazuhironagai77:20200719225353p:plain

意味分かんないですよね。何で意味が分からないかと言うと、人は一種類しかいないのに色々な種類の人と訳されているからです。これって色々な職業じゃねぇ。と日本人なら思うかもしれません。

全ての人には権利があるが、色々な職業の人はそれぞれの職業に留まっていた方が皆のためになる。

これなら理解出来ますよね。「タクシーの運転手は、国会議員に成る権利はあるけれどずっとタクシーの運転手をしてる方が皆が幸せになる。」と言う事です。これに対して賛成か反対かを述べる事で、自分の政治的な立ち位置が分かるわけですから、何か納得出来ますよね。

でも違ったんです。正直に言うと私も分かりませんでしたが、このテストを受けた保守派の論客を左派の論客が批判したYouTubeのビデオを見て分かったのですが、この質問は、

黒人(アジア人)が白人と結婚する権利はあるけど、結婚しないほうがお互いのためだよね。

と言う意味だったんです。つまりこの質問は被験者の人種差別度を測る質問だったんです。アメリカでは人種差別問題はこれぐらい曖昧にさせないと議論出来ないんです。だからall lives matterのような一見差別用語に思えない言葉でも差別用語な場合があるんです。

更にNワードと全く同じに聞こえる日本語もあります。「逃げろ!」がNワード+runに聞こえるのは有名な話ですが、他にもいっぱいあります。人種差別的な悪口を言ったつもりがなくても言った事にされる可能性まであるんです。

アメリカで勉強や仕事をしたいと思って英語の勉強をしている人達は本当に人種差別に関しては気を付けてください。今までの努力が一発で水の泡になる可能性があるからです。特に差別用語に関しては、日本人にはどんなに気を付けても気を付け過ぎる事はありません。

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

<本文>

今週は、先週終わらなかった教科書の内容をch4_3に行います。

1.アイテムが購入出来る店の追加と購入したアイテムが使用出来るようにする

この節でInventory populationと言う言葉が出て来ているのですが、前回読んだときはよく意味が分からないので飛ばして読んでいました。更に以下に示した文では、dynamically populated inventory screenと言う表現を使用しています。

f:id:kazuhironagai77:20200719225608p:plain

この場合のdynamically populated inventory screenはch4_3ではまだ作成していませんが、ch2では既に作成した

f:id:kazuhironagai77:20200719225638p:plain

この画面のScrolling boxを指しているはずです。

となるとこの場合のpopulatedはItemボタンを擬人化してItemボタンがこのScrolling box内に居住 (populated)しています。と言う事を言っているみたいですね。

populated areaと言えば人口密集地の事です。すし詰めのニュアンスもあるかもしれません。

これらを踏まえてInventory populationの意味を考察すると、Itemボタンがinventory画面(この場合はScrolling box)にどんどん移住してすし詰めになって行く様を表していると思われます。

1.1 Boolean変数をThirdPersonCharacter内に作成する

作りました。

f:id:kazuhironagai77:20200719225710p:plain

教科書に載っている図が間違っていますね。

f:id:kazuhironagai77:20200719225727p:plain

何でGetDataTableRow()関数を使用している図がここに載っているんでしょうか?

1.2 Inventory Screenが開いているかどうかを確認する

はい。教科書通りに作成しました。

f:id:kazuhironagai77:20200719225812p:plain

ThirdPersonCharacterにアクセスするのに教科書はGetAllActorsOfClass()関数を使用していますが、GetPlayerPawn()関数を使用してもいいと思います。

f:id:kazuhironagai77:20200719225845p:plain

どっちが速いんですかね。

1.2 道具袋内の道具と店に置いてある道具の局所的な違い

何が言いたいのか分かったような分からないような題ですが、やって行きます。

まず、Itemボタンがクリックされた時、道具屋でそのアイテムを購入する時なのが、道具袋を開けてそのアイテムを使用する時なのかの判別が必要です。

以下に示した方法で判別します。

f:id:kazuhironagai77:20200719225919p:plain

この部分も考えどころですね。教科書ではポーズ画面の道具ボタンと道具屋での道具ボタンの両方をItemウィジェットで作成していますが別々にしても何も問題ないです。どちらがユーザーに分かり易く綺麗なデザインでなるかで考えると分けるのもありだと思います。

次にThirdPersonCharacter内にArrayItem変数を作成します。

f:id:kazuhironagai77:20200719225949p:plain

ArrayItem変数はTextの配列で購入したアイテムの名前を保持するための変数です。

しかし既にRPGGameInstance内にItemsと言う名前の変数を全く同じ目的で作成しています。

f:id:kazuhironagai77:20200719230013p:plain

これは、私のゲームはプレイヤーが操作するキャラが違うレベルを移動するため、そのキャラクターの情報をそれぞれのレベル内で維持するために作成された物ですが同じ目的の変数を二つも作成する必要はありませんよね。しかし今週は教科書通りに行い、来週以降どのように改良するのかを考えます。

1.3 道具袋スクリーンを完成させる

しました。

f:id:kazuhironagai77:20200719230038p:plain

1.4 アイテムを購入出来るようにする

以下に示したように大体教科書通りに作成して道具を買えるようにしました。

f:id:kazuhironagai77:20200719230102p:plain

こんな感じです。

f:id:kazuhironagai77:20200719230123p:plain

保持しているアイテムの管理をThirdPersonCharacterで行うのか、RPGGameInstanceで行うのか良く考える必要がありますね。

1.5 アイテムの使用

以下に示したように実装しました。

f:id:kazuhironagai77:20200719230147p:plain

HPのみしか作用するようになっていませんね。全部のパラメーターが作用するように後で変更します。

テストします。

回復薬を使用するとHPが20ほど回復しました。

f:id:kazuhironagai77:20200719230215p:plain

ただし使用した回復薬が無くならないです。これも後で直します。

2.装備

今度は装備の部分を作成します。

2.1 武器防具のデータテーブルの作成

これは既に作成しています。それを使用します。

f:id:kazuhironagai77:20200719230252p:plain

2.2 武器と装備用のスクリーンのための変数の作成

ThirdPersonCharacterにArrayWeaponsとEquipmentScreenを追加します。

f:id:kazuhironagai77:20200719230318p:plain

Pause_EquipmentのBPで以下のコードを実装する事でPause_Equipmentウィジェットが表示されている間のみ、EquipmentScreen変数がTrueになるようにします。

f:id:kazuhironagai77:20200719230348p:plain

2.3 Weaponボタンを作成します。

Itemウィジェットを複製してWeaponと名付けました。

f:id:kazuhironagai77:20200719230417p:plain

装備画面からWeaponボタンが押された場合のコードを以下に示したように変更しました。

f:id:kazuhironagai77:20200719230441p:plain

これだと、元々のATKと武器を装備した後、ATKの変化が分からなくなるため、武器を外した時に困った記憶があります。その辺も来週以降直します。

2.4 装備用のスクリーンの作成パート2

武器装備画面を開いたら、装備出来る武器が全て表示されるような実装をしました。

f:id:kazuhironagai77:20200719230508p:plain

こんな感じです。

f:id:kazuhironagai77:20200719230525p:plain

これ見ると結構、私の前のプロジェクトであるCh2も結構改良していたのが分かります。武器は道具と同じように店で買える様になっていましたから。

2.5 WeapやArmの脇のTextBlockに文字を表示させる

教科書では以下に示したやり方で行っています。

ThirdPersonCharacter内に変数SoldierWeaponを作成します。

f:id:kazuhironagai77:20200719230549p:plain

この変数は装備している武器の名前を保持します。

EquipmentScreenのweapの隣のテキストボックスにSoldierWeapon変数に保持されているテキストが表示されるようにします。

f:id:kazuhironagai77:20200719230614p:plain

Weaponボタンが押された時にSoldierWeapon変数に押されたWeaponボタンの名前が保持されるようになります。

f:id:kazuhironagai77:20200719230633p:plain

短剣(大)を押したらきちんと表示されています。

f:id:kazuhironagai77:20200719230703p:plain

武器を選んでも防具を選んでも同じようにWeapに表示されていますね。この辺も後で直していきます。

2.6 武器を装備した時のキャラの状態値を正す

この節の論理は間違ってはいませんがもっとマシな実装をすべきだと思います。

武器を装備した時、キャラクターのATKの値に直接武器のATKの値を足してしまっているので、

f:id:kazuhironagai77:20200719230737p:plain

武器のボタンを押すたびにAP(ATK)が上昇してしまうバグがあります。

f:id:kazuhironagai77:20200719230754p:plain

もう一度短剣(小)のボタンを押した。

このバグを直すのがこの節の目的です。

そのためにWeapon内のBlueprintでThirdPersonCharacterに作成したSoldierBaseATKの値を調節しているのですがWeaponが作成されるたびにこのコードが実行されます。Pasue_Eqipments画面を開くたびにWeaponボタンは16個(現状の段階でも)作成される訳で、16回も同じ事を繰り返す訳です。武器を装備する時に、SoldierBaseATK + WeaponATK = ATKとセットして、SoldierBaseATKの値はThirdPersonCharacterが作成された時に、RPGGGameInstanceからYourMyHero変数のATKをコピーすればいいはずです。

以下に示した方法で作成しました。

f:id:kazuhironagai77:20200719230821p:plain

まずThirdPersonCharacterのEventBeginPlayでSoldierBaseATKの値にMyYourHeroのATKの値をセットします。

f:id:kazuhironagai77:20200719230858p:plain

WeaponBP内では武器を装備した時にThirdPersonCharacterのSoldierBaseATKと武器のATKを足した値をRPGGGameInstance のYourMyHeroのATKにセットします。

これで完成です。

f:id:kazuhironagai77:20200719230927p:plain

f:id:kazuhironagai77:20200719230939p:plain

f:id:kazuhironagai77:20200719230951p:plain

f:id:kazuhironagai77:20200719231002p:plain

出来ていますね。

3. レベルアップ、アビリティ、そしてセーブ

この部分、2節で終わりと思っていたら6節もあるじゃないですか。ちょっと今週に終わらせるのは無理みたいです。

不本意ですが来週に回します。

4. まとめと感想

今週中には教科書の内容は終わると思ったのですが終わらなかったです。来週頑張ります。

 

「Unreal Engine 4.xを使用してRPGを作成する」の足りない部分を作成する 教科書のサンプルをもう一度作成する

f:id:kazuhironagai77:20200712210833p:plain

<前文>

高齢者ビジネスとコロナ共生時代

スシロー、ハズキルーペ、そしてポケモンGoは意図しているのか偶然かは分かりませんが、高齢者向けの商品を開発して大成功した例と考えています。ハズキルーペポケモンGoはまあ分かるとして何でスシローが高齢者ビジネスなの?と思うかも知れませんが、スシローの寿司は他の回転ずしと比べて小さいんです。歯が悪くなっている高齢者でも食べ易いんです。

ドローン(Drone)、VR、そして機械学習は今から4,5年前にこれから成功すると言われたIT関連の技術です。今これらの技術を見てみるとドローン(drone)は大成功、VRは完全な失敗、機械学習は引き分けですかね。これドローンは高齢者でも操縦したりドローンからの映像を録画したり出来るのに対してVR機械学習は高齢者を全く無視しているんです。特にVRは酔いを無視し過ぎていて体が弱くなった高齢者が使用したら大変な事になる仕様です。

何でこんな事を言っているのかと言うと、これから日本で成功するビジネスは全部、高齢者向けのサービスだと思っているからです。

そしてコロナ共生時代です。コロナによって変化した社会と高齢者の組み合わせがどんなニーズを生み出すのでしょうか?コロナも一部の人が予測したような悲惨な結果には成らなそうですが梅雨が来ても収束していないと言う事は、コロナと共生して生きていかなければならない新しい時代が来た事を示しています。これはこれから社会が大変化する事を示しています。社会が大変化するに従って多くの経済的な敗者を作り出しますが、その引き換えに次の時代の支配階級になる大きな勝者も生み出す事でしょう。

ではIT関連ではどんなビジネスが来るのでしょうか?

現時点でも判明しているのは、コロナ共生時代では在宅勤務は増えると言う事です。これは体力のない高齢者にはありがたい事でもあるので、加速度的に在宅勤務は増えると思われます。そうなるとIOTを使用して自宅に居なくても携帯で〇〇が出来る様な技術よりも自宅に居ながら○○が出来る様な技術が必要になるとかと思います。自宅と自宅でデータのやり取りをするのですから通信の秘密の保証は絶対必要でしょう。更に通信量自体も爆発的に増える事が予測されます。これらに関連した技術を持つビジネスは絶対伸びるでしょうね。

ネットにおける売買も今より更に活発になるでしょう。今、アメリカではGoogleやアップルに取られるアプリの手数料が高すぎるとして、そのアプリを制作した会社が自社のホームページ上で手数料を差し引いた値段で全く同じアプリが買えるようなって来ているそうです。中小企業が楽天やアマゾンに出店して販売するだけでなく、更に自分たちのウェブサイトから直接、商品を販売する事で手数料の分だけ安く販売する形態は日本でも増えそうです。となると物品の売買が出来るwebの制作依頼は増加しそうですね。ただ高齢者が今までオンラインショッピングのやり方で買い物が出来るかどうかかなり疑問でアマゾンのワンクリックみたいな新しい技術が必要になって来るかも知れません。

ゲームも高齢者向けのゲームが主流になるでしょう。それがどんなものか分かりませんが、在宅勤務が主流になる社会では携帯でやるゲームは今ほど盛んにはならないでしょう。

このテーマはまだまだ深堀り出来そうですね。しかし今週はこの位にして勉強を始めましょう。

<本文>

今週は、教科書のサンプルで作成されている機能をch4_3にどんどん追加していきます。

色々考えたんですが、教科書通りにまず作成します。その後で自分で改良した部分を、ブログを見ながら直していきます。この方法が一番速いし簡単だと思います。

1. ポーズメニューの追加

1.1  ポーズメニューの作成

以下に示したように作成しました。

f:id:kazuhironagai77:20200712210930p:plain

教科書でやった事の取りこぼしがないかどうかの確認だけなので、どんどん先に行きます。

1.2 Inventory サブメニューの作成

こんな感じに作成しました。

f:id:kazuhironagai77:20200712210952p:plain

1.3 Equipment サブメニューの作成

Weapon とarmorにborderを使用しています。

f:id:kazuhironagai77:20200712211019p:plain

1.4 Key のバインド

以下に示したコードをThirdPersonCharacterのBPに実装しました。

f:id:kazuhironagai77:20200712211041p:plain

このコードは後で、RPGGameModeBaseBPに移すと思います。更に戦闘中にはPause出来ないような設定も追加します。

1.5  Pause_Mainのボタンに機能を追加する

以下に示したように作成しました。

f:id:kazuhironagai77:20200712211103p:plain

f:id:kazuhironagai77:20200712211111p:plain

f:id:kazuhironagai77:20200712211118p:plain

このやり方だとpause 画面からプレイ画面に戻った時、カーソルが表示されたままですが、良いんでしょうか?

それはともかくとして簡単ですね。眠くなりそうです。

f:id:kazuhironagai77:20200712211137p:plain

やっぱりcursorは消せと書かれていました。消します。

f:id:kazuhironagai77:20200712211155p:plain

テストします。

全部正常に動きました。簡単過ぎるのでスクリーンショットは省略します。

2.ポーズメニューにキャラの状態を表示させる。

教科書見る前に自分で考えてみます。まず以下に示したRPGGameInstanceクラスのMyYourHero変数にアクセスします。

f:id:kazuhironagai77:20200712211220p:plain

BlueprintReadOnlyなのでBPからのアクセスが可能なはずです。

アクセス方法はGetGameInstance -> cast to RPGGameInstanceです。

以下に示したようにGameCharacterクラスの変数、HP、MP、ATK、DEF、そしてXPはBlueprintReadWriteなのでBP側から読む事が出来ます。

f:id:kazuhironagai77:20200712211241p:plain

この値をPause_Mainのキャラの状態値に読み込ませます。

2.1 キャラのデータを得る

以下の方法で表示しました。

f:id:kazuhironagai77:20200712211302p:plain

f:id:kazuhironagai77:20200712211309p:plain

教科書のやり方は私の想像したやり方とほぼ同じでした。一個だけ変更したのはCharacterTarget変数のassign方法だけです。PauseMainウィジェットを作成する時にassignしました。

教科書ではGameInstanceをRPGGameInstanceにcastしています。私はRPGGameInstanceBPにcastしました。

うーん。どっちがいいんでしょうか?

正直、分かりません。今回のケースではどちらでも必要な値にアクセス出来るので問題はないはずです。

2.2  他の状態値も値を表示させる

PauseMainのMP値は以下の方法で値が表示出来るようにします。

f:id:kazuhironagai77:20200712211340p:plain

Pause_Inventoryとpasue_equipmentの状態値も表示されるようにコードを実装します。

結果だけ以下に示します。

f:id:kazuhironagai77:20200712211416p:plain

f:id:kazuhironagai77:20200712211424p:plain

f:id:kazuhironagai77:20200712211436p:plain

教科書ではプレイヤーのキャラの状態値を保持する変数の名前をTargetCharacterと名付けているので、後になると何を指しているのか非常に分かりづらくなります。

TargetCharacterが指している値はRPGGameInstanceクラスのYourMyHero変数なのでTargetCharacterをYourMyHeroに変更します。ただしこれは教科書に書かれている内容を全部終わらしてからやります。

3NPCとセリフ

今度はNPCとそのセリフを作成します。

以下に示す道具屋と武器屋を作成するための土台部分の作成に当たります。

f:id:kazuhironagai77:20200712211513p:plain

どうやって作ったのかもう覚えていませんので、復習を兼ねて教科書に書かれているままに作成していきます。

3.1 NPC Character BPの作成

教科書のままに作成しました。

f:id:kazuhironagai77:20200712211536p:plain

Characterクラスから作成します。

f:id:kazuhironagai77:20200712211553p:plain

Boxを追加します。

f:id:kazuhironagai77:20200712211610p:plain

MeshにSK_MannequinをセットしてAnim ClassにThirdPerson_AnimBPをセットします。

f:id:kazuhironagai77:20200712211627p:plain

f:id:kazuhironagai77:20200712211635p:plain

見た目はかなり変ですが後でモデルは入れ替えるので、今回はこのままで行きます。

f:id:kazuhironagai77:20200712211705p:plain

スケルタルメッシュの設置やアニメーションの追加など、こっちが完全に理解している内容をやっているので滅茶苦茶簡単です。去年はほとんど理解しないでやっていたのであまり大きな口では言えませんが。

3.2 NPC との干渉

教科書ではUE4C++のPRGGameInstanceクラス内にBoolean変数であるTalkShopを作成し、NPCShopOwnerのBoxにPlayerの操作するキャラがOverlapしたらTalkShop変数がTrueに成るように作成します。そしてTalkShopがTrueの時にEを押すとNPCとの会話が出来るようになっています。

何で敢えてUE4C++にBoolean変数を作成する必要があるのかが不明ですが、更にその変数の管理をGameInstanceクラスに任せるのは更に不明です。このBoolean変数をどこで管理するかは後でしっかり考察します。

今週は教科書に書かれているままに作成します。

f:id:kazuhironagai77:20200712211733p:plain

ビルドします。

f:id:kazuhironagai77:20200712211751p:plain

成功しました。

変数一個追加したぐらいで大袈裟かもしれませんが、久しぶりにUE4C++側をいじったのでちょっと緊張しながらやりました。

NPCShopOwnerのBoxにPlayerの操作するキャラがOverlapしたらTalkShop変数がTrueに、Overlapしなくなったらfalseになるように実装します。

f:id:kazuhironagai77:20200712211809p:plain

OverlapしているactorがThirdPersonCharacterでない場合はTalkShopはTrueにはなりません。そんくらいですかね。このコードで重要なのは。

LevelのBP内で以下のコードを実装します。

f:id:kazuhironagai77:20200712211825p:plain

もしNPCのbox内にプレイヤーが操作するキャラがいると、Eを押すとHelloが表示されます。

何故、この部分の実装をLevelBP内でするのでしょうか?別なBPで実装した方がいい気がします。これは後で考察します。

テストします。

f:id:kazuhironagai77:20200712211842p:plain

されました。

f:id:kazuhironagai77:20200712211900p:plain

一応確認のために、NPCのBox外でEを押してみました。この時はHelloは表示されませんでした。

成功ですね。

3.3 セリフ用のボックスの作成

セリフ用のボックスって一体何?と思ったら、これの事でした。

f:id:kazuhironagai77:20200712211940p:plain

それでは作って行きます。

f:id:kazuhironagai77:20200712211956p:plain

NPC_dialogクラスをUserWidgetクラスから作成しました。

NPCDialogを作成しました。

f:id:kazuhironagai77:20200712212014p:plain

NPC_Parentクラスを親クラスとするDialogBoxクラスを作成します。

f:id:kazuhironagai77:20200712212041p:plain

f:id:kazuhironagai77:20200712212053p:plain

ここまで、これから先の実装は次の節でやるそうです。

3.4 Welcomeボックスの作成

Shop_WelcomeウィジェットをDialogBoxを複製して作成します。

f:id:kazuhironagai77:20200712212119p:plain

f:id:kazuhironagai77:20200712212126p:plain

以下に示したようにTextBlock_DialogBox内にセリフが表示されるように実装しました。

f:id:kazuhironagai77:20200712212147p:plain

このNPCのボックス内にプレイヤーが操作するキャラがいる時にEを押した場合、Shop_Welcomeウィジェットが表示されるようにします。

f:id:kazuhironagai77:20200712212222p:plain

テストします。

f:id:kazuhironagai77:20200712212242p:plain

表示はされましたが、一々マウスの動きに合わせて視点が激しく動きます。見にくいです。

余りにも見にくいので、SetGamePausedをTrueで追加しました。

f:id:kazuhironagai77:20200712212322p:plain

更にExitを押した時、

f:id:kazuhironagai77:20200712212345p:plain

GamePausedを解除してMouseのCursorを消しました。

f:id:kazuhironagai77:20200712212429p:plain

大分見やすくなりました。

3.5 NPC会話ボックスを追加します。

Shop_TalkをDialogBoxを複製して作成します。

f:id:kazuhironagai77:20200712212458p:plain

中身は全く一緒です。

f:id:kazuhironagai77:20200712212518p:plain

テキストはNPCDialogの0に保存されている文章を表示します。

f:id:kazuhironagai77:20200712212539p:plain

Shop_welcomeウィジェットTalkをクリックした時にShop_Talkウィジェットが開くようにします。

f:id:kazuhironagai77:20200712212604p:plain

Shop_talkのExitボタンがクリックされた時は以下に示したように実装しました。

f:id:kazuhironagai77:20200712212635p:plain

最後に表示される文字がはみ出さない様にAuto Wrap Textにチェックを入れました。

f:id:kazuhironagai77:20200712212709p:plain

テストします。

Talkをクリックすると以下のウィジェットが表示されました。

f:id:kazuhironagai77:20200712212733p:plain

更にExitをクリックすると

f:id:kazuhironagai77:20200712212752p:plain

普通の画面に戻りました。

3.金貨、アイテムそしてショップ

ショップでアイテムを買えるようにします。

3.1 金貨のインスタンスとセッター、ゲッター

ショップで買い物が出来るためには、最初にお金を作る必要があります。金貨を作成します。

最初にモンスターを倒した時に手に入る金貨を設定するためにEnemyMonsterInfoクラスに変数、Goldを追加します。

f:id:kazuhironagai77:20200712212841p:plain

既に作成されていました。

今度はGameCharacterクラスに変数、Goldを追加します。

f:id:kazuhironagai77:20200712212902p:plain

GameCharacterクラスにはGold変数はないので追加します。

f:id:kazuhironagai77:20200712212918p:plain

念のためにビルドもしましたが、大丈夫でした。

GameCharacterクラスはCH2のGameCharacterクラスを元に作成していると思っていたのですが、何でGold変数を作成していなかったのか覚えていません。Ch4_3 のGameCharacterクラスにはGold変数がないので追加する以外の選択肢はないですが何か気になります。

f:id:kazuhironagai77:20200712213004p:plain

をCreateEnemyMonster()関数に追加します。

次に教科書ではCombatEngineクラス内に敵のモンスター全員の合計の金貨を表す変数、GoldTotalを作成しています。

f:id:kazuhironagai77:20200712213136p:plain

私のゲームでは敵は常に一体なのでこの部分はスキップします。

教科書では更に、保持している金貨の管理をGameInstanceクラスで行います。どうもこの教科書ではキャラクターは敵だけでなく味方も途中で交代する場合を考慮していてそのためにお金の管理はGameInstanceクラスで行うようにしたみたいです。

うーん。私、個人的にはお金の管理はそのキャラに任せるべきと思います。更に私のゲームではキャラは一体のみなので、敢えてGameInstanceクラス内に保持している金貨の管理を行う変数を作成する意味はないです。

取り敢えず教科書通りに作成して後で直します。

RPGGameInstanceクラスにGameGold変数を追加します。

f:id:kazuhironagai77:20200712213203p:plain

RPGGameModeBaseクラスのTick()関数内に以下のコードを追加します。

f:id:kazuhironagai77:20200712213229p:plain

これで戦闘に勝利するたびにRPGGameInstanceクラスの金貨を管理している変数GameGoldの値が増えるはずです。

f:id:kazuhironagai77:20200712213252p:plain

ビルドも成功しました。

今度はこのGameGoldの値をPauseMainウィジェットに表示させます。

f:id:kazuhironagai77:20200712213313p:plain

f:id:kazuhironagai77:20200712213320p:plain

テストします。

f:id:kazuhironagai77:20200712213340p:plain

戦闘に勝利したらGOLDが10増えました。

勿論ゴブリンが保持する金貨は10です。

f:id:kazuhironagai77:20200712213359p:plain

二回戦闘した場合は、金貨の数は20になっています。

f:id:kazuhironagai77:20200712213429p:plain

うん。出来ましたね。

3.2 アイテムのデータ

この部分は既に作成していました。のでスキップします。

3.3 ショップのスクリーンの作成

アイテムを買う時に使用するウィジェットを作成します。

f:id:kazuhironagai77:20200712213521p:plain

Shop_welcomeウィジェットのShopボタンをクリックしたらこのウィジェットが開くようにします。

f:id:kazuhironagai77:20200712213543p:plain

Exitボタンをクリックした時にこのウィジェットが閉じるようにします。

f:id:kazuhironagai77:20200712213602p:plain

当然、GamePausedを解除してMouse cursorを非表示にします。

最後にGOLDの値を表示するようにします。

f:id:kazuhironagai77:20200712213625p:plain

以上です。

テストも成功しました。

3.4 アイテムボタンのフレームワークの作成

最初に作成した時、この節の題であるThe Item button Frameworkの意味が全く分からなかったんですが、この場合のフレームワークとは、アイテム一個一個を表示するために使用するウィジェットの事を指しています。

UE4WidgetBlueprintはWidgetBlueprintからWidgetBlueprintを呼べるためにそう言う事が出来ます。

f:id:kazuhironagai77:20200712213656p:plain

f:id:kazuhironagai77:20200712213705p:plain

このフレームワークではCanvasPanelは使用していませんが、CanvasPanelを使用した方が制約も付きますが、複雑な構造も作成出来ます。

f:id:kazuhironagai77:20200712213727p:plain

教科書の図ではItem変数はarrayのように見えたんですが、arrayにする必要はありませんのでしませんでした。

3.5 アイテムデータのリンク

3.4で作成したウィジェットItemをウィジェットshopのスクロールボックス内に表示されるように実装します。

f:id:kazuhironagai77:20200712213759p:plain

このやり方は散々勉強しました。ここで更に復習する必要はないでしょう。

テストをすると以下に示した図が表示されました。

f:id:kazuhironagai77:20200712213823p:plain

4.まとめと感想

教科書の内容は今週で全部やる予定でしたが、量的にちょっと無理なので来週もやる事に変更しました。今丁度半分終わったところです。

「Unreal Engine 4.xを使用してRPGを作成する」の足りない部分を作成する MyCombatEngineの作成4

f:id:kazuhironagai77:20200705204636p:plain

<前文>

保守派の論客について

と言っても日本の話ではなくてアメリカの話です。私はずっと前から思っていたのですが、Fo〇ニュースなどに代表されるアメリカの保守派の言っている事は突き詰めると「聖書に書かれている事を守れ!」に帰結すると。それを踏まえて今回のBLM運動を観ると興味深い考察が出来ましたので、ここに書き残しておきます。

聖書とは何なのかが、平均的な日本人は知らないので、私なりの非常に簡便な解説をすると、聖書は人間と神との契約書です。死後、天国に行きたければ神と契約しろ。と言うわけです。そしてその契約書には現世において守らなければならない事が書かれています。キリスト教徒がこの事を日本人にあんまり言わないのは、日本人を勧誘する時に「法律を守っている上に更に戒律まで守らなければならないのか!そんな事はやってられない。」となるから黙っているんです。

それでアメリカの保守派の話に戻りますが、私が見るに、彼らは彼らの先祖がその聖書に書かれている契約を守ったから、神は自分たちに祝福を下さったと考えています。この場合の祝福とは、世界で最も強く、最も豊かで、最も自由であるアメリカの支配階級の一員でいる事です。なので聖書に書かれている契約を破れば神からの祝福は無くなってしまうと考え「聖書に書かれている事を守れ!」と激高するわけです。

BLM運動でデモしている人に、保守派の人が銃を構えている映像を見たんですが、余りにも銃が場違いな気がしたんです。銃を持ったことが無い人は知らないかもしれませんが、銃に使われている鉄は滅茶苦茶頑丈なんです。鉄パイプ何かとは全然質が違います。弾なんか入っていなくても銃だけで十分凶器になるんです。そこから実弾が発射されるわけですから、デモしている人達が暴動に繋がるかも知れないと思っていたとしても、余りにもオーバーキルな武器なんです。

それで、あくまでその映像が本物である前提ですが、ある仮説を思いつきました。彼らはBLM運動でデモしている人と戦っている訳ではないんだと。何か別な物と戦っているんだと。ここで分かったんです。アメリカの保守派の言っている事の真実が。彼らは「聖書に書かれている事を守れ!」と言っていますが、「聖書に書かれている事を守る!」とも「聖書に書かれている事を守っています!」とも言っていないんです。自分の事は棚上げなんです。白人至上主義者の奥さんがアジア人なのを見て我々日本人は?と成りますが、彼らも同じで自分の事は棚上げなんです。しかしそんな保守派の人もふと我に返る時があるはずです。そしてその時に己の罪と神からの罰に恐れおののくはずで、その結果、取った選択が銃を持つだったんです。あの銃は決して国家と戦うためや自衛のためのモノじゃなかったんです。自分を罰しに来た神を殺すためだったんです。

BLM運動でデモしている人に銃を向けた保守派の人には、BLM運動でデモしている人達が、彼らから権力と富と自由の返却を迫る神の軍隊に見えたんです。だから彼らに銃を向けたんです。

幼女戦記と言うアニメがあって、このアニメで主人公が神に対して銃をぶっ放すシーンがありますが、この主人公はハナッから神を神と認めていません。全知全能ならこんな問題を最初から起こすわけがないと。つまり神を、神と名乗る偽物であると断じて神に対して銃をぶっ放す訳です。更に科学文明に根差した現代を生きる我々にとっては、むしろ神を殺すと言う行為は人間性の真なる自由を得る儀式として必要なものである可能性すらあります。

しかし今回の保守派の銃はネガティブな神殺しで、アメリカの保守派の精神世界ではある程度整合性が取れているかもしれませんが、私には精神を病むタイプの神殺しに思えます。しかもこの考えはアメリカ人の心理を非常に深い所で縛っている気がします。権力と富の返却を迫る神の軍隊に銃を向けたアメリカ人は二度と、元の地位に戻る事は出来ないと自分で自分を縛ってしまうかもしれません。ひょっとするとアメリカは衰退するかもしれませんね。しかも10年や20年ではなく100年とか500年単位の衰退と停滞の始まりかもしれません。

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

<本文>

今週はカメラを動かします。

1.カメラの移動

このサイトに複数のカメラを配置してそれぞれのカメラから撮影する方法が説明されています。一見便利な方法ですが、カメラの位置をキャラクターに合わせて動かす事が出来ないので今回はこの方法はパスします。ただし戦闘用の別なマップを作成してそこで戦う場合は非常に有効な方法だと思います。近い将来、戦闘用の別なマップを作成する場合はこの方法に切り替えます。

このサイトに複数のカメラを使用するのではなく、一個のカメラの位置をコントロールする方法が書かれていました。これならばキャラクターに付属の一個のカメラの位置を変更するだけで出来そうです。試してみます。

f:id:kazuhironagai77:20200705204732p:plain

これで自分の姿が映るはずです。

試してみます。

f:id:kazuhironagai77:20200705204753p:plain

バッチリ映っています。今度はカメラの位置を元に戻します。

f:id:kazuhironagai77:20200705204818p:plain

先程操作したカメラの逆の操作をカメラに対して行いました。

行列の計算ならばこれで元の値に戻るはずです。試してみましょう。

f:id:kazuhironagai77:20200705204846p:plain

戻りました。

うん。普通に出来ましたね。これを戦闘中に出来るようにします。

EventReportBeginExecuteActionの

f:id:kazuhironagai77:20200705204904p:plain

IsPlayerがTrueの場合に

f:id:kazuhironagai77:20200705204926p:plain

カメラが切り替わるようにします。

f:id:kazuhironagai77:20200705204942p:plain

そしてアニメーションが終了したらカメラの位置を元に戻します。

f:id:kazuhironagai77:20200705204959p:plain

テストします。

f:id:kazuhironagai77:20200705205016p:plain

f:id:kazuhironagai77:20200705205024p:plain

f:id:kazuhironagai77:20200705205032p:plain

折角なんで魔法も試してみます。

f:id:kazuhironagai77:20200705205048p:plain

中々迫力があります。

今週やりたい事は出来てしまいましたね。

うーん。やっぱりゲームエンジンだけあってゲームを作成するに必要な関数は一通り揃っているんですね。先週のアニメーションの追加にしても今週のカメラの位置の移動にしても基本的には一個の関数を呼ぶだけで出来ましたから。

2.UIの改良

余った時間何をしようか考えたんですが、UIを改良します。

f:id:kazuhironagai77:20200705205123p:plain

元々の戦闘時のUIは上記に示したようにする予定でした。

f:id:kazuhironagai77:20200705205144p:plain

現在のUIは予定していたのと比べるとかなり見にくいです。改良します。

f:id:kazuhironagai77:20200705205201p:plain

こんな感じに作り替えました。

f:id:kazuhironagai77:20200705205218p:plain

こんな風に表示されます。

f:id:kazuhironagai77:20200705205235p:plain

f:id:kazuhironagai77:20200705205243p:plain

f:id:kazuhironagai77:20200705205254p:plain

ボタンが後ろのイメージから浮いていますね。それ以外は即席で作成したにしては中々いいデザインだと思います。

f:id:kazuhironagai77:20200705205314p:plain

コメント欄にはずっと前にビジュアルノベルを作成した時に作成した木の模様図(以下に示した)を使用しました。

f:id:kazuhironagai77:20200705205347p:plain

こういう図って著作権あるんでしょうか?単純な模様の繰り返しに著作権が存在するんですかね。この絵、描くのに6時間くらいかかった記憶があります。単純な模様の繰り返しには著作権が存在しないならどっかからコピーしたいですね。

3.これからやる事の整理

ちょっとゴチャゴチャして来たのでこれからしなければならない事を整理します。

3.1 ターン制の戦闘の改良について

これに関しては大体は出来たと考えています。敵のモンスターとそのモンスターの動作を追加する必要があります。

3.2 Ch2で追加した機能について

Ch4_3ではch2に追加した機能はほとんど作っていません。例えば道具の購入や武器の装備です。これも追加する必要があります。

正直どんな機能を追加したのか覚えていません。ブログを見直して見ます。

去年の10月から教科書にない機能を追加し始めていました。

うーん。思えば結構やっていますね。

  • メインメニューの作成
  • セーブ機能の追加
  • マップの追加とワープ機能
  • 道具屋とそのUIの作成
  • モンスターのAIの追加
  • 所持している道具を表すUIの作成
  • 武器屋の作成
  • 所持している武器、防具と装備している武器、防具を表すUIの作成
  • 装備した武器や防具の値がATKなどに反映されるようにする。
  • ワープしても武器や防具が外れないようにする。
  • 装備した武器や防具をキャラが実際持っているようにする
  • 移動のモーションは武器によって変更する。ワープしてもモーションが変わらないようにする。

今年の3月9日までやっていますね。その日から戦闘部分の作成に代わっています。

3.3 教科書に書かれている内容で作成していない部分の追加

Ch4_3では教科書のサンプルの最低限の部分しか作成していないので戦闘のダメージなどが一律10で計算されたりしています。戦闘が終了しても経験値もゴールドも得られません。

教科書を軽く見直して見た所、4章のポーズメニューから先は全くやっていません。全部追加する必要があります。

4. RPGのストーリー制作

今週も時間が余ったのでもう少しだけプログラムをやろうと思ったのですが、やらなければならない事を整理してみると簡単には出来そうもないのと、BLMと保守の論客の議論を通じて新たな思想を得る事が出来たのでRPGのストーリー制作と題して、前文にまとめているような内容をもう少し深く考察してまとめてそれをここに載せる事にしました。

4.1 人種差別とアニメ

ゲーム自体は娯楽ですからやってもやらなくても良いはずです。プログラマーとしてゲーム制作に携わる場合、北米やヨーロッパの発表を見ると平均のサラリーが他のプログラマーと比較してかなり低い結果になっています。マネージャークラスになってやっと同じ位になるらしいです。そのデータに日本のゲーム制作に携わるプログラマーの推定年収も載っていましたが、生きていけないレベルと断定されていました。現状ではビジネスとしてゲームを制作するメリットは全くないわけです。

ではゲームを制作する事自体無駄なのかというと、私は違うと思っています。それは人種差別とアニメの関係がゲームにも言えると思うからです。

どの人種にも良い人もいれば悪い人もいます。人種でその人を判断するのは道義として間違っているだけでなく事実に基づかない考えだから間違っている訳でもあります。しかし実際問題として全く知らない人を判断する場合、その人の見た目しか判断基準がないので人種で判断せざる得なくなってしまいます。所が、これは今のアメリカで実際に起きている事ですが、好きなアニメのキャラのTシャツを着ていると、そのアニメのキャラが好きな人とは、それだけで人種を超えた信頼関係が築けるんです。勿論、アメリカの事ですので、その事に気が付いた狡い奴がそのアニメを見た事もないのに人気のキャラのTシャツを着たりする事例も出て来ていますが。

問題のある白人警官だって自分の好きなアニメのキャラのTシャツを着た黒人は簡単には撃たないですよ。話し合いで解決したいと思うはずです。アニメは人種差別を解決出来でしまうんです。今、アメリカ全体が人種差別の問題で崩壊寸前ですが、日本のアニメはそれを解決出来るんですよ。勿論、全てのアニメにそれだけの力がある訳ではなく、本当に人気のあるごく少数のアニメに限っての話ですが。これは優れたゲームも同じ事が言えると思います。だからこれだけでもゲームを制作する価値はあるんです。

4.2 優れたゲームを制作するには

問題はゲームを制作するのと優れたゲームを制作するのが同じではない事なんです。我々が知りたいのは優れたゲームの作成方法なのに、今あるのはゲームの作成方法だけです。昔、シイタケの栽培は切ったクヌギの木に傷を付けてほったらかすだけだったそうです。そうすると空気中に漂うシイタケの菌がくっついてシイタケが生える場合もあるし生えない時もある。単なるギャンブルです。今は菌糸をクヌギの木に植え付けるので必ず生えるそうです。

このシイタケの栽培方法が改善された例に従えば、優れたゲームの制作方法だって必ずあるはずなんです。

RPGに限って言えば優れたストーリーこそが優れたRPGを作成するはずです。しかし我々はどうすれば優れたストーリーを作成出来るのか知りません。しかし、前文で書いた保守派の論客のようなキャラをゲームに登場させたらストーリーが抜群に面白くなると思ったんです。ここが大事なポイントです。その保守派の論客が理想とする社会をゲーム内に忠実に再現するのではなく、その保守派の論客のようなキャラをゲームに登場させたらストーリーが抜群に面白くなるんです。

良く映画や大作のゲームでポリコレのためにマイノリティーを無理やり重要な役に入れますが、そうじゃなかったんです。面白いストーリーを作成するためには、ポリコレを守れと叫ぶおばちゃんを重要な役に入れる事だったんです。そのポリコレを守れと叫ぶおばちゃんが一緒の船に乗っているLGBTなおっさんが女子トイレを使用する時に、どんな態度を取るのか?これが面白いストーリーの作成に不可欠だったんです。

そう言えば9条絶対主義を実現したような世界観のJRPGをやっているアメリカ人がこんなつまらないゲームは初めてだ。初めてゲームを憎むほど嫌いになった。と言っていたのを思い出しました。そのゲームで悪い帝国軍かなんかが侵略を開始しているのに誰も戦争して止めようとしないシーンがあって、そのアメリカ人は登場人物全員に戦争すべきかどうか聞いて回るんです。そしたら全員が、「戦争反対。」と答えるです。これは平均的なアメリカ人には結構衝撃的な解答なんですが、これがJRPGの洗礼なのか?と衝撃を受けながらもその理由を聞く訳です。きっとアメリカ人には想像もつかないけど納得出来る凄い日本的な哲学が出てくると期待して。そしたら全員が「戦争は悪い事だから。」しか答えない訳です。ポカーンとなったそうです。しかしそのアメリカ人はそういうアホな選択をした人達が悲惨な結果を迎えるかもと、一縷の望みを託して最後までプレイしたそうです。そしたら9条絶対主義を実現したような世界観が現実を曲げに曲げて戦争反対を言った人達は勿論ゲーム内ですが何事もなく幸せに過ごしたそうです。

このゲームだって9条絶対主義を実現したような世界観にしたからつまらなくなったんで、9条絶対主義の左翼のおっさんを登場させたら面白くなったはずです。日本が外国から侵略された時に、このおっさんが人間の盾となって全世界で中継される中で真っ先に犠牲になっても一人だけちゃっかりとアメリカなんかに逃亡しても超絶面白いです。

4.3 ちょとだけアメリカの政治について

BLM運動と保守派の論客との議論でちょっとだけアメリカの思想に詳しくなりました。結構、びっくりしたのですが、保守でも革新でもないアメリカ人でも結構BLM運動に反対している人達がいる事を知りました。最初は革新のふりをした保守なんだろうと思ったのですが、よく話を聞いてみると結構重要な問題がBLM運動にある事が分かりました。今回はちょっとだけその事について記しておきたいです。

保守でも革新でもないアメリカ人でBLM運動に反対している人達の理由を私なりにまとめると、共和党は黒人と敵対しているが民主党は黒人に寄生して私腹を肥やしているので民主党が主体のBLM運動を支持しても貧困層にいる黒人の助けにならない。と言う意見です。データと統計学を駆使して説明していてかなり説得力がありました。特に民主党が歴史的に黒人を助けると称して黒人に寄生して私腹を肥やしているのが丸わかりになるのが面白かったです。

こういう蜀に取り立てられる前の諸葛孔明みたいな人もRPGに登場させたら更に面白いストーリーになると思いました。

5. まとめと感想

今週はこれだけです。来週は教科書に書かれている内容をCh4に追加します。

「Unreal Engine 4.xを使用してRPGを作成する」の足りない部分を作成する MyCombatEngineの作成3

f:id:kazuhironagai77:20200628203106p:plain

<前文>

前文で何回も紹介している英語の音素の区別がつくようになるゲームですが、効果が凄いのでビジネスとして展開する決意をしました。ただ普通に販売しても全く注目されず売れもしないのは分かり切っているので、商業的に成功するための作戦を今考えてみます。

と思ったんですがビジネス系の勉強を全くした事がない私は、商業的に成功するための作戦について全く知らないです。うんうん。頭をひねってやっと思いだしたのが以下の話でした。

  1. 安売りは絶対しない。
  2. Subscription制は儲かる。
  3. 対象とするお客のイメージをなるだけ具体的にする。
  4. 資本金は掛けない。

1. についてですが「安売りするとクレーマーが集まる。」と言う話を昔、何かの本で読んだのですが、商売をやっている人達にその話をした時、みんな共感していたのでかなり事実の様です。ある人は「値段を3割下げたらクレーマーの数が2倍になった。」と言っていました。ので安易な安売りは絶対避けるべきです。アンドロイドやI-phoneのアプリにするの事を考えていましたがこれは結構安易な安売りでクレーマーを集めるだけかもしれません。

2. についてはアドビ―社がsubscription制にしたら、海賊版を使用する人たちも購入するようになって結果的に収入が上がった。と言う話とCostcoが成功しているのが会員制にする事で安定的に月々の収入を得る事が出来るから、と言う話を聞いたのを思い出しただけです。このモデルでやる場合は、一つ考えがあります。英会話、特に子供向けの英会話教室に月額いくらかつ個別でこのゲームを貸し出す方法です。大手の英会話学校と直で交渉するとこっちは拙い個人なので全部利益を取られてしまいますが、個人相手ならば普通に商売として確立出来ると思います。

3. これは最近YouTubeで見たのですが、かなり役に立つ情報と思いました。具体的な顧客のイメージは全く持っていませんでした。というかこれだけ効果のある練習法を、いくらお金を払うからと言って誰にでも伝授するのは気分的に良くないので意識的に避けていました。これからは考える様にします。

4. これは当たり前ですが資本金がなくなってしまうとそれ以上チャレンジ出来ません。失敗しても立ち直れるようになるだけお金は掛けない方向でやります。

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

<本文>

今週はアニメーションを追加します。

1. アニメーションの追加

1. 兎に角、アニメーションが実行されるようにします。

f:id:kazuhironagai77:20200628203328p:plain

これが表示された時に攻撃用のアニメーションが実行されるようにします。

f:id:kazuhironagai77:20200628203352p:plain

このイベントが発生した時に攻撃用のアニメーションが実行されれば良いみたいです。

滅茶苦茶簡単な方法ですが以下の実装をしてみました。

f:id:kazuhironagai77:20200628203410p:plain

テストします。

f:id:kazuhironagai77:20200628203428p:plain

f:id:kazuhironagai77:20200628203434p:plain

攻撃のモーションが実行されました。

ハッキリ言って攻撃のモーションについてはこのやり方で十分ですね。後で装備している武器によってモーションが変化するように改良します。

2. 攻撃のモーションの時は、ウィジェットを消したい。

CombatUIのvisibilityをCollapsedに変え、アニメーションをプレイします。アニメーションのプレイが終了したらCombatUIのvisibilityをvisibleに戻します。

f:id:kazuhironagai77:20200628203543p:plain

テストします。

f:id:kazuhironagai77:20200628203601p:plain

攻撃の間だけCombatUIが消えました。

f:id:kazuhironagai77:20200628203636p:plain

攻撃が終了したらCombatUIは元に戻ります。

これも簡単に出来ました。

3. 戦闘に勝った時と負けた時のアニメーションを追加する。

EventReportFightIsOverにアニメーションを追加します。

f:id:kazuhironagai77:20200628203708p:plain

1.と同じ方法でアニメーションを追加しました。

f:id:kazuhironagai77:20200628203726p:plain

テストします。

勝利のアニメーションは実行されますが、前の攻撃のアニメーションが省略されてしまいました。

f:id:kazuhironagai77:20200628203753p:plain

更に今気が付いたのですが、

f:id:kazuhironagai77:20200628203818p:plain

戦闘が終わっても、MyThirdPerson_AnimBPが適用されなくなって使用したアニメーションのポーズを維持しています。

これらを直します。

MyThirdPerson_AnimBPが適用されなく問題ですが、アニメーションの最後でもう一度、MyThirdPerson_AnimBPをセットし直して見ました。

f:id:kazuhironagai77:20200628203841p:plain

これで直れば儲け物位の気持ちですが、テストしてみます。

f:id:kazuhironagai77:20200628203907p:plain

普通に直りました。

次に勝利のアニメーションが戦闘が終了してから実行されるようにします。

以下に示したようにEventFightIsOverの後で、アニメーションが開始されるようにしました。

f:id:kazuhironagai77:20200628203931p:plain

テストします。

戦闘が終わってから勝利のポーズを取るようになりました。

上手くスクリーンショットが取れないので、図はなしです。

敗北した場合のアニメーションも追加します。

f:id:kazuhironagai77:20200628204007p:plain

勝利のアニメーションを入れた時と全く同じやり方です。

テストします。

以下に示したようなアニメーションが死んだ時に流れました。

f:id:kazuhironagai77:20200628204029p:plain

うーん。今週やろうと思っていた事全部出来てしまいましたね。流石にこれで終にするには短すぎますね。どうしましょうか?

2. 魔法

色々考えたんですが、魔法を追加します。

1. 魔法の追加

武器屋や道具屋を追加するとゴールドなどを表示するためのUIの作成がその前に必要ですので面倒です。戦闘が開始した場合に別なマップにワープする機能は絶対必要と言う訳ではないので後回しでいいと思っています。そうするとカメラワークの追加に成りますがそれは来週やろうと思っているので、特にやりたい事や今の状況で出来る事がないです。

そんな中で考えたのが魔法の追加です。これなら、UE4C++をあんまり弄らなくて見た目に大きな変化があるものが作成出来そうなのでこれをやります。

魔法や道具の場合は、攻撃と違い使用する魔法や道具を最初に選択する必要があります。

以下に示したようにCombatUIのTargetsを分割して、片方を魔法や道具の選択のために使用します。

f:id:kazuhironagai77:20200628204120p:plain

まず、ここに使用出来る魔法が表示出来る様にします。

となると魔法についてのデータシートが必要ですね。

以下にアイテムのItemDataを示します。

f:id:kazuhironagai77:20200628204145p:plain

これを真似て作成します。

消費MPは絶対必要ですね。名前はMPでいいでしょう。次にダメージ量を表す項目、これはHPで良いです。更に攻撃力や防御力をアップする魔法もあるかもしれませんのでATK、DEFも必要ですね。運を上げる魔法もあるかもしれませんのでLuckは残しておきます。魔法の絵があると見やすいのでToolImageに似たMagicImageも追加しておきましょう。Goldは要らないですね。

では作成します。

と思ったらDataTableの作り方をすっかり忘れてしまっていました。色々調べたら2020-04-19のブログに作り方がまとめてありました。それを元に作成します。

UObjectを親クラスとしてMagicsDataクラスを作成します。

f:id:kazuhironagai77:20200628204215p:plain

f:id:kazuhironagai77:20200628204223p:plain

これを2020-04-19のブログに載っている方法でDataTableに改造します。

f:id:kazuhironagai77:20200628204251p:plain

ビルドします。

f:id:kazuhironagai77:20200628204312p:plain

成功しましたが、UE4エディターがクラッシュします。

UE4エディターを再起動します。

以下に示したように項目を追加しました。

f:id:kazuhironagai77:20200628204334p:plain

ビルドします。

成功しました。

DataTableを作成します。

f:id:kazuhironagai77:20200628204353p:plain

f:id:kazuhironagai77:20200628204405p:plain

出来ました。

f:id:kazuhironagai77:20200628204430p:plain

魔法も追加します。

f:id:kazuhironagai77:20200628204447p:plain

イラストも作成しました。

f:id:kazuhironagai77:20200628204508p:plain

これで魔法のデータテーブルが出来ました。

使用出来る魔法の一覧を保持した変数をGameCharacterクラス内に作成すべきかどうかですが、ちょっと迷っています。この辺は所持している道具の管理の復習をやってから考える必要がありそうです。今回はGameCharacterクラスは変更しない事にします。

こんな感じに作成しました。

f:id:kazuhironagai77:20200628204545p:plain

魔法を押すと使用出来る魔法の種類がChoose内に表示されます。

f:id:kazuhironagai77:20200628204604p:plain

f:id:kazuhironagai77:20200628204612p:plain

炎(小)を選択するとゴブリンが表示されます。ゴブリンを選択すると

f:id:kazuhironagai77:20200628204633p:plain

と表示されます。

まあ、今週はこの辺はあまり作成したい個所じゃないのでこの位で止めておきます。

2. 魔法のアニメーションの追加

2.1 準備

私が今週したいのはこの魔法にアニメーションを追加したいんです。

まずそのための準備をします。

戦闘中のアニメーションはRPGGameModeBaseBPのEventReportBeginExecuteActionで管理しています。

f:id:kazuhironagai77:20200628204719p:plain

RPGGameModeBaseBPは、EventReportBeginExecuteActionが攻撃、魔法、アイテム、そして逃げるの中からどれを選択して呼ばれたのかを知る必要があります。

これはEnumを作成して伝達する事にしました。Enum、 CombatSelectionsを作成します。

UE4C++で作成するかBPで作成するか迷ったのですが、攻撃、魔法、アイテム、そして逃げるの選択自体がBP上にしか存在しないので、BPで作成する事にしました。

f:id:kazuhironagai77:20200628204744p:plain

f:id:kazuhironagai77:20200628204752p:plain

これを使用してEventReportBeginExecuteAction が呼ばれた時にRPGGameModeBaseBPが攻撃、魔法、アイテム、そして逃げるの選択肢の中のどれから呼ばれたのか知る事が出来る様にします。

以下に示すようにCombatUIクラス内にCombatSelectionsから変数、CombatSelectedを作成します。

f:id:kazuhironagai77:20200628204815p:plain

攻撃ボタンが押された場合はAttack、魔法ボタンが押された場合はMagicが保持されるようにセットします。

f:id:kazuhironagai77:20200628204848p:plain

RPGGameModeBaseBP内でEventReportBeginExecuteActionが呼ばれたら、

f:id:kazuhironagai77:20200628204921p:plain

CombatSelectedの値によってアニメーションが変わる様にコードを組みます。

f:id:kazuhironagai77:20200628204940p:plain

テストします。

攻撃を選択した場合のアニメーションのスクリーンショットを以下に示します。

f:id:kazuhironagai77:20200628204959p:plain

魔法の場合です。

f:id:kazuhironagai77:20200628205034p:plain

選択した別のアニメーションが実行されました。

2.2 ファイアーボールの作成

ここでこのチュートリアルに載っているファイアーボールを発射するアニメーションを追加したいんです。

f:id:kazuhironagai77:20200628205058p:plain

ずっと昔勉強したのですがやり方はすっかり忘れてしまったのでもう一度勉強し直します。

出来ました。

f:id:kazuhironagai77:20200628205122p:plain

しかしこれをアニメーションにする方法が分かりません。

取りあえずこんな感じで組んでみました。

f:id:kazuhironagai77:20200628205142p:plain

テストの結果です。

f:id:kazuhironagai77:20200628205207p:plain

f:id:kazuhironagai77:20200628205219p:plain

f:id:kazuhironagai77:20200628205228p:plain

f:id:kazuhironagai77:20200628205236p:plain

動作が速すぎますね。その辺の調整は来週行います。今週は時間が無くなってしまったのでここで終了です。

3. まとめと感想

来週はカメラを動かします。

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

f:id:kazuhironagai77:20200621195342p:plain

<前文>

今週は、日本人の英語と韓国人の英語と中国人の英語の違いについてちょっとだけ語りたいと思います。最近、BLM運動で日本人も英語で結構な議論をしているのをネットのあちこちで見かけました。それぞれに色々な立場や考え方がある中でかなり激しい議論を日本人同士が英語で議論しているのをみて、正直「あれ、日本人ってこんなに英語得意だったっけ?」とかなり驚きました。

それは別にいいのですが(因みに私が作っている英語の音素の区別がつくゲームはそういう在米何十年のレベルの方でも、小学生の時に移民しない限りは聞き分けられない微妙な音素の区別が、遊んでいるだけで誰でも出来るようになる滅茶苦茶凄い効果のあるゲームです。)議論している人の中に日本人じゃないのに日本人として参加している人がいました。その人が書く英語を読んですぐに分かりました。日本人の英語と韓国人の英語と中国人の英語って同じようでかなり違う部分があるんです。

まあ、私は傍観者(あくまで日本人同士の不毛な議論に対しての傍観者という意味です。BLM運動自体は勿論支持しています。)だったのでどうでも良かったんですが、その議論している人の誰もがその事に気が付かないのはどうなの?とちょっと思ってしまいました。

アメリカに何十年住んでもbとv の区別が付かない人もいますから、どんなに英語が上手くなっても、日本人の英語と韓国人の英語と中国人の英語の違いが分からない人もいるんでしょうね。ネットでバトルするなら相手の素性は怪しいと思うべきで、それを確認する方法は研究しておくべきでしょう。

一個だけ簡単な例をここで公開します。中国人の場合ですがuから始まる単語がaなのかanなのかの区別が出来ません。日本人なら中学生でアイウエオはan、それ以外ならaと覚えると思います。のでunderdogならアンダードックだからan、unicornならユニコーンだからaと英語学習の初心者でも間違える事はほとんどありません。これが中国人の英語になると相当な上級者でもuの前のaとanは間違えていたりします。

まあ、こんな感じである程度は書かれている英語から相手の素性を見極める技術もネットでバトルするなら磨いておいた方がいいんじゃない。とお節介ながら思いました。

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

<本文>

1. 先週の直し

1. テキストがボックス内に表示されるようにする。

f:id:kazuhironagai77:20200621195548p:plain

今のテキストは表示された文字が消える事はありません。ので最終的には文字がボックスからはみ出してしまいます。“読みましたボタン”を押したら、表示されている文章は消えるように変更します。

f:id:kazuhironagai77:20200621195620p:plain

まあ、簡単ですが、これで“読みましたボタン”を押したら、表示されている文章は消えるようなりました。ただこれだけだと次の文章の最初が、2段目から始まるようになるのでそれも直します。

f:id:kazuhironagai77:20200621195651p:plain

文章が終わったら、段落を変えるようにします。これだけです。

テストします。

f:id:kazuhironagai77:20200621195712p:plain

“読みましたボタン”を押しました。

f:id:kazuhironagai77:20200621195730p:plain

消えていますね。

2. テキスト文の推敲など

コメント欄に表示される文章が微妙におかしいです。

以下に示したのは最初の画面ですが、次のフェーズに移行するためには、プレイヤーは攻撃、魔法、道具、逃げるの4つのボタンから選択する必要があります。

f:id:kazuhironagai77:20200621195800p:plain

しかし、青色のテキストボックスでは、“KUMOは次の行動を考えています。”とだけ表示されていて、プレイヤーが具体的に何をすれば良いのかは分かりません。

「プレイヤーは攻撃、魔法、道具、そして逃げるのどれかを選択してください。」ぐらいは表示されないと意味不明になりますね。

よし、そのセリフを表示させましょう。

やり方は簡単です。

f:id:kazuhironagai77:20200621195827p:plain

RPGGameModeBaseBPのEventBeginMakeDecisionの最後に以下の部分を付足します。

f:id:kazuhironagai77:20200621195855p:plain

ただしGameCharacterクラスのisPlayer変数はBPからアクセス出来ないので以下のように変更しました。

f:id:kazuhironagai77:20200621195922p:plain

ビルドします。

f:id:kazuhironagai77:20200621195940p:plain

テストします。

f:id:kazuhironagai77:20200621200022p:plain

綺麗に表示されていますね。

攻撃ボタンをクリックします。

f:id:kazuhironagai77:20200621200047p:plain

あれ?ボタンの表示が何か変ですね。どうしたんでしょうか?

以下にボタンの作成方法を示します。

f:id:kazuhironagai77:20200621200105p:plain

これを見ると、攻撃対象のモンスターを表示するwidgetを作成する時に、パラメーターとして変数をパスしていません。その直後に変数にアサインしています。この少しの差がボタンを作成した時に敵のモンスターの名前が分からない事態を生んでいると思います。

以下のように作り替えてみました。

f:id:kazuhironagai77:20200621200134p:plain

これで試してみます。

f:id:kazuhironagai77:20200621200154p:plain

今度はゴブリンと表示されました。

. TextBoxの更なる改良

やっている事は1.と変わらないんですが、先週の直しではないので新しい節に変えました。

1.RPGGameModeBaseBPのReportExecuteAction()が実行された後も“読みましたボタン”を押すまでは先のフェーズに進まないで待ってほしい。

まず、GameCharacterクラスのExecuteAction() 関数の実装を以下のように変えました。

f:id:kazuhironagai77:20200621200245p:plain

更に、RPGGameModeBaseBPのEventReprotExecuteActionに

f:id:kazuhironagai77:20200621200302p:plain

以下に示したコードを追加しました。

f:id:kazuhironagai77:20200621200322p:plain

一応、理論上はこれで良いはずなのでテストします。

f:id:kazuhironagai77:20200621200408p:plain

文章の表示が止まっています。戦闘のフェーズも停止しているようです。

“読みましたボタン”を押します。

f:id:kazuhironagai77:20200621200438p:plain

今度は、ゴブリンのアクションに対しての報告が表示されました。

f:id:kazuhironagai77:20200621200501p:plain

うん。出来ているみたいです。

ここまで見てるとCombatEngineのIDecisionMakerクラスとICombatActionクラスを分ける必要があるのか疑問になって来ました。一個のクラスにしてCombatUIWidgetに継承させればもっと簡単にBPとUEC++を繋げられそうな気がします。

2. 戦闘終了時のコメントが表示されない。

今度はこれを追加します。

現状、戦闘が終了した時には以下のコメントがログに表示されています。

f:id:kazuhironagai77:20200621200541p:plain

f:id:kazuhironagai77:20200621200549p:plain

この関数を、以下に示すようにRPGGameModeBaseクラスのTick()関数内から呼びます。

f:id:kazuhironagai77:20200621200640p:plain

この関数を、以下に示すようにRPGGameModeBaseクラスのTick()関数内から呼びます。

f:id:kazuhironagai77:20200621200706p:plain

f:id:kazuhironagai77:20200621200714p:plain

GameOverの場合はfalse、Victoryの場合はtrueをパスします。

以下に示すように、RPGGameModeBaseBP内でReportFightIsOver()関数の実装を行います。

f:id:kazuhironagai77:20200621200803p:plain

単に、勝った時は、勝ちました。負けた時は負けましたとコメント欄に表示されるようにしただけです。

テストします。

何も表示されずに戦闘が終わってしまいました。

これは多分ですが以下に示すRPGGameModeBaseクラスのTick()関数内のコードが先に実行されたせいでしょう。

f:id:kazuhironagai77:20200621200826p:plain

更に関数と変数を追加して“読みましたボタン”をクリックするまでこれらのコードが実行されないようにしましょう。

まず、RPGGameModeBaseクラスに以下の関数と変数を

f:id:kazuhironagai77:20200621200848p:plain

f:id:kazuhironagai77:20200621200858p:plain

追加しました。

HadReadFightIsOver()関数は以下に示したように実装しました。

f:id:kazuhironagai77:20200621200925p:plain

変数は、TestCombat()関数内で、以下に示したように

f:id:kazuhironagai77:20200621200944p:plain

Assignしました。

更にTick()関数内を以下に示したように改造しました。

f:id:kazuhironagai77:20200621201003p:plain

最後にRPGGameModeBaseBPのEventReportFightIsOverの実装を以下に示したように変えました。

f:id:kazuhironagai77:20200621201022p:plain

f:id:kazuhironagai77:20200621201029p:plain

EventReportFightIsOverはパラメーターとしてCharacterをパスしないのでRPGGameInstanceBPクラスからMyYourHeroをSelectedCharacterとしてセットします。更に最後にEvent confirm button is clicked にバインドした全てのイベントを外します。

これで戦闘が終わった後の結果についてのコメントが青色のコメント欄に表示されるはずです。

テストします。

f:id:kazuhironagai77:20200621201055p:plain

敗北したと表示されました。そして“読みましたボタン”をクリックすると

f:id:kazuhironagai77:20200621201134p:plain

GameOver画面に映りました。完璧ですね。

今度は勝利した場合をテストします。YourHeroClassesのDataシートの値を以下に示したように

f:id:kazuhironagai77:20200621201153p:plain

変えてテストします。

f:id:kazuhironagai77:20200621201212p:plain

今度はKUMOは勝利しました。

f:id:kazuhironagai77:20200621201237p:plain

勝利した後は何事もなかったかのようにゲームが続行されます。

完璧に機能していますね。

3. もう少しだけ文章の推敲

かなり良くなったのですが、もう少しだけ良くしたいです。

戦闘中は青色のボックスには以下に示したようなコメントが表示されています。

f:id:kazuhironagai77:20200621201306p:plain

  • 戦闘が開始しました。
  • KUMOは次の行動を考えています。
  • (プレイヤーは攻撃、魔法、道具、逃げるから一つを選択してください。)

と一気に表示されています。

  • 戦闘が開始しました。

のみが表示される。

“読みましたボタン”をクリック。

  • KUMOは次の行動を考えています。
  • (プレイヤーは攻撃、魔法、道具、逃げるから一つを選択してください。)

が表示される。

“読みましたボタン”をクリック。

f:id:kazuhironagai77:20200621201429p:plain

が表示される。

位の方が分かり易いですね。

f:id:kazuhironagai77:20200621201453p:plain

“”は次の行動を決定しました。ですね。

これは簡単に直せるので今直してしまいます。

f:id:kazuhironagai77:20200621201526p:plain

直しました。

f:id:kazuhironagai77:20200621201550p:plain

決定した行動が何なのかもっと具体的な内容がほしいですね。「KUMOはゴブリンへ攻撃した。」みたいな。ついでに言えば、攻撃してどうなったのかの情報もほしいです。例えば「ゴブリンは10のダメージを受けた。」と言った感じです。

f:id:kazuhironagai77:20200621201656p:plain

そういう意味では「KUMOは次の行動を決定しました。」も「KUMOはゴブリンを攻撃する事を決定しました。」の方が分かり易いですね。

f:id:kazuhironagai77:20200621201728p:plain

最後の勝利した後ですが、「金貨を何枚得た」とか「宝箱が取れた」とかの情報もほしいですね。

金貨とかアイテムのInventory systemはこのプロジェクトでは作成していませんが、表示位は出来る様にしたいです。

4. 推敲した部分を直していく

4.1 戦闘開始の部分の直し

結構考えましたが以下の方法でやって見ます。

まず、RPGGameModeBaseクラスのTick()関数をFightIsStartIsRead変数がtrueの時だけ実行されるようにします。

f:id:kazuhironagai77:20200621201810p:plain

勿論、FightIsStartIsRead変数をtrueにする関数も作成します。

f:id:kazuhironagai77:20200621201830p:plain

今度は、UE4Editorに移り、UIWidgetの真ん中の部分(以下の図で選択されている箇所)が表示されない様にします。

f:id:kazuhironagai77:20200621201905p:plain

f:id:kazuhironagai77:20200621201913p:plain

最後に“読みましたボタン”を押したらFightIsStartIsRead変数をtrueにする関数が呼ばれるようにします。

f:id:kazuhironagai77:20200621201932p:plain

この方法だと“読みましたボタン”を押すたびにFightIsStartIsRead変数をtrueにする関数が呼ばれますが、多少動作が遅くなる意外は問題ないので、取りあえずはそのままにしておきます。
それではテストします。

f:id:kazuhironagai77:20200621201959p:plain

戦闘が開始してもプレイヤーが選択出来るボタンは表示されていません。“読みましたボタン”を押します。

f:id:kazuhironagai77:20200621202032p:plain

プレイヤーに攻撃、魔法、道具、逃げるから一つを選択して下さいとコメント欄に表示されると同時に攻撃ボタン、魔法ボタン、道具ボタン、そして逃げるボタンが表示されました。

3.では、コメント欄に「プレイヤーは攻撃、魔法、道具、逃げるから一つを選択して下さい。」と表示されてから“読みましたボタン”を押したら、攻撃ボタン、魔法ボタン、道具ボタン、そして逃げるボタンが表示と書きましたが、これも良い感じなのでこのままにします。

f:id:kazuhironagai77:20200621202155p:plain

次のターンも問題なく続いています。

出来ました。

4.2 「KUMOは次の行動を決定しました。」を「KUMOはゴブリンを攻撃する事を決定しました。」に変える。

いきなり「KUMOはゴブリンを攻撃する事を決定しました。」に変更するのは大変なので、以下のように変更してみました。

f:id:kazuhironagai77:20200621202241p:plain

攻撃ボタンがクリックされた場合、以下に示されたコードが実行されます。

f:id:kazuhironagai77:20200621202306p:plain

更に、対象になるモンスターを選択した場合、AttackTargetOption widgetより以下のコードが実行されます。

f:id:kazuhironagai77:20200621202339p:plain

テストします。

f:id:kazuhironagai77:20200621202358p:plain

攻撃ボタンを押すと以下のようなコメントが追加されます。

f:id:kazuhironagai77:20200621202417p:plain

更に攻撃対象としてゴブリンを選択すると

f:id:kazuhironagai77:20200621202445p:plain

が追加表示されます。

全体としては以下のような文章になっています。

f:id:kazuhironagai77:20200621202507p:plain

まだまだ推敲が必要ですね。しかしこういう状況によって表示するコメントが変わる場合のもっと根本的な仕組み自体を考える必要がある気がするのでこの辺で止めておきます。

4.3「KUMOはゴブリンへ攻撃した。」みたいな具体的な行動の内容をコメントする。

現状、行動を実行した場合のコメント欄での説明は以下のようになっています。

f:id:kazuhironagai77:20200621202623p:plain

これに

  • “KUMO”は“ゴブリン”に攻撃した。
  • “ゴブリン”は10のダメージを受けた。

のような表現を追加したいです。

一見すると「“KUMO”は“ゴブリン”に攻撃した。」の方が簡単そうですが、「“ゴブリン”は10のダメージを受けた。」はUE4C++のコードでダメージを与えてる箇所からBlueprintImplementableEventな関数を呼べば良いだけなのでこちらを先にやります。

f:id:kazuhironagai77:20200621202722p:plain

ムムム…

キャラクターにダメージを与えているUE4C++のコードを見つけたら、Combat Engine内のTestCombatActionクラスの関数でした。Combat Engineは単なるC++で書かれたengineなのでUE4C++の機能を使用してBlueprintImplementableEventな関数を作成する事は出来ません。

ちょっと考えます。

こんな感じで作ってみました。

まず、二つの関数をRPGGameModeBaseクラスとGameCharacterクラスにそれぞれ作成しました。

RPGGameModeBaseクラスに作成したBlueprintImplementableEventな関数、ReportCharacterHPisDamaged()。

f:id:kazuhironagai77:20200621202826p:plain

GameCharacterクラスに作成した単なるC++の関数、ReportDamageHPtoRPGGameModeBase()。

f:id:kazuhironagai77:20200621202845p:plain

まず、TestCombatActionクラスのBeginExecuteAction()関数内でCharacterにダメ―ジが発生したら、以下に示めすように

f:id:kazuhironagai77:20200621202926p:plain

ダメージが発生したキャラからReportDamageHPtoRPGGameModeBase()関数を呼びます。

ReportDamageHPtoRPGGameModeBase()関数は、RPGGameModeBaseクラスのBlueprintImplementableEventな関数、ReportCharacterHPisDamaged()を呼びます。

f:id:kazuhironagai77:20200621203009p:plain

最後にRPGGameModeBaseBP内にReportCharacterHPisDamaged()の実装を行いました。

f:id:kazuhironagai77:20200621203056p:plain

テストします。

f:id:kazuhironagai77:20200621203206p:plain

出来ましたね。

何かBPとUE4C++と生のC++の正しい関係が見えて来ました。後できちんとまとめますが、忘れないためにちょっとだけここにも書いて置きます。

まず生のC++とBPですが関係を持つ事は出来ません。この二つが連絡したり一緒に行動したりするためには必ずUE4C++の助けが必要になります。UE4C++とBPは関係を持つ事が出来ますが、その関係は対等ではなく政府(government )と一般人(people)みたいな上下の存在する関係です。UE4C++からBPへの連絡はほとんどが命令ですがBPからUE4C++に命令する事はほとんど出来ません。その唯一の例外がBlueprintImplementableEventを使用した関数で、これはBPで指定した内容をUE4C++で実行します。なのでC++からBPに連絡したりBPからC++に命令したりするためには、ちょっとした工夫が必要になります。

うん。これだけ書いておけば後で忘れる事はないでしょう。残りはこのブログの最後でまとめます。

今度は、「KUMO”は“ゴブリン”に攻撃した。」を表示させます。

以下の方法で試してみます。

まず、新しい変数CommentForExecteActionをWidgetUI内に作成します。

f:id:kazuhironagai77:20200621203309p:plain

WidgetUI内のAttackedButtonがクリックされた時、

f:id:kazuhironagai77:20200621203334p:plain

以下に示されたコードが実行されます。

f:id:kazuhironagai77:20200621203350p:plain

これにより「“敵のモンスター名”を攻撃した。」と言うコメントがCommentForExecteAction変数内に保持されます。

更にRPGGameModeBaseBP内でEven tReportBeginExecuteActionが発生した時に、

f:id:kazuhironagai77:20200621203428p:plain

以下に示したコードが実行されるようにしました。

f:id:kazuhironagai77:20200621203453p:plain

これにより、プレイヤーがコントロールするキャラが行動を実行した場合のみ、「“プレイヤーの操作しているキャラ名”が“敵のモンスター名”を攻撃した。」とコメント欄に表示されるはずです。

テストします。

f:id:kazuhironagai77:20200621203527p:plain

「“KUMO”がゴブリンを攻撃した。」と具体的に表示されるようになりました。

f:id:kazuhironagai77:20200621203550p:plain

敵のモンスターに関してはどのような攻撃をするかなどはまだ全くかんがえていませんので、このままにしておきます。

これで一応3.で述べた部分は直し終わりました。

5.「…した。」と「…ました。」を統一します。

以下に示したように「…した。」と「…ました。」が適当に使用されています。全て「…ました。」に統一します。

f:id:kazuhironagai77:20200621203701p:plain

直しました。

f:id:kazuhironagai77:20200621203758p:plain

f:id:kazuhironagai77:20200621203805p:plain

こちらの方が読みやすいですね。

6. “読みましたボタン”を必要な時だけ表示させる。

これ結構重要なんですが、今まで忘れていました。

f:id:kazuhironagai77:20200621203900p:plain

まず、“読みましたボタン”を押したら、必ず“読みましたボタン”の表示は消えるようにしました。

f:id:kazuhironagai77:20200621203918p:plain

次にRPGGameModeBaseBPの全てのBindEventtoConfirmButtonIsClickedノードの前にボタンを表示するようにしようとしたら

f:id:kazuhironagai77:20200621203940p:plain

RPGGameModeBaseBPからConfirmedButtonもSetVisiblity関数も呼び出せませんでした。

のでWidgetUI内で以下に示した関数

f:id:kazuhironagai77:20200621204010p:plain

を作成してその関数をRPGGameModeBaseBPから呼び出しました。

f:id:kazuhironagai77:20200621204039p:plain

テストします。

f:id:kazuhironagai77:20200621204128p:plain

戦闘が開始しましたが“読みましたボタン”が表示されています。ので“読みましたボタン”をクリックします。

f:id:kazuhironagai77:20200621204150p:plain

“読みましたボタン”が消えて、代わりに4つの攻撃、魔法、道具、そして逃げるボタンが表示されました。

f:id:kazuhironagai77:20200621204216p:plain

攻撃を選び、ゴブリンを選択すると上記のコメントが表示され更に“読みましたボタン”が表示されました。

全部記録しても意味がないので残りは書きませんが、最後まで上手く行きました。

今週の予定していた部分はもう終わってしまいましたがまだまだ時間が空いているのでどうしようかと思っています。

. C++UE4C++BPの関係についての考察

2.の4.3で少しだけ書きましたが、C++とUE4C++とBPの関係がイメージとして具体化出来たのでそれをここにまとめる事にします。

UE4でゲームを作成する時に、BPで作成するのが良いのかUE4C++で作成するのが良いのかの議論がありますが、UE4C++の方が速く処理出来る以外の有効な情報がなくて、結局どっちでも良いんじゃないみたいな話になってしまっています。このイメージを理解すると、この問題についてもある種の解決策を得る事が出来ると思います。

まず、UE4C++とBPの関係ですが対等ではありません。上下関係があります。UE4C++が上でBPが下です。政府(government )と一般人(people)に例えるとしっくりします。UE4C++が政府(government )で、BPが一般人(people)です。政府(government )は一般人(people)に命令出来ますが、一般人(people)は政府(government )に命令出来ません。一般人(people)が政府(government )に対して出来るのは基本的にはお願いだけです。

同じ関係性がUE4C++とBPにもあります。UE4C++はBPに命令出来ますが、BPからUE4C++には命令は出来ません。唯一の例外は今週使用したBlueprintImplementableEventな関数で、これはBP側からUE4C++にこれをやれと命令出来ます。出来ますが、この関数でさえいつどこで行うのかはUE4C++側が決定します。

現実の世界でも一般人(people)が政府(government )に命令出来る時は僅かですがあります。例えば110番や119番通報は、必ず警察や消防車が駆けつけなければならないのでお願いではなく命令です。ただしこれはどちらかと言えばBlueprintCallableな関数と同じで、BPから呼び出せますが、やる内容はBP側で決定する事は出来ません。

更にUE4C++ではBPに特別な関数を追加したり、基本的な関数を使用させないようにしたりする事も出来ます。これも政府(government )が特定の人々だけに特別な許可(医者が医療行為を出来る。など)を与えたり、特定の人々の権利を制限したり(犯罪者を刑務所に収容とか)するのに似ています。

次に生のC++とBPの関係ですが、生のC++ はBPと関係を持つ事は出来ません。BPに何か命令したい場合はUE4C++を通す必要があります。これは何でしょうか?国連か何かに似ていると思えばそこそこしっくりしそうですね。国連が治安維持部隊を派遣したいと思ってもあなたに直接、従軍しろと命令は出来ませんよね。まあ日本では絶対ないでしょうが、国連が政府に命令してその命令に基づいて政府があなたに従軍するように命令する感じでしょうか?

このイメージは結構、C++とUE4C++とBPの関係を正確に表している気がします。例えばあなたが原っぱで野球を友達とやるとします。政府に許可を貰いますか?貰わないですよね。つまり原っぱで友達と野球をするようなプロジェクトはBPのみで作成した方が良いと言う事です。では、貴方が近所の池にブラックバスを放して繁殖させたいと思った時はどうでしょうか?これがその池を管理している役所にお願いして許可をもらうとか、ひょっとすると議会で新しい法律を作成してもらう必要があるかも知れませんし、そういう政府との交渉をしないといけないでしょうね。これをゲーム制作に例えると、UE4が基本的には提供していない機能を追加する時や、UE4に元々ある機能を停止したいときだと思います。このようなゲームを制作する場合はUE4C++から作成すべきとなります。

最後にC++で作成した流体のシミュレーションをUE4を使って可視化したい。何で場合は、まさしく国連と政府とあなたの関係みたいになるんでしょうね。

今週はC++(combat engine)とUE4C++とBPを行ったり来たりしていたのでこんなイメージが具象化したのだと思います。正直この説明が一番分かり易いと言えるほど自信はありません。社長、部長、一般社員(貴方)で説明した方が分かり易い気もしています。部長は貴方に命令出来ますが、貴方が部長に対して出来るのはお願いだけです。しかし貴方が社長にお願いする事で、社長が部長に命令して、間接的ですが、貴方が部長に命令する事も出来ます。みたいにまとめた方が分かり易いかもしれなかったです。BlueprintImplementableEventな関数だって実際は実装をBP側で行うだけで、その実装を工夫する事で、BPからUE4C++に命令するような事を実現しているわけですから。

このアイデアは今まで誰も考えた事がない事なので内容が粗削りなのは仕方ないかもしれません。これから精製して発展させたいと思います。

. コメント欄のセリフの管理方法について

Treeを使った管理が必要

コメント欄のセリフですが、攻撃、魔法、道具、逃げるの4択からそれぞれ更に細分化された選択が存在しその一つ一つに対応したセリフがあります。これらのセリフを個別に管理する事は不可能です。一か所でエクセルのようなフォーマットで管理しないといずれどのセリフがどこにあるのかが分からなくなります。

ここで思ったのですが、エクセルで管理するよりもUE4のAIみたいなTreeを使用した管理の方が更に分かり易いと思いました。分岐に分岐を重ねる訳ですからエクセルでも最後は追えなくなる可能性がありそうです。UE4のAIみたいなTreeを使用した管理ならその見やすさから後から直す時に混乱して訳わからなくなる事が起きないと思いました。

. まとめと感想

今週はコメント欄に表示するテキストを表示するためのプログラミングを作成しました。普段より結構多めにやったように見えますが実際にはより少ない時間で終わりました。来週はこれにアニメーションを追加します。

「Unreal Engine 4.xを使用してRPGを作成する」の足りない部分を作成する MyCombatEngineの作成

f:id:kazuhironagai77:20200614230617p:plain

<前文>

前回、お話した英語の音素の区別がつけれるようになるゲームについての続報ですが、一応、今の所、このゲームの概要は以下のように考えています。

  • テスト版とトレーニング版を作成。テスト版は無料で、利用者が現在どれくらい英語の音素の区別がつけられるのかをテストするためのものです。このテスト版で満点が取れる人は全ての英語の音素の区別がネイティブと同じように出来る人と言う訳ではありませんが、かなり近い存在であると言う事になります。LとR、BとV、ThとSなどの音や、3つのアの音を含む全ての母音、更にR音が被った母音などの日本人が区別出来ていない音素を重点的にテストします。全部で150問程度の問題になるようにする予定です。
  • レーニング版は大体1500円位の価格を考えています。内容はRPGです。世界の各地に散らばっているボスのモンスターを倒すためには、10問連続で出される問題を全て正解しなければなりません。例えばLとRの音素の区別が出来ているかどうかのテストならRightとLightのどちらかの単語が発音されるので、正しいと思う方をプレイヤーが選択します。このテストで10回連続で正解する必要があります。倒したボスモンスターはカードになってプレイヤーのブックに保存されます。
  • 勿論、トレーニング版ですので、ボスのモンスターにチャレンジする前にたっぷりと練習出来る場所を作成しておきます。この練習で先週説明した凄い効果の出ている練習を行います。大体20分から1時間練習すればほとんどの人がその音に関しては区別が付くはずです。ゲームとしても丁度いい難度だと思います。
  • ゲームとしての面白さもないとユーザーは途中でゲームを止めてしまうので、ライバルや行方不明の主人公の親とか、海賊の財宝や世界征服を企む魔王なんかも登場する予定です。
  • 70から120のボスモンスターを倒す位の強さでゲームとしてはクリア出来るようにして残りは、ポケモンみたく集めるのが好きな人用に残しておきます。

私の周りの極少数の人に試しただけですが、このゲームで作成したトレーニングは英語の音素の区別に関しては凄い効果がありました。これだけの短い時間でこの効果を出せるなら大金を取っても全く問題ないと思いました。この言い方が分かり易い例えかどうか分かりませんが、外資や海外での転職を考えるビジネスマンにとっては20万や30万だしてもお釣りがくるトレーニングだと思いました。次の課題としてはどうやって商業的な成功を収めるのかと思っています。

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

<本文>

やっと今週からCombatEngineの自作に取り掛かれます。ブログの名前も今週からMyCombatEngineの作成に変更しました。

いつもならバグ直しから始めるのですが、早く自前のCombatEngineを作成したいので、今週はバグ直しはなしで始めます。

1. CombatEngineの改良

1. CombatUIの直し

CombatUIのwidgetを以下の様に直しました。

f:id:kazuhironagai77:20200614230832p:plain

こんな感じで表示されます。

f:id:kazuhironagai77:20200614230911p:plain

2. CombatUIの青色のボックス内にコメントを表示させる。

以下の文章を青色のtext blockに表示させます。

f:id:kazuhironagai77:20200614230952p:plain

どうやってテキストに文字を表示させていたのか忘れてしまったのでちょっと復習します。

f:id:kazuhironagai77:20200614231029p:plain

これを見るとNPCDialog2からテキストを参照して表示していますね。その元のNPCDialog2はどこにあるのでしょうか?

f:id:kazuhironagai77:20200614231056p:plain

ありました。このWidgetの中です。

f:id:kazuhironagai77:20200614231121p:plain

うん。大体分かりました。これに今週はこれに沿って作成します。

まず、BlueprintImplementableEventで関数を作成します。

f:id:kazuhironagai77:20200614231146p:plain

以下に示すようにこの関数がBeginMakeDeiciion()関数が呼ばれた時に呼ばれるようにセットします。

f:id:kazuhironagai77:20200614231205p:plain

以下に示すようにCombatUIのBP内でこの関数、BeginMakeDecisionStart()関数を実装します。

f:id:kazuhironagai77:20200614231227p:plain

f:id:kazuhironagai77:20200614231244p:plain

テストします。

以下のように表示されました。

f:id:kazuhironagai77:20200614231332p:plain

一応、考えた通りに表示されています。shift+enterを使用する事で改行も出来ました(このサイトを参照)。

BlueprintImplementableEventで作成した関数は、どのBPからでも呼び出せるのでしょうか?

GameCharacterクラス内にBlueprintImplementableEventの特性を持つ関数を作り、その実装をBP内で出来たら作成がかなり楽になります。

ただしGameCharacterクラス自体にはBPはありません。

このサイトによれば、

f:id:kazuhironagai77:20200614231402p:plain

BlueprintかLevelのBlueprintで実装出来るとあります。

試してみます。

色々試しましたが、UE4C++から派生したBPからしか呼べないみたいです。

それよりもRPGGameModeBaseBP内に書いたコードが全く実行されません。勿論、RPGGameModeBaseBPをGameMode にセットしています。

f:id:kazuhironagai77:20200614231426p:plain

うーん。RPGGameModeBaseクラス内にBlueprintImplementableEventの特性を持つ関数を作成してRPGGameModeBaseBPと他のBPとコミュニケーションを取ろうと思っていたのですが…。

ダメ元で試してみます。

f:id:kazuhironagai77:20200614231447p:plain

f:id:kazuhironagai77:20200614231454p:plain

f:id:kazuhironagai77:20200614231503p:plain

テストします。

f:id:kazuhironagai77:20200614231527p:plain

あれ?出来ました。

RPGGameModeBaseクラスのBeginPlay()関数とTick()関数にはUFUNCTION()が付いていないし、実装でもSuper()を使用していないので、

f:id:kazuhironagai77:20200614231547p:plain

それらが原因でBP内のコードが実行されないのかもと思い、ひょっとしたらRPGGameModeBaseクラスのBeginPlay()関数から呼ばれた関数の場合は、BPで実装されていても実行されるかもと思いました。

それで試してみたのですが、この考え方が正しいのかどうかは分かりませんが、兎に角動きました。

GameCharacterクラス内にRPGGameModeBaseの変数を作成してそこから、BlueprintImplementableEventの特性を持つ関数を呼び出す事で、変則的ですが、GameCharacterクラスのそれぞれの関数が呼ばれた時にCombatUIのBP内のコメント欄に反映する事が出来そうです。

3. GameCharacterクラスからRPGGameModeBaseクラスのBlueprintImplementableEventの特性を持つ関数を呼び出す。

最初の問題は、RPGGameModeBaseクラスはGameCharacter.hをインクルードしているので、GameCharacter.hでRPGGameModeBase.hをインクルードするとcircular dependencyに成ってしまう事です。

以下に示すようにGameCharacter.hで

f:id:kazuhironagai77:20200614231625p:plain

Forward declarationをしてGameCharacter.cpp内で

f:id:kazuhironagai77:20200614231644p:plain

インクルードしました。

何故、RPGGameModeBase.hをGameCharacter.hでインクルードしなかったのかと言うと、それをするとbuildした時にCircular dependencyでエラーになったからです。今まで、散々、interfaceの時のcircular dependencyはForward declarationとインクルードを同時にヘッダーファイルでやっても勝手にcompilerが判断してcircular dependencyを回避しつつインクルードもしてくれるみたいだ。と言っていたのですが、今回のケースは全くそう言う事は起きなかったです。

うーん。良く分かりませんね。

来週考えます。

RPGGameModeBaseクラスのtestCombat()で以下に示すように敵のモンスターをGameCharacterクラスのコンストラクターを使用して作成していますが、

f:id:kazuhironagai77:20200614231706p:plain

良く見ると、RPGGameModeBaseのインスタンスをパスしています。

のでGameCharacterクラスのCreateEnemyMoster()関数内に、以下に示したコードを追加しました。

f:id:kazuhironagai77:20200614231808p:plain

テストしますと、

f:id:kazuhironagai77:20200614231831p:plain

RPGGameModeBaseクラスのBlueprintImplementableEventの特性を持つ関数、TestBlueprintImplementableEvent()が見事に実行されています。

4. RPGGameModeBaseクラスのTestBlueprintImplementableEvent()を実装してCombatUIの青色のコメント欄に文字を表示させる。

色々試したのですが、以下の方法で出来ました。

f:id:kazuhironagai77:20200614231909p:plain

GetGameMode()関数を使用してRPGGameModeBaseを獲得する。

そこからTestBlueprintImplementableEvent()関数を呼び出す。

例えばRPGGameModeBaseの変数をGameCharacter.hで宣言するとTestCombat()関数を実行するとエラーになりエディターがクラッシュします。

実装は以下に示したように行いました。

f:id:kazuhironagai77:20200614231935p:plain

結果は、

f:id:kazuhironagai77:20200614231956p:plain

となり、GameCharacterクラスのBeginMakeDecision()関数からRPGGameModeBaseクラスのTestBlueprintImplementableEvent()関数を呼び出す事に成功しました。

このやり方が、最も一般性がありそうです。このやり方で統一します。

5. UIwidgetの青色のコメント欄に以下のようなコメントを表示させる。

f:id:kazuhironagai77:20200614232052p:plain

RPGGameModeBase.h内に以下の関数を宣言しました。

f:id:kazuhironagai77:20200614232110p:plain

それぞれの関数をGameCharacterクラス内の関数から呼び出します。

f:id:kazuhironagai77:20200614232130p:plain

f:id:kazuhironagai77:20200614232138p:plain

f:id:kazuhironagai77:20200614232148p:plain

f:id:kazuhironagai77:20200614232155p:plain

更に、RPGGameModeBaseBP内でそれぞれの関数を実装します。

f:id:kazuhironagai77:20200614232215p:plain

f:id:kazuhironagai77:20200614232224p:plain

f:id:kazuhironagai77:20200614232234p:plain

f:id:kazuhironagai77:20200614232241p:plain

結果を示します。

f:id:kazuhironagai77:20200614232303p:plain

やっぱり、4.のやり方の方が見た目が良いですね。ただまだ追加しなければならない機能が2つあります。

まず、名前が表示されていません。

コメントも次から次へと表示されるので、プレイヤーが読む時間がありません。

これらの機能を作成していきましょう。

6. UIwidgetの青色のコメント欄のコメントに名前を表示させる。

どうやって表示させようか考えていたら、既にUIで名前を表示していました。

f:id:kazuhironagai77:20200614232329p:plain

これらがどうやって表示したのかを見ると、

f:id:kazuhironagai77:20200614232348p:plain

f:id:kazuhironagai77:20200614232356p:plain

単にパラメーターとしてパスしているだけでした。

同じ方法でやってみます。

f:id:kazuhironagai77:20200614232414p:plain

f:id:kazuhironagai77:20200614232422p:plain

取りあえず、一個だけパラメーターにGameCharacterを追加しました。

f:id:kazuhironagai77:20200614232443p:plain

BPの方での実装はこんな感じです。よく考えたらパスされたGameCharacterは攻撃されるターゲットではなくて攻撃する側でしたね。名前をselectedCharacterに変更しました。

f:id:kazuhironagai77:20200614232516p:plain

うん。良さそうですね。残りの関数も同じように改良します。

f:id:kazuhironagai77:20200614232533p:plain

いい感じで表示されていますね。

7. UIwidgetの青色のコメント欄に新しいコメントが表示されたら、プレイヤーがクリックするまで次のコメントは表示しないで待機する。

色々考えたんですが、結構難しいです。

取りあえずGameCharacterクラスのMakeDecision()関数の返り値が

f:id:kazuhironagai77:20200614232607p:plain

UIwidgetの青色のコメント欄内にコメントが表示された後にtrueになるように変更してみます。

GameCharacterクラス内に以下のコードを追加します。

f:id:kazuhironagai77:20200614232657p:plain

f:id:kazuhironagai77:20200614232710p:plain

f:id:kazuhironagai77:20200614232719p:plain

f:id:kazuhironagai77:20200614232729p:plain

RPGGameModeBase内でReportTypingFinished()関数を呼び出す関数を作成します。

f:id:kazuhironagai77:20200614232751p:plain

f:id:kazuhironagai77:20200614232758p:plain

この関数を今度はRPGGameModeBaseBPから呼び出します。

f:id:kazuhironagai77:20200614232825p:plain

Event MakeDecisionの最後に付けました。更にDelayを1秒にセットしたので、結構ゆっくりと表示されるはずです。

f:id:kazuhironagai77:20200614232848p:plain

ああつ。全然想像と違う結果が!

後、textboxって文章が多くなると勝手にスクロールしてくれると思っていたのですが、しませんね。

何か難しい事を考えたくない気分なので今回はここで止めて来週また挑戦します。

余った時間は何か簡単な事をする事にします。

2. Fontについて

f:id:kazuhironagai77:20200614232921p:plain

今利用しているFontはRobotoというやつです。UE4に付属のFontだと思いますが確信はないです。

このサイトによると

f:id:kazuhironagai77:20200614232938p:plain

勝手に使って良いみたいですね。

3. まとめと感想

たまには早く終わらせるのも悪くないので今週はここまでとします。

4. おまけ

1.6が出来ないのが納得出来なかったのでもう一回だけ試してみたら出来ちゃったのでここに記録しておきます。

GameCharacterクラスに二つのBoolean変数を追加します。

f:id:kazuhironagai77:20200614233024p:plain

BeginMakeDecision()関数内でその二つの関数にそれぞれfalseとtrueをアサインします。

f:id:kazuhironagai77:20200614233042p:plain

その二つの変数を使用してMakeDecision()関数を以下のように改良しました。

f:id:kazuhironagai77:20200614233104p:plain

まず、プレイヤーが行動を決定してtmpResult変数がtrueになると、一回だけテキストを表示するための関数ReportMakeDecision()が呼ばれます。呼ばれますがこのMakeDecision()関数はTrueは返しません。このMakeDecision()関数がtrueを返すためには、以下に示すhelper関数であるTextFinishTyping()を呼ぶ必要があります。

f:id:kazuhironagai77:20200614233128p:plain

このTextFinishTyping()関数はRPGGameModeBaseクラスの関数、TextTypingDone()によって呼ばれます。

f:id:kazuhironagai77:20200614233150p:plain

以下に示すようにこのRPGGameModeBaseクラスの関数、TextTypingDone()はBPから呼ぶ事が出来ます。

f:id:kazuhironagai77:20200614233221p:plain

以下に示すようにCombatUIのwidgetに読みましたボタンを追加しました。

f:id:kazuhironagai77:20200614233244p:plain

このボタンをクリックすると、Event DispatcherであるConfirmButtonIsClickedが呼ばれます。

f:id:kazuhironagai77:20200614233302p:plain

それをReportMakeDecision()関数の最後、Textをタイプし終わった後、バインドし、更にTextTypingDone()を呼ぶようにします。

f:id:kazuhironagai77:20200614233322p:plain

以下にテストの結果を示します。

f:id:kazuhironagai77:20200614233402p:plain

最初はこれだけが表示されています。

f:id:kazuhironagai77:20200614233422p:plain

攻撃をクリックしゴブリンをクリックすると

f:id:kazuhironagai77:20200614233440p:plain

と表示されそのままストップしています。

f:id:kazuhironagai77:20200614233458p:plain

をクリックすると

f:id:kazuhironagai77:20200614233518p:plain

が表示され、また一旦停止しました。

もう一度、読みましたボタンをクリックすると

f:id:kazuhironagai77:20200614233559p:plain

次のアクションのセリフが表示され戦闘が開始したのが分かりました。

ただし、文字がテキストに一杯になった後は、セリフが表示されていないみたいです。それは来週直します。