UE4の勉強記録

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

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

f:id:kazuhironagai77:20210214215522p:plain

<前文>

Genocide そして進撃の巨人 Final Season

日本で有名なYouTuberの方が海外に移住するらしいですが、逆に英語圏で有名なYouTuberが日本に移住したりもしていて「Internetで世界は一つの村に成る。」との予言は正しかったんだなと思いました。

それはともかく、日本に移住した英語圏の人達の最初の難関は、市役所への転入の書類の提出だそうです。これに保険証の申請やら何やらで、全部自分でしなければならない場合は、ほとんど不可能らしいです。そしてこれは日本人の間でも有名ですが、外国人が日本でアパートを借りるのは相当大変みたいですね。アメリカ人の間では、一軒家を買ってしまう方が遥かに簡単と、一軒家購入の進めみたいなのまであります。

そんな大変な思いをして日本に移住したのに、2年も経つと自分の期待していた日本と現実の日本の違いに絶望するらしいです。そんなに日本の暮らしって悪いのかと話しを聞くと「2年も日本に住んでいたのに日本人の友達、一人も出来なかった。」とか「日本で暮らした時の最高の思い出は、スタミナ太郎の食い放題。」とか、それは日本人でも絶望するでしょう。みたいな悲惨な経験を語って来ます。

でもこれ日本人が海外に行っても同じ事です。特に、親戚もいない、その国の言語もしゃべれない。ましてや風習や宗教も知らない国に行ったら、相当悲惨な目に合うのは間違いないでしょう。

それでも私は、日本人は海外に一時でも暮らしてみるべきだと非常に強く思っています。

その理由は、幾つかありますが、そのうちの一つは世界の常識と日本の常識があまりに乖離している事が実感出来るからです。

その例の一つがGenocide です。

世界にはGenocideが普通に存在しています。Genocideは日本語に訳すと虐殺で、英語のMassacreと同じ意味に成ってしまいます。しかし、この二つの単語の意味は、全く違います。Massacreは沢山の人を殺す事です。それは酷い事ですが、Genocideに比べるとその悪意は、たかが知れるレベルで、人類史の前では取るに足らない軽犯罪です。

しかしGenocideは全く違います。Genocideとは、ある民族全体を絶滅させる事です。海外に出ると直ぐに分かるのですが、日本民族を絶滅させたいと思っている人々は沢山います。とてつもない悪意をもって日本民族を絶滅させたいと思っている人達がですよ。実際にいるんです。それも一つの思想として根付いているんです。こういう人達に実際に出会うだけでも、海外に住む価値があると思うんです。

アメリカに長く暮らしていた私は、一部のアメリカ人が日本民族に対してGenocideをほのめかす時、冗談で言ってない事に直ぐにピンと来ます。

彼らにとって日本民族が消滅してほしい理由は大きく二つあります。

勿論、全部のアメリカ人がそう思っている訳ではないですが、概念としてのGenocideは普遍的に存在していています。何かあると必ずその邪魔な民族、全滅出来ないかと考えるのは日本人以外にとっては、普通の事なんです。

最近、Capitol Riotを含む国内テロリズムの原因として、〇ox News のAnchorを含む保守派のコメンテーターらが超高額の訴訟を起こされています。その事自体はザマァーですが、その起訴の内容は、昨年の大統領選挙の投票結果に対して嘘を広めた事です。

所が、彼らが嘘をついていたのは昔からなのです。みんな彼らが嘘を言っているのは知っていたんです。その彼らの嘘を元に、メキシコとの国境に壁を立てたり、中国からの輸入品にとてつもない関税を付けたり、日本にアメリカ国内では使用が禁止されている発癌性の農薬を使用した果物を輸出したりした時は、今、彼らに対して激怒しているアメリカ人も一緒になってゲラゲラ笑っていたんですよ。

日本を含めて、これらの国はその生存をアメリカとの貿易に依存しています。それらの国に対して嘘を元に貿易戦争を仕掛けるのは、その国の民族に対して、暗にGenocideを実行しているのと同じ事です。

しかし他民族がGenocideされる分には、ほとんどのアメリカ人にとっては笑い事で済んでしまう事なんです。今、アメリカ人が彼らに対して激怒しているのは、自分たちが彼らの嘘のせいでコロナによって死ぬ可能性が出て来たからです。

こういう事を肌で感じれる様になる経験をする事は全ての日本人にとって大切だと思います。

そして進撃の巨人Final seasonです。

進撃の巨人Final seasonはまさしくGenocideがテーマの作品なんです。だからGenocideの思想がない日本ではそんなにヒットしていないですが、それが普遍的に存在している海外では、あんなに受けているです。

今週は、これについて語ろうと思ったのですが前文が既に長くなりすぎてしまったので、残りは来週にします。

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

