UE4の勉強記録

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

「Unreal Engine4.xを使用してRPGを作成する」の足りない部分を作成する。日本語化など

<前文>

f:id:kazuhironagai77:20191027202819p:plain

Google Stadiaのサービスが米国で開始されましたが、ゲーマーの方からこれ以上ないほど酷評されています。そう言えばUE4を作成したEpic game社もゲームを独占販売するので大変な批判を受けているようですね。新しく販売されたポケモンも非難の嵐です。

私は、ゲームは全くといってもいいほどやらないので、これらの批判が的を得ているのかどうか全く分かりません。しかしUE4を勉強して少しだけ分かった事もあります。ゲーマーの方の批判の中には、揉め事が大好きで問題を起こすために批判している人もいれば、真剣に忠告している人もいると言う事です。この真剣に忠告している人の意見は聞かなければいけません。しかし大体において真剣に忠告している人の声は小さく、良く聞こえないものです。

どうすれば、真剣に忠告してくれる人の意見を聞き取る事が出来るでしょうか?

データサイエンスに批判的な私ですら、データサイエンスを駆使すれば、真剣に忠告してくれる人の意見のみを抽出する事が可能な気がします。

これってかなり正しい方法だと思われます。同時に、問題を起こすために批判している人も抽出出来きて、それに対する対応も出来るからです。

うーん。やっぱりデータサイエンスも勉強しようかな。と思うこの頃です。

それでは、勉強を始めましょう。

<本文>

1.言語の日本語化

今週は特に何をやるのか決めていなかったので、まず日本語化から始めます。

UIの英語を全て日本語に変換します。

f:id:kazuhironagai77:20191124220132p:plain

f:id:kazuhironagai77:20191124220142p:plain

f:id:kazuhironagai77:20191124220151p:plain

店主のセリフが二か所に保存されていたのですが、理由が分かりませんね。一応全部日本語に変換出来たはずです。

2.店主のセリフを増やす

店主のセリフがどのように決定しているのか忘れてしまったのでもう一度調べ直します。

f:id:kazuhironagai77:20191124220219p:plain

この二つのUIが店主のセリフがあったUIです。よく見たら両方とも、NPC_Parentから派生したクラスでした。

f:id:kazuhironagai77:20191124220244p:plain

NPC_Parentクラスを開いて見ると、

f:id:kazuhironagai77:20191124220305p:plain

NPCDialog変数のみがあるクラスでした。

と言う事はここで店主のセリフを増やす事が出来そうです。

f:id:kazuhironagai77:20191124220335p:plain

これをそれぞれの土地にいる店主にしゃべらせればいい訳です。

まず店主のメッシュを変えたいですが、Unreal Engine 4のマーケットプレイスのキャラクターを全部見たのですが、店主にふさわしいキャラクターはありませんでした。しょうがないのでダウンロードしたModularRPGHeroesPolyartから選びます。

f:id:kazuhironagai77:20191124220359p:plain

これなんかどうでしょうか?商人と強弁すれば商人に見えなくもないです。

f:id:kazuhironagai77:20191124220430p:plain

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

f:id:kazuhironagai77:20191124220453p:plain

会話するとこんな感じです。

店主はそれぞれの島に一人ずつ居ますが、今は全部同じです。これをそれぞれ別人にしたいです。

まず、どうやって店主との会話が行われているのかを確認します。

以下にShopOwnerのevent graphを示します。

f:id:kazuhironagai77:20191124220515p:plain

指定したボックス内にプレイヤーが侵入した場合に、RPGGameInstanceクラスにあるブーリアン変数TalkShopをTrueに指定しているだけですね。

RPGGameInstanceのヘッダーファイルを見てみます。

f:id:kazuhironagai77:20191124220536p:plain

EditDefaultsOnlyですね。と言う事はこの変数はクラス全体で一個しか持てないと言う事ですね。

Project全体で他にTalkShopを使用している箇所を探したのですが見つかりませんでした。恐らくTalkShopを使用した店主との会話はブループリント内で設定されているのでしょう。

今度は、BP内でTalkShopを検索しました。ありました。なんと、レベルのBP内で使用していました。

f:id:kazuhironagai77:20191124220612p:plain

なるほど。プレイヤーがEを押した時にTalkShopがTrueならばShop Welcomeウィジェットを表示するように設定してます。これならばわざわざ、ShopOwner を変えなくても、それぞれのレベル上のBPで改変したShop Welcomeウィジェットを表示すれば良い訳ですね。ただ、そのためには改変したShop Welcomeウィジェットをもう二つほど作成する必要がありますね。

やってみます。

その前に、NPC_parentウィジェット内のNPCDialogを三つに分割します。

f:id:kazuhironagai77:20191124220718p:plain

それぞれに、セリフを分割します。

f:id:kazuhironagai77:20191124220740p:plain

Shop Welcomeからアクセスします。

f:id:kazuhironagai77:20191124220809p:plain

あれ。出来ませんね。

f:id:kazuhironagai77:20191124220832p:plain

何か警告みたいなのも出ています。

この方法は駄目みたいですね。

戻します。

f:id:kazuhironagai77:20191124220857p:plain

全部のセリフをNPCDialogに詰め込みました。今度は子クラスであるShop Welcomeからもアクセス出来ます。ただし、

f:id:kazuhironagai77:20191124220930p:plain

この警告はまだ出ていますね。

うーん。良く分かりませんね。でもこの警告は今回の親クラスで変数を追加した事と関係なさそうですね。

NPC_parentウィジェット内で複数の変数で整理出来ないと後で、結構面倒な事になりそうです。なので原因を解明するためにもう少し検討します。