<本文>

1.今週の予定

やっとですが、今週からSave機能をもう一度作り直します。予定としては以下の順番でやろうと思っています。

  1. Blogなどで今まで作成したSave機能の復習をする。
  2. Saveしなければならないデータの確認。
  3. データ以外のSaveに必要な要素の確認 (ゲーム内)
    • セーブ出来る場所の決定
    • Loadした後に倒したモンスターは復活するのか?
  4. データ以外のSaveに必要な要素の確認 Part 2 (ゲーム外)
    • セーブデータの保存場所
    • セーブデータの暗号化、
    • Serverに保存する場合の方法について
  5. Save機能のTutorialを復習する。
  6. 実際の作成

2.今まで作成したSave機能の復習

以下のブログでSaveについて書いてありました。

それ以外のブログはSave機能について勉強するといってやってませんでした。Save機能を作成する前に、Saveするデータが揃う必要があったので、実際はあんまり勉強しなかったんです。思い出しました。

2.1 2019-09-22のブログの復習

本文と関係ないですけど、前文でこの統計学の本読んだら、今までよく意味が分からなかった統計学の意味が分かった。と書いていますが、今考えるとこの本読んでも、統計学の本質は理解していませんでした。

今は理解しています。

統計学は確率の裏返しです。

これだけ分かれば後は計算方法だけ理解すれば良いんです。

UE4のSave機能の作成部分ですが、教科書(「Unreal Engine 4.xを使用してRPGを作成する」)の10章を勉強していて、その中でSave機能の作成方法を勉強したようです。

具体的には、

Save機能の作成方法

  1. SaveGameクラスから派生したクラスを作成。
  2. そのクラスにsaveしたいデータが保持出来る変数を作成。
  3. Saveボタンを押したらそのクラスのオブジェクトを作成してその変数に値を追加。
  4. SaveGameToSlotノードを使用してそのオブジェクトをSlotに保存。

を行っています。更に

Load機能の作成方法

  1. DoesSaveGameExitノードでSlot内にSaveしたGameDataがあるのか調べる。
  2. 在る場合はそのデータを、LoadFromSlotノードでゲーム内にロード。
  3. ロードしたデータをGameInstanceなどの変数にセット。

を行っていました。

やり方自体に特にコメントはありません。正攻法だと思います。

一個だけちょっとおかしいかもと思う箇所が以下の部分ですが、

f:id:kazuhironagai77:20210214215756p:plain

Slotのobjectを保持する必要はあんまりない気がします。もし保持したいならその後のNewSameGameにCastしたobjectを保持した方が良い気がします。

2.2 2019-10-20のブログの復習

この回のブログでは、2019-09-22でSaveの作成方法を初めて勉強したので、その時に学習したSaveGameBPノードから一般的なUE4のSaveの作成方法を調査しています。

更に

  • Loadのやり方が分からない。
  • 複数のSaveDataの保存方法が分からない。

と書かれていて、その解答を見つけるためにSaveGameBPノードの調査をすると書かれていました。

Loadのやり方は、2019-09-22で既に解説されていましたが、この時は良く分かっていなかったのでしょうね。

複数のSaveDataの作成は単にSaveGameBPのobjectを沢山作成してそれぞれSlotにSaveすれば良いと思います。ただ今の私の考えでは複数のSave Dataを作成出来るとゲームが面白く無くなるので、Saveは一回しか出来ない様にするつもりです。

以下の二つのサイトで勉強していました。

これらのサイトは今週、もう一度勉強し直します。

2.3 2020-07-26のブログの復習

ここでは、ほぼ現状のSave機能の作成内容について説明しています。流石に半年前のブログだと今読んでもかなり勉強になる内容が書かれていて読んでて唸ってしまいました。

大切だと思う事だけここに抜き出します。

  • SaveGameクラスにGameInstanceの変数を作成してGameInstanceそのものをSlotに保存しようとしたら、load出来なかった。Shallow Copyになっているみたい。
  • GameInstanceクラスにある変数を一つ一つSaveGameクラスの変数として作成して保存しようとしたら、GameInstanceクラスにある変数は全て、BlueprintReadOnlyで指定されていてLoad時に値を代入する事が出来なかった。
  • UEC++からSaveGameクラスの派生クラスを作成してそこから、GameInstanceクラスにある変数の値をSaveGameクラスの変数に保存したり、SaveGameクラスの変数の値をGameInstanceクラスにある変数に代入したり出来るようにした。

SaveGameに作成する変数の値が、Shallow copyに成っていないかの確認が必要である事。そしてGameInstanceクラスにある変数は全てBlueprintReadOnlyで指定したためにUE4C++側にSave, Load機能を作成する必要がある事。この二つは今回、新たにSave機能を作成する時にも気を付けなければならない要素です。

一つだけ問題だと思うのがSaveGameクラスの変数の値をGameInstanceクラスにある変数に代入するための関数ですが、

f:id:kazuhironagai77:20210214215838p:plain

このやり方だと、mySlotと言う名前のSlotが存在しない時はErrorになる気がします。実際のコードを改良する時、この個所はしっかり考えて直します。

2.4 ブログの復習のまとめ

大体、今までやった内容は理解出来ました。GameInstanceクラスにある変数を全てBlueprintReadOnlyで指定したためにUE4C++側でSave、Loadの処理をしなければならない以外は正攻法でSave、Load機能を作成していると思います。

Slotに保持出来る変数がShallow copyになっていないかの確認が必要な事はすっかり忘れていました。

昔書いたブログを読み直すのは恥ずかしいですが、こうやって記録を付けておくと後で簡単に復習出来るので、大変便利です。ブログを書く事の大切さをもう一回確認出来ました。

3. Saveしなければならないデータの確認

RPGGameInstanceクラス内の全ての変数をSaveすれば良いはずです。もしかしたら漏れがあるかもしれませんが、取りあえずそれからやって見ます。

3.1 RPGGameInstanceBP内の変数

BP内だけで以下の変数が作成されていました。どの変数を何のために使用したのか全く覚えていません。

f:id:kazuhironagai77:20210214215922p:plain

一個ずつ確認していきます。

<Map>

クラス:Map(調べたら自作したEnumクラスでした。)

f:id:kazuhironagai77:20210214220012p:plain

ワープして別のMapに移動するために使用されるはずです。

Loadする時にどのMapから始めるのかを記録しておく必要があるので保存する必要がある変数と思われます。

<Zone>

クラス:Zone(Enumクラス)

f:id:kazuhironagai77:20210214220047p:plain

ワープした時にどの地点に出現するかを指定する関数です。この場所を敢えてSaveする必要なないと思われます。

<warped

クラス:Bool

ワープした時に使用される関数であるのは確かですが、何のために使用するのか全く覚えていません。調べます。

検索したらウィジェットであるw_map, とLevelであるmap1, map2, map3で使用されていました。

f:id:kazuhironagai77:20210214220116p:plain

この感じからするとLevelであるmap1, map2, map3は全く同じ使用をされていると思われます。

まずウィジェットであるw_mapを見てみます。

まずデザインですが、世界地図の上にボタンが散りばめられています。

f:id:kazuhironagai77:20210214220138p:plain

それらのボタンを押すと以下に示した様に関数、ChangeMapが呼ばれます。

f:id:kazuhironagai77:20210214220155p:plain

ChangeMap関数内の実装ですが、その中で、warpedがTrueにセットされました。

f:id:kazuhironagai77:20210214220213p:plain

このノードにChangeMap関数があります。その関数は呼ばれると指定されたMapを新たに開きます。

ので、Map1が開かれたと仮定してMap1のLevel BPを見てみます。

Event Begin Play関数の一番最後で、WarpedをFalseにセットしているだけでした。

f:id:kazuhironagai77:20210214220232p:plain

この変数は、全くSaveする必要はないですね。そればかりがワープ機能にも要らない可能性もある気がしています。後でこの変数が本当に必要か調べます。

<DroppedItem

クラス:Bool

何に使用している関数なのか全く覚えていません。調べます。

検索したら沢山の似た名前の変数が引っかかってしまいました。

検索の最初に出て来たDroppedItemBaseクラスから調べて見ます。

f:id:kazuhironagai77:20210214220254p:plain

DroppedItemBaseクラスを以下に示します。

f:id:kazuhironagai77:20210214220311p:plain

分かりました。マップに配置されているアイテムを表示するためのActorクラスです。

Box内にplayerが操作するキャラが侵入するとTrue、出るとFalseにセットしています。

f:id:kazuhironagai77:20210214220327p:plain

これだけでは何のための変数か分かりませんね。もう少し調べます。

PickUpItemクラスでも使用されています。

f:id:kazuhironagai77:20210214220703p:plain

PickUpItemクラスの方も調べて見ます。

まず、PickUpItemクラスはウィジェットでした。

f:id:kazuhironagai77:20210214220726p:plain

これの拾うボタンと戻るボタンを押した時に呼ばれていますが、マジで意味不明です。

f:id:kazuhironagai77:20210214220744p:plain

これ以外には使用されていませんでした。

ひっとすると昔は何かに使用していたのですが、Itemを拾う機能を改善している内に要らなくなった変数かもしれません。

後でこの変数が本当に必要か調べ要らないようなら削除します。

勿論、Saveする必要はありません。