今度は何の問題もなく子クラスであるShop Welcomeからもアクセス出来ました。

f:id:kazuhironagai77:20191124221000p:plain

何だったんでしょうか?

前回は単にNPCDialogをduplicateしたのがいけなかったのでしょうか?もしかしたらC++で言うshallow copyみたいなのが起きたのかもしれません。が本当の事は分かりません。

テストします。

f:id:kazuhironagai77:20191124221025p:plain

キチンと表示はされましたが、字がはみ出しています。

Shift+Enterで改行出来るそうです。

f:id:kazuhironagai77:20191124221121p:plain

f:id:kazuhironagai77:20191124221131p:plain

出来ました。

Map3にいる店主のセリフも変更します。

f:id:kazuhironagai77:20191124221159p:plain

f:id:kazuhironagai77:20191124221208p:plain

一応出来ました。

これを応用すれば、それぞれの店で売っている道具も変更出来ますね。

3.武器を増やす。

今、短剣(小)と短剣(大)しかありません。もう少し武器の種類を増やします。ModularRPGHeroesPolyartにある武器と防具を全部加えましょう。

f:id:kazuhironagai77:20191124221240p:plain

とありました。それぞれに対応する名前も考えてみました。

  • 矢1:矢(初心者向け)
  • 矢2:矢(上級者向け)
  • 斧:オノ
  • 弓1:弓(初心者向け)
  • 弓2:弓(上級者向け)
  • ハンマー
  • 盾1:木の盾(初心者向け)
  • 盾2:木の盾(上級者向け)
  • 盾3:鉄の盾
  • 盾4:騎士の盾
  • 盾5:王の盾
  • 剣1:短剣(小)
  • 剣2:短剣(大)
  • 剣3:剣
  • 剣4:長剣
  • 杖1:魔法の杖(初心者向け)
  • 杖2:魔法の杖(上級者向け)

以下に示すように、Weaponに登録しました。

f:id:kazuhironagai77:20191124221533p:plain

こんな感じに表示されています。

f:id:kazuhironagai77:20191124221605p:plain

今週はこれで終りです。

<おまけ>

https://docs.unrealengine.com/en-US/Programming/Introduction/index.html

のMemory Management and Garbage Collectionに前々から疑問に思っていたUEC++におけるガーベージコレクション(garbage collection)についての分かり易い説明がされていたのでここにまとめます。

f:id:kazuhironagai77:20191124221639p:plain

上記の説明を、自分なりの理解でまとめると、「UE4C++のガーベージコレクション(garbage collection)は、ルートセット(root set)と呼ばれる方法で管理されています。ルートセット(root set)は、オブジェクトのリストです。このリストに載っているオブジェクトは決してガーベージコレクター(garbage collector)によって消される事はありません。逆に言えば、あらゆるUE4C++の変数はこのリストに載っていない限り、何時でもガーベージコレクター(garbage collector)によって消されてしまう可能性があります。」となります。

f:id:kazuhironagai77:20191124221702p:plain

UE4C++のオブジェクトを、そのルートセット(root set)内のリストに載せるためには、

  1. UPROPERTY()を宣言時に使用する。
  2. UE4 Container(TArrayなど)を使用する。

のどちらかを使用する必要があります。

以下に簡単な例を示します。

f:id:kazuhironagai77:20191124221758p:plain

f:id:kazuhironagai77:20191124221805p:plain

DoomedObjectはUObjectから派生したMYGCTypeクラスから作成したオブジェクトです。しかし上記の初期化ですと、UPROPERTY()を指定していないので、(勿論containerも使用していません。)ルートセット(root set)内のリストにDoomedObjectは登録されません。登録されないので、ガーベージコレクター(garbage collector)が起動された時に、このオブジェクトは消されてしまいます。

1.アクター(Actor)とガーベージコレクション(Garbage Collection)

アクタークラスは少し特別で、UPROPERTY() で指定やContainerを使用しなくても、ルートセット(root set)内のリストに自動的に登録されます。これらの登録されたアクターはそのレベルが消滅するまで存在し続けます。アクターをそのアクターが存在しているレベルが消滅するより先に破壊するには、Destroy()関数を呼ぶ必要があります。

f:id:kazuhironagai77:20191124221839p:plain

AActorより

以下にActorクラスから派生したクラス内の変数がdangling pointerになってしまう例を紹介します。

f:id:kazuhironagai77:20191124221923p:plain

DoomedObjectはUPROPERTY()で指定していないので、ルートセット(root set)内のリストに登録されません。のでDoomedObjectが指しているアドレスはガーベージコレクター(garbage collector)によって消去されてしまいます。しかしAMyActorはAActorクラスの派生クラスなのでそのオブジェクトは自然にルートセット(root set)内のリストに登録されます。のでその変数であるDoomedObjectはガーベージコレクター(garbage collector)によって消去されたアドレスを指し続ける事になります。

2.UStructについて

f:id:kazuhironagai77:20191124222017p:plain

UStructはガーベージコレクター(garbage collector)によって集められることはありません。もしUStructを動的に作成する時は、スマートポインターの使用を進めます。

だそうです。

3.普通のC++クラス内でUObjectを使用する場合

普通のC++のクラス内で使用されるUObjectの派生クラスをルートセット(root set)内のリストに登録する事も出来ます。FGCObject、AddReferencedObjects、並びにFReferenceCollectorを使用します。

以下に例を示します。

f:id:kazuhironagai77:20191124222148p:plain

以上です。

大体これで今まであやふやだったUPROPERTY()とガーベージコレクション(garbage collection)の関係がはっきりしました。