<Dropped Item Content

クラス:Dropped Item Base

以下のクラスで使用されています。

f:id:kazuhironagai77:20210214220811p:plain

ちょっと不思議な点があります。

まずDroppedItemBaseクラスがDroppedItemBaseクラス内で使用されています。更にSetばかりでGetに使用しているのがThirdPersonCharacterBPのみです。

DroppedItemBaseクラスから見てみます。

Box内にPlayerのキャラが侵入したら自身をセットしています。

f:id:kazuhironagai77:20210214220849p:plain

Box内にPlayerのキャラが去ったら自身のセットを解除しています。

f:id:kazuhironagai77:20210214220910p:plain

何故か全く同じ名前の変数がGameModeBaseBPにもあってそれにも同様の事をしています。

f:id:kazuhironagai77:20210214220933p:plain

次はThirdPersonCharacterBPを見てみます。

f:id:kazuhironagai77:20210214221000p:plain

これはDroppedItemBaseのボックス内にPlayerのキャラが侵入したらPickUpItemウィジェットを作成して表示させるための実装ですね。そのためにDropped Item Contentをパスしています。

分かりました。これはどのアイテムがそのボックス内に存在しているかをPickUpItemウィジェットに伝えるために使用される変数です。

確認のためにPickUpItemウィジェットも見てみます。

まず、Dropped Item ContentはMy Dropped Item と言う変数名でPickUpItemウィジェットにセットされていますので、My Dropped Itemを調べます。

アイテムを「拾う」を選択した場合です。

f:id:kazuhironagai77:20210214221029p:plain

黄色で囲った部分がMy Dropped Itemが使用されている箇所です。緑は間接的に使用されている箇所です。

一個ずつ見て行きます。

My Dropped ItemがWeaponかどうかを聞いています。

f:id:kazuhironagai77:20210214221054p:plain

Playerの保有するWeaponとItemは別なArrayで管理しているので、拾ったItemが本当のItemなのか武器なのかの確認が必要です。それをここで行っています。

しかしItemであった場合に実行すべきコードはまだ実装されていませんでした。後で作成します。

次にMy Dropped Itemの名前が本当に武器名なのか確認しています。

f:id:kazuhironagai77:20210214221113p:plain

無くてもいいかもしれませんが、念のために確認しても良い気もします。

その名前をRPGGameInstanceBPのWeapon変数に追加します。

f:id:kazuhironagai77:20210214221128p:plain

覚えていませんが、このWeapon変数はplayerの操作するキャラが保持する武器を管理する変数のようです。

確認のためにRPGGameInstanceBPの変数を見ましたが載っていません。UE4C++のRPGGameInstanceクラスで作成した様です。

f:id:kazuhironagai77:20210214221145p:plain

ありました。

f:id:kazuhironagai77:20210214221201p:plain

思い出して来ました。

この変数、BlueprintReadOnlyなんですが、Arrayだからか、Add関数を使用するとBP側からでも要素を追加出来たんで、BP内のみで新しい値を追加したんです。

このやり方が正しいのかは分かっていません。後でバグが出るかもしれないのでこのやり方でも正しいのかについても後で調べる事にします。

f:id:kazuhironagai77:20210214221229p:plain

次は以下の関数が呼ばれています。

f:id:kazuhironagai77:20210214221245p:plain

このPickUpItemウィジェット内で自作した関数でした。

簡単に説明するとGameInstance内の変数、ItemSpawnDataはそのレベル上で、何処にどんなItemをSpawnさせるのかを管理しています。

そのItemSpawnDataにこのItemはPlayerがもう獲得したのでこれからはSpawnさせないで下さいとお願いしています。

f:id:kazuhironagai77:20210214221309p:plain

このやり方よりマシな方法は絶対あると思いますが、取りあえずは望んだとおりに動くので、今回はこのままにしておきます。

後にもっとUE4のArrayの関数に詳しくなった時に復習します。

f:id:kazuhironagai77:20210214221344p:plain

My Dropped ItemをDestroy Actor関数で破壊しています。

これは今Level上に表示されているItemがこれ以上表示されないためにしたのでしょうか?多分そうですね。

最後に、My Dropped Itemではありませんが、My Dropped Item にパスされているDropped Item Content(ただしGame Instanceに保持されている方)が開放されています。

f:id:kazuhironagai77:20210214221436p:plain

正直、このやり方で開放するのが正しいのかも分かっていないですが、RPGGameInstanceのDropped Item Contentが何をしているのかは理解出来ました。

まず、この変数はSaveする必要はありません。この変数はItemを拾う時のみに必要になる変数でItemを拾う途中でSaveする事は出来ないからです。

更にGameInstanceにある必要は全くないです。RPGGameModeBaseBPにある全く同じ変数が全部対応していますのでGameInstanceのDropped Item Contentは消して良いです。

GameInstanceのDropped Item Contentは後で、もう一度、要らない事を確認したら消去します。

<Time Spend

この変数は最近作成したので覚えています。一日の内どれくらいの時間が経過したのかを記録する変数です。

一応確認だけします。

f:id:kazuhironagai77:20210214221502p:plain

Set Time Spend 0はEvent Despatcher で、Level BPと他のBPのデータのやり取りをする為に作成したものです。

Inn_Welcomeウィジェットは宿屋の管理をするウィジェットですので泊まった時は必ず朝になる必要があります。

f:id:kazuhironagai77:20210214221528p:plain

この変数をsaveする必要はありません。なぜならLoadから始める場合は、いつでも朝から始まってもオカシクないからです。

<Third Person Character Location

この辺の変数は最近作成したのでまだ覚えています。

この変数は、戦闘で別なマップに移動したプレイヤーの操作するキャラを戦闘後に元の位置に戻すための変数です。

Saveする位置がまだ決まっていませんが多分この変数をsaveする必要ないでしょう。

<Monster Spawn Data

この変数はそのレベル上で倒されたモンスターのデータも管理しています。

Loadで戻った時、倒したモンスターは再生されるのか、どうかを決める必要があります。

再生されないのならSaveする必要があります。

<Monster Name In Fighting

戦闘中に表示されるモンスターの種類を決定するための変数です。

Saveする必要はありません。

<Third Person Character Rotation

この変数も、戦闘で別なマップに移動したプレイヤーの操作するキャラを戦闘後に元の位置に戻すための変数です。

この変数はキャラの向きを保存します。

思い出しました。この変数、Meshの向きだけ変えてカメラの位置はそのまま。というバグが残っていました。

Saveする必要は多分ないでしょうね。

<Item Spawn Data

Level上に配置するItemのデータを保持しています。Playerが既に収得したアイテムについてもこの変数が管理しているので、絶対にsaveする必要があります。

RPG Game Instance BP内の変数まとめ>

Saveする必要のある変数は、

  • Map
  • Monster Spawn Data(仮)
  • Item Spawn Data

の3つだけでした。

3.2 RPGGameInstance内の変数

以下の変数があります。

f:id:kazuhironagai77:20210214221652p:plain

Talk Shop、Talk Weapon Shop、そしてTalk Inn以外の変数は全部Saveする必要があります。

Game CharacterクラスであるMyYourHeroやArrayであるItemsやWeaponsはそのままSaveしてもShallow copyになってしまうんでしょうか?その辺の確認が必要ですね。

4.データ以外のSaveに必要な要素の確認 (ゲーム内)

4 .1 セーブ出来る場所の決定

セーブ出来る場所を作成します。

NPC、神官を作成して神官のいる場所でSave出来るようにします。

NPCの作成方法を忘れてしまったので復習します。

4.1.1 NPCの作成方法

2020-10-11のブログでNPCを作成していました。これを読むとこれ以前に、NPC_Oldmanの原型を作成していますね。2020-08-23のブログで最初のNPCを作成しています。こっちから読んでいきます。

2020-08-23のブログを読むとまず、

f:id:kazuhironagai77:20210214221744p:plain

を作成しています。

今のProjectでは、

f:id:kazuhironagai77:20210214221802p:plain

と名前が違っていますが、多分これですね。

開いて見ると、Box内にplayerが侵入した時、RPGGameModeBaseBPのMyPlaceForEvents変数にNPC_Personの変数Occupationをセットしています。

f:id:kazuhironagai77:20210214221822p:plain

MyPlaceForEvents変数はRPGGameModeBaseクラスの変数で、EPlaceForEventsから作成されていました。

f:id:kazuhironagai77:20210214221852p:plain

これがEPlaceForEvents です。

f:id:kazuhironagai77:20210214221910p:plain

ここに神官を追加する必要がありますね。

この後で、ThirdPersonCharacterBPのEvent Do Somethingに行くのは覚えているのですが、どうやってここに飛ぶのかが分かりません。

f:id:kazuhironagai77:20210214221934p:plain

分かりました。Eボタンを押すんでした。

f:id:kazuhironagai77:20210214222004p:plain

f:id:kazuhironagai77:20210214222011p:plain

これは何処かに解説しておかないとUserには分からないですね。

NPCとの会話はEを押す。」を後で追加します。

Event Do SomethingではEPlaceForEvnetsのそれぞれの要素によって分岐しています。

ここに神官の場合を作成する必要があります。

f:id:kazuhironagai77:20210214222030p:plain

分岐の先はほとんど同じで作成するwidgetなどが違うだけです。

f:id:kazuhironagai77:20210214222100p:plain

神官用のWidgetの作成も必要ですね。

老人と魔法研究家のWidgetを以下に示します。

f:id:kazuhironagai77:20210214222118p:plain

f:id:kazuhironagai77:20210214222153p:plain

思い出しました。

単に別のNPCをコピーしてちょっとだけ変更して新しいNPCウィジェットを作成したんです。

後はここに表示する会話のシステムを理解すれば良いだけですね。

ここまでNPCの作成方法を復習してアレ何ですけど、神官は普通のNPCから作成するんじゃなくて武器屋、道具屋、宿屋と同じ方法で作成すべきな気がして来ました。

ここまでやっちゃったので普通のNPCの作成方法、最後まで勉強します。

会話のシステムですが、DataTableから読み込んでいます。

f:id:kazuhironagai77:20210214222215p:plain

以下に示した様なDataTableが作成されています。

f:id:kazuhironagai77:20210214222237p:plain

開いて見るとこんな感じです。

f:id:kazuhironagai77:20210214222255p:plain

思い出しました。

このEnumクラスから作成したDataTableらです。

f:id:kazuhironagai77:20210214222310p:plain

NPCのコメントをConversationに書き込み、その解答をAnswer Choiceに書き込みます。答えによって次のNPCの会話が決まるので、どのコメントを読むのか番号(Jump To Comment)で指定します。

最後に、選択するために表示されるNPCに対する返事が書かれたボタンがNPCの分だけ別なクラスで作成しないとエラーになる事を思い出しました。

f:id:kazuhironagai77:20210214222327p:plain

f:id:kazuhironagai77:20210214222336p:plain

メンドクサイですが現状直し方が分からないです。

これでほとんど完全にNPCの作成方法を思い出しました。念のためにブログをもう一回読み直します。

読み直したら、2020-10-18のブログでNPCの作成方法について逐一記録してありました。これに沿って作成すれば何も復習する必要なかったです。

4.1.2 武器屋、道具屋、宿屋の作成方法

ここまでNPCの作成方法について復習してあれですが、神官は武器屋、道具屋、宿屋と同じ方法で作成した方が良い気がしています。

こちらの作成方法についても調べます。

2020-10-04のブログに宿屋の主人の作成方法についての細かい手順が全て書かれていました。これに沿って作成すれば簡単に作れそうです。

関係ないですが、Vtuberについて前文で触れていました。

ある時からRedditでこのVtuberをアンチから擁護しようと主張するコメントは即ブロックされるので不思議に思っていたら、そのSub Reddit、そのVTuberが属している会社が運営していました。もうVtuberを見るのは止めてしまいましたが、この会社の名前を見ると反吐が出ます。表ではこのVtuberを守ると宣言してファンの信頼を獲得して、裏ではアンチと組んでこのVtuberをイジメているなんで卑劣過ぎます。

4.1.3 神官の作成

色々考えましたが、神官は宿屋の主人と同じ方法で作成する事にしました。

NPC_ItemShopOwnerをduplicateしてNPC_Priestと名付けました。

f:id:kazuhironagai77:20210214222413p:plain

NPC_Priest を開いたらRPGGameInstanceクラスのboolean変数であるTalkInnをTrueにセットしています。

f:id:kazuhironagai77:20210214222437p:plain

このTalkInnに変わる変数をRPGGameInstanceクラスに作成する必要があります。作ります。

この関数が何故必要なのか今一分からないのですが、今回は宿屋と全く同じ作成方法で神官を作る事にします。これらのNPCの作成方法の最適化は後で考えます。

作りました。名前はTalkPriestにしました。

f:id:kazuhironagai77:20210214222504p:plain

NPC_PriestのTalkInnをTalkPriestに変更します。

f:id:kazuhironagai77:20210214222531p:plain

f:id:kazuhironagai77:20210214222541p:plain

今度はMyPlaceForEventsにPE_Priestを追加します。

f:id:kazuhironagai77:20210214222601p:plain

Buildします。

UE4 editorを一回閉じて開きます。

My Place for EventsにPEPriestを選択します。

f:id:kazuhironagai77:20210214222617p:plain

ThirdPersonCharacterBP内にPE_Priestの選択先を実装します。

f:id:kazuhironagai77:20210214222633p:plain

実装内容はPE_Innと全く同じです。

f:id:kazuhironagai77:20210214222648p:plain

Priest用のWelcomeウィジェットが無いので作成します。

Inn_Welcomeを元にPriest_Welcomeを作成します。

f:id:kazuhironagai77:20210214222705p:plain

以下の様にデザインしました。

f:id:kazuhironagai77:20210214222719p:plain

Inn_Welcomeの場合会話ボタンを押すとInn_Talkウィジェットが開かれます。

f:id:kazuhironagai77:20210214222746p:plain

同様のwidgetをPriest用に作成します。Priest_Talkと名付けます。

f:id:kazuhironagai77:20210214222813p:plain

更にNPC_ParentウィジェットにNPCPriestDialogを追加しセリフを書きます。

f:id:kazuhironagai77:20210214222831p:plain

セリフの内容はInnとほとんど同じです。後で、神官にふさわしいコメントに改善します。一応意味は通っているはずです。

f:id:kazuhironagai77:20210214222848p:plain

これらのセリフがPriest_WelcomeとPriest_Talkのコメント欄に表示されるように設定を変更します。

Priest_Welcomeのコメント欄に表示するテキストは以下の様な設定になっています。

f:id:kazuhironagai77:20210214222906p:plain

参照するテキストはNPCPriestDialogに変更しました。

Dialog Numberは

f:id:kazuhironagai77:20210214222937p:plain

にセットされています。

更にセーブボタンを押した時はDialog Numberが2または3にセットされています。

f:id:kazuhironagai77:20210214222958p:plain

ThirdPersonCharacterBPのCreate widgetの設定をPriest Welcomeに変更します。

f:id:kazuhironagai77:20210214223015p:plain

会話ボタンを押した時に開く、WidgetをPriest_Talkに変えます。

f:id:kazuhironagai77:20210214223032p:plain

Priest_Talkのコメント表示の参照にするテキストをNPCPriestDialogに変更します。

f:id:kazuhironagai77:20210214223049p:plain

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

f:id:kazuhironagai77:20210214223108p:plain

普通に表示されています。

f:id:kazuhironagai77:20210214223123p:plain

「出る」を押したらカーソルが消えてしまいました。バグですね。

以下の様に変更しました。

f:id:kazuhironagai77:20210214223138p:plain

今度は「出る」を押してもカーソルが表示されました。

Innでは泊まるを選択した場合、Sleepingというwidgetが作成されます。

f:id:kazuhironagai77:20210214223159p:plain

こんなヤツです。

f:id:kazuhironagai77:20210214223227p:plain

Saveでも似たようなWidgetを作成します。

f:id:kazuhironagai77:20210214223252p:plain

このwidgetを呼ぶ事にします。

f:id:kazuhironagai77:20210214223307p:plain

Saveをテストします。

セーブボタンを押します。

Prayウィジェットのアニメーションが流れます。

f:id:kazuhironagai77:20210214223323p:plain

f:id:kazuhironagai77:20210214223331p:plain

f:id:kazuhironagai77:20210214223338p:plain

アニメーションが終わったら元の画面に戻りました。

コメントも正しく表示されています。

f:id:kazuhironagai77:20210214223355p:plain

これで神官NPCは完成とします。

4.2 Loadした後に倒したモンスターは復活するのか?

ストーリーに関係するボスキャラが復活したらおかしいですが、雑魚のモンスターは朝になると復活したりしてもおかしくはないです。

今、配置しているモンスターらは雑魚モンスターと仮定すれば、復活しても良くなりMonster Spawn Dataをセーブする必要は無くなります。

4.3 Saveデータの数

前は、少なくとも3つ位のセーブデータが保持出来るような機能は必要と思っていました。

しかしゲームの面白さはバランスだと言う事に気がついた後では、沢山セーブ出来る事もバランスが変化する事が分かりました。のでsave出来るデータは一個だけとします。

5.データ以外のSaveに必要な要素の確認 Part 2(ゲーム外)

ここは調査の記録になります。良く分かっていない事ばかりなので間違えているかもしれませんが最初の一歩と言う事です。

今、データのセーブにおいて私が知りたいのはUE4では、セーブしたデータをどんな形でどこに保存しているのかです。

その理由は、保存しているデータを直接書き変える事で、キャラのパラメーターや所持するアイテムや武器、使用出来る魔法などを好き勝手に書き変えられてしまうかもしれないと私が恐れているからです。

今回確認したいのはその部分です。

後、それらのデータをサーバーに保存する方法を教えているTutorialがあるかも調べます。

5.1 セーブデータの保存場所

このサイトによると

f:id:kazuhironagai77:20210214223440p:plain

セーブデータとセーブされる場所に関しては以下の様に説明されています。

f:id:kazuhironagai77:20210214223457p:plain

Ch4_3で調べて見ると、

f:id:kazuhironagai77:20210214223514p:plain

ありました。

NodePad++で開いて見ると、ほとんどは意味が分からない滅茶苦茶なalphabetの羅列ですが、幾つかは

f:id:kazuhironagai77:20210214223530p:plain

f:id:kazuhironagai77:20210214223539p:plain

f:id:kazuhironagai77:20210214223557p:plain

f:id:kazuhironagai77:20210214223613p:plain

f:id:kazuhironagai77:20210214223626p:plain

意味が分かる単語があります。

.sav fileを読み込めるeditorを使用するか、もしくは技術のある人が作成した解析ツールを使用すれば、ここに書かれているデータを変更する事は簡単に出来そうです。

一般に販売されているゲームはPackageした後のSave dataの管理はどうやっているんでしょうか?携帯のゲームのガチャなどでレアアイテムが出た事に変えられたら結構大問題だと思います。

SlotにSaved dataの保存を任せるのではなくServer側に保存させてしまえば良いのかもしれませんね。

以下に示した図は単なる想像なのですが、

以下の方法でガチャを行うと、

f:id:kazuhironagai77:20210214223645p:plain

途中で結果を変える事が出来る可能性がありますが、

f:id:kazuhironagai77:20210214223700p:plain

以下のやり方ならば、途中でデータを改ざんしても結果を変更する事は出来ません。

f:id:kazuhironagai77:20210214223717p:plain

これだったらServerに直接攻撃されない限りは結果を改ざんされる事はなさそうです。

どうしても結果の改ざんを防ぎたいならblock chainのやり方を真似るのも手かもしれません。block chainがどうやっているのか具体的には知りませんが。

5.2 セーブデータの暗号化

セーブデータをSlotとしてClientのPCもしくはスマートホン内に保存する場合は、暗号化は絶対必要と思っていたのですが、前節の調査と考察を踏まえて、もう一度考えてみるとそうでもない気がしてきました。

  • まず買い取り型の一人で遊ぶゲームの場合ですが、Cheatしても誰にも迷惑はかけないので、ご自由にどうぞ。とも考えられます。
  • みんなで遊ぶゲームでCheatされるのが問題だったんです。そのタイプのゲームは前節のやり方でやれば、Clientが改ざん出来るデータは全くないのでCheatは防げます。

つまり、Slotにあるセーブデータを暗号化する価値はあんまり無いと思われます。

5.3 Serverに保存する場合の方法について

やり方を教えているTutorialがあると助かる訳でそれがないかを調べます。特にServerをタダで使用出来る方法を教えてくれるヤツがありがたいです。

Multi-play用のServer-Clientの作成方法はやっぱり沢山検索に出て来ますね。

How to Host Your UE4 Dedicated Server on AWS for FREEAWSのサーバーを無料で使用していますね。AWSはある程度までは無料なんでしょうか?GoogleのFire Baseをちょっとだけ勉強した時、来月からお金がかかりますみたいなメールが来たので止めちゃいましたが。無料なサービスならAWS使用したいですね。

しかし今回、私が知りたいのはServerにPlayerのデータを保存する方法だけです。

Multi-play Gameのような複雑な仕組みは、もっとUE4に詳しくなってから勉強します。

そのまま検索しても何も引っかからないので「Serverを使用してUE4でLoginを作成する方法」で検索してみました。Loginする方法とデータをサーバーに保存する方法は多分ほとんど同じでしょう。

Unreal Engine 4 Tutorial: Online Login System

がまずありました。Node.jsとAWSを使用しているみたいです。この辺のやり方はWebの開発者だったら超基本的な事かもしれません。UE4からデータをServerに発信する方法と受け取る方法さえ分かれば、残りはWEB開発の人に全部任せるのも手かもしれません。私はWEBの勉強よりUE4の勉強がしたいですし。

5.4 今回の調査からのSave方法に対しての結論

Slotにセーブでいいです。特別にServerを作成してゲームのdataの管理をする必要はないと思います。Multi-play用のゲームを作成した時にServer関係は勉強します。

6.Save機能のTutorialを復習する

正直、もう復習する必要ない位、UE4のSave方法について理解している自信がありますが、一応勉強します。

「2.2 2019-10-20のブログの復習」で紹介されていた

この二つのサイトを復習します。

全部、見ました。

UE4のSave方法について理解してから見るとHTF do I? Use the SaveGame Object in Unreal Engine 4は、簡便に説明していますが、基本はしっかり説明して、このTutorialを見るだけで学習者はSaveGameノードを使用してGame Dataをセーブする事が出来る作りになっています。

Saving and Loading Your Game

の方は、BPとC++の両方のやり方が説明されていますが、BPに関して言えば説明が十分と言えず、これを見ただけでは、学習者はSaveGameノードを使用してGame Dataをセーブする事は出来ないと思いました。C++に関しては、Asynchronousでセーブする方法や、Save Game To Slot関数が、Game DataをBinaryに変換してセーブしている事などが解説されていて勉強になりました。

7.まとめと感想

流石に集中力が切れて来たので今週はここまでにします。残りは来週以降やっていきます。