UE4の勉強記録

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

「Unreal Engine 4.xを使用してRPGを作成する」の足りない部分を作成する 新しい機能を追加する5

f:id:kazuhironagai77:20200920213819p:plain

<前文>

Kawaiiは世界基準に成れるか?

可愛いの英語はcuteとかadorableでしょう。と思っていたのですが、昔、あるアメリカ人からkawaiiとcuteやadorableは全然違うと指摘されました。そん時は、また、アメリカ人の知ったかかよ。と思って無視していました。で、すっかり忘れてしまったのですが、最近大〇なおみ選手が優勝した時、アメリカ人が本当にうれしそうな顔しているのを見てその事を思い出しました。そしてkawaiiとcute(adorableも)が違う事が何となく分かりました。アメリカのマッチョな文化には、大〇なおみ選手のような可愛いさは存在しません。アメリカ文化にもcuteは沢山あります。しかしkawaiiはないんです。ので、アメリカ人はその可愛さを持っている大〇なおみ選手が大好きなんです。

不思議なのは可愛いかどうかは誰でも分かりますが何が可愛いのかは良く分からない事です。

最近vtuberの動画を見まくっていて、日本のvtuberは可愛いのに海外産のvtuberは可愛くないと思いました。理由は上記に説明したように分かりません。今、vtuberは海外からの人気が非常に高いですが、安易に日本語をちょっとしゃべれる外国人にやらせるのはかなり危ういと思います。外国人はこの可愛いと言う文化がないから日本人が当然と思っている可愛さが全くない感じになってしまうかもしれません。

しかしvtuberを見る海外の人はvtuberに可愛さを求めています。この辺を読み違えると大失敗に終わる気がします。

まあ、vtuberの海外進出が失敗に終わってもkawaiiが世界中から切望されるコンテンツである事は間違いありません。失敗しても別な何かで、世界はkawaiiを手に入れるでしょう。

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

<本文>

今週も、programming partとdesign partに分けてやって行きます。

Programming part

  1. 戦闘中に「逃げる」を選択した時、他の選択をした時と挙動が違っています。これを直します。
  2. 逃げるのコメントを正しくします。
  3. 戦闘中に選択を間違えた時の対応を考えます。

Design part

  1. 宿屋がない事に気が付きました。宿屋を作成します。
  2. 完成した村を今のプロジェクトに移し、村人を配置します。
  3. 村のタイルの大きさをもっと小さくします。

全部は無理かもしれませんが一応、目標です。

1. Programming Part

1.1 「逃げる」の直し

先々週、戦闘中の逃げるを作成しましたが、先週判明した戦闘システムのプログラミングの手順に沿って作成はしなかったので、順序などが滅茶苦茶になっているはずです。それを直します。

今の状態だと以下のようになっています。

まず戦闘システムから逃げるを選択すると、RPGGameModeBaseBPのSetCombatEnginePhaseMakeOff()関数が呼ばれます。

f:id:kazuhironagai77:20200920213952p:plain

以下に示すように、SetCombatEnginePhaseMakeOff()関数内で、CombatEngineクラスのインスタンスであるcurrentCombatInstanceの関数、SetPhaseToMakeOff()が呼ばれます。

f:id:kazuhironagai77:20200920214010p:plain

以下に示したように、CombatEngineクラスのSetPhaseToMakeOff()内でSetPhase()関数が呼ばれます。

f:id:kazuhironagai77:20200920214028p:plain

以下にCombatEngineクラスのTick()関数内でPhaseがMakeOffに変わった時に実行されるコードを示します。

f:id:kazuhironagai77:20200920214047p:plain

Trueを返すだけですね。

今度はTrueを返されたRPGGameModeBaseのTick() 関数がどのようなコードを実行するかを見て行きます。

f:id:kazuhironagai77:20200920214120p:plain

まず、ここでCombatOverがtrueに成るので、if節が実行されます。

更にPhaseがMakeOffだった場合、以下に示したコードが実行されます。

f:id:kazuhironagai77:20200920214142p:plain

ここで大切なのは関数ReportFightIsOver() が実行される事です。

関数ReportFightIsOver()は以下に示したようにBlueprintImplementableEventでした。

f:id:kazuhironagai77:20200920214159p:plain

BPにおける実装は以下に示すコメントの表示内容を決定する部分と

f:id:kazuhironagai77:20200920214217p:plain

以下に示すアニメーションを表示する部分で構成されている関数です。(ただし逃げる時のアニメーションはないので逃げるを選択した時はアニメーションはなし。)

f:id:kazuhironagai77:20200920214238p:plain

今の逃げるを選択した時の流れが分かりました。

次に攻撃を選択した時の流れを見てみます。

まず、攻撃ボタンをクリックした時にCombatSelected変数の値をAttackにセットします。

f:id:kazuhironagai77:20200920214257p:plain

ここは、逃げるを選択した場合も、基本的には同じです。(CombatSelected変数の値をEscapeにセット)

この後、色々やっていますが、基本的には二つの事をやっています。

まずVirtical boxであるTargetsに攻撃対象のキャラを追加する事。

f:id:kazuhironagai77:20200920214324p:plain

次に攻撃を選択した時のコメントの表示

f:id:kazuhironagai77:20200920214343p:plain

を行っています。

この手順に従うならば、逃げるの選択をした場合も、まず、逃げる対象をTargetsに表示して、その後コメントを表示すべきです。

やっと具体的に直す箇所を一個見つけました。

更に見て行きます。

攻撃対象であるモンスターを選択した場合、AttackTargetOptionウィジェットのボタンがクリックされます。その時のBPのコードを見てみましょう。

AttackTarget()関数を読んでいます。

f:id:kazuhironagai77:20200920214403p:plain

AttackTarget() 関数はCombatUIWidgetクラスの関数で以下に実装部を示します。

f:id:kazuhironagai77:20200920214421p:plain

中を見てみると、ここでTestCombatActionクラスを作成しています。Itemを使用した時は、新しいクラス、TestCombatActionItemを作成したので、正しい手順にそうならば、逃げるを選択した場合はここでTestCombatActionEscapeクラスを作成すべきですね。

更に言えば、Itemを使用した場合は、

f:id:kazuhironagai77:20200920214438p:plain

AttackTarget()関数ではなく、UseItemInCombat()関数が呼ばれています。逃げるを選択した時のためにEscapeFromEnemy()関数を作成する必要がありそうです。

次に、ActionPanelをHideしています。

f:id:kazuhironagai77:20200920214509p:plain

以下の図で示した緑でくくった個所を全部隠します。

f:id:kazuhironagai77:20200920214536p:plain

この機能は、ユーザーが一個以上の選択するのを防ぐために勿論必要ですが、実際はユーザーは戦闘中に一個以上のボタンをクリックする事が出来るのでもっと厳しい対策が必要です。この対策は1.3でやります。

最後に表示するコメントをセットします。

f:id:kazuhironagai77:20200920214555p:plain

これで攻撃ボタンをクリックした場合のコードは全て実行されましたが、finishedDecisionがtrueにセットされた事によりCombatEngine並びにRPGGameModeBaseクラスのTick()関数で実行されているプログラム内容が変化します。

f:id:kazuhironagai77:20200920214616p:plain

まず、CombatUIWidgetクラスの関数、MakeDecision()の返し値がTrueに代わります。

f:id:kazuhironagai77:20200920214634p:plain

そのため、今度はGameCharacterクラスのMakeDecision()関数の返し値がTrueになります。

(以下の実装では、直接Trueになってはいません。これはコメントを表示する関係ですこしだけ教科書のコードより複雑になっているためです。)

f:id:kazuhironagai77:20200920214717p:plain

次にCombatEngineクラスのTick()関数内でdecisionMade関数がTrueに変化します。その結果、PhaseがCPHASE_Actionに変化します。

f:id:kazuhironagai77:20200920214737p:plain

PhaseがCPHASE_Actionに変化したためCombatEngineクラスのTick()関数内で以下のコードが実行されます。

f:id:kazuhironagai77:20200920214825p:plain

①から説明します。BeginExecuteAction()関数は、GameCharacterクラスの関数です。以下に示したコードが一回だけ実行されます。

f:id:kazuhironagai77:20200920214844p:plain

正直、教科書のこの書き方は無駄に複雑にしているような気がしていますが、今回はその部分には触れません。

この関数内で今度は、TestCombatActionクラスのBeginExecutionAction()を実行します。

f:id:kazuhironagai77:20200920215059p:plain

ハイ、ここで初めて敵のモンスターにダメ―ジを与えました。

今度は、CombatEngineクラスのTick()関数内の②についての解説です。

f:id:kazuhironagai77:20200920215119p:plain

因みにこの関数はactionFinished変数がTrueになるまで何度も呼ばれ続けます。

CurrentTickTarget変数はGameCharactetrクラスから作成されています。GameCharacterクラスのExecuteAction()関数を見てみます。

f:id:kazuhironagai77:20200920215138p:plain

ここで大切なのはTestCombatActionクラスのインスタンスを保持するCombatAction変数のExecuteAction()関数が呼ばれている事です。

はい。TestCombatActionクラスのExecuteAction()関数を以下に示します。

f:id:kazuhironagai77:20200920215156p:plain

ここで初めて、TestCombatActionクラスの変数delayTimerが0以下になったらTrueが返される事になります。

そして今までたどった経路をさかのぼって、CombatEngineクラスのTick()関数内の②の返し値がTrueになり、

f:id:kazuhironagai77:20200920215215p:plain

CombatEngineクラスのTick()関数内の以下のコードが実行され、

f:id:kazuhironagai77:20200920215238p:plain

また、攻撃、魔法、道具、逃げるの選択画面に戻ります。

以下にこの流れをまとめました。

f:id:kazuhironagai77:20200920215256p:plain

ここから

f:id:kazuhironagai77:20200920215315p:plain

を一回だけ実行した後、

f:id:kazuhironagai77:20200920215332p:plain

となります。

よし完璧に分かりました。それでは「逃げる」を直していきましょう。

まず逃げるを選択した時にCombatUIクラスで実行する内容を以下のようにしました。

f:id:kazuhironagai77:20200920215351p:plain

逃げるのに、対象を選ぶ必要はないので、コメントを表示するだけです。

CombatUIWidgetクラスに

f:id:kazuhironagai77:20200920215409p:plain

を追加します。

攻撃を選択した時のためのTestCombatActionクラスやItemを選択した時のUseItemInCombatクラスのような逃げるを選択した時のICombatActionクラスからの派生クラスを作成します。

f:id:kazuhironagai77:20200920215500p:plain

ここで初期化するTestEscapeActionクラスを作成します。

f:id:kazuhironagai77:20200920215524p:plain

f:id:kazuhironagai77:20200920215534p:plain

と言っても何が必要なのかまではまだ分からないので、ほぼTestCombatActionクラスをコピーしただけです。

一個足りない事が判明しました。逃走が成功したのか失敗したのかがユーザーから不明な事です。

GameCharacterクラスにReportEscapeOrNotToRPGGameModeBase()関数を作成して、それをこのTestEscapeActionクラスのBeginExecutionAction()から呼ぶ事で逃走が成功したのか失敗したのかをユーザーに伝えます。

f:id:kazuhironagai77:20200920215554p:plain

GameCharacterクラスにReportEscapeOrNotToRPGGameModeBase()関数は、基本的にはReportDamageHPtoRPGGameModeBase()関数やReportDamageMPtoRPGGameModeBase()関数と同じです。

f:id:kazuhironagai77:20200920215652p:plain

f:id:kazuhironagai77:20200920215701p:plain

単に結果をRPGGameModeBaseクラスの関数、ReportEscapeOrNot()に伝えているだけです。

RPGGameModeBaseクラスでは、ReportEscapeOrNot()関数を以下に示したように宣言しています。BlueprintImplementableEventを使用しているのでReportEscapeOrNot()関数の実装はBPで行えるはずです。

f:id:kazuhironagai77:20200920215824p:plain

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

f:id:kazuhironagai77:20200920215920p:plain

Buildは成功しました。

ReportEscapeOrNot()関数の実装を忘れていたのでしました。

f:id:kazuhironagai77:20200920215948p:plain

戦闘を開始して逃げるを選択しました。

f:id:kazuhironagai77:20200920220011p:plain

f:id:kazuhironagai77:20200920220020p:plain

出来ているみたいです。

今度はKUMOもLUCKを下げてみます。

f:id:kazuhironagai77:20200920220050p:plain

戦闘を開始して逃げるを選択しました。

f:id:kazuhironagai77:20200920220121p:plain

ここまでは同じです。

f:id:kazuhironagai77:20200920220142p:plain

今度は逃げられません。

f:id:kazuhironagai77:20200920220216p:plain

逃げるのを失敗すると相手の攻撃を受けてダメージが入ります。

これも成功ですね。

1.2 「逃げる」のコメントの直し

コメントも1.1で直してしまったのでここでやる事はありません。

1.3  戦闘中に選択を間違えた時の対応を考えます。

まず、どんな問題が在るがですが、

f:id:kazuhironagai77:20200920220257p:plain

戦闘中に攻撃を選択した後でも別の選択肢である魔法や道具などがクリック出来ます。

f:id:kazuhironagai77:20200920220357p:plain

クリックすると前に押した攻撃を上書きした状態になります。ただしコメントは直りません。

f:id:kazuhironagai77:20200920220431p:plain

コメント欄は滅茶苦茶なってしまいます。

ので選択ボタンを一個押したら他のボタンは押せないようにします。

f:id:kazuhironagai77:20200920220452p:plain

BP関数、HideButtonsをCombatUIウィジェット内に作成しました。

f:id:kazuhironagai77:20200920220511p:plain

これを攻撃ボタンを押した時に実行されるようにします。

f:id:kazuhironagai77:20200920220534p:plain

攻撃を選択した後は、他の選択が出来なくなりました。

ずっと消えたままだと困るので今度はボタンを表示される関数を作成します。

f:id:kazuhironagai77:20200920220555p:plain

この関数を、ReportExecuteAction()の実装部の最後に実行します。

f:id:kazuhironagai77:20200920220614p:plain

正直、ここがベストなのかどうか良く分かっていませんが、ほぼ正解だと思います。

テストしてみます。

f:id:kazuhironagai77:20200920220633p:plain

次の行動を選択する時に、ボタンが表示されました。

同様に、魔法や道具を選択した時もボタンが消えるように

f:id:kazuhironagai77:20200920220649p:plain

しました。

テストするために道具を買いに行ったらエラーになってしまいました。

f:id:kazuhironagai77:20200920220709p:plain

その理由ですが、UE4C++のRPGGameModeBaseクラスのコードを書き変えるたびにBPのCasttoRPGGameModeBaseBPk関数を作り直す必要があります。

これを忘れていました。でもこれ何で必要なんでしょう。

直ったのでテストしました。

出来ていました。

同じ方法でアイテムを選択した場合もやって行きます。

CombatItemウィジェットのOnClicked eventに以下のコードを追加し

f:id:kazuhironagai77:20200920220729p:plain

CombatUIのItemButtonがクリックされた時のeventに以下のコードを追加しました。

f:id:kazuhironagai77:20200920220746p:plain

テストします。

使用する道具を選択したら、道具全部非表示になりました。

f:id:kazuhironagai77:20200920220805p:plain

次のターンで道具を選択すると

f:id:kazuhironagai77:20200920220825p:plain

道具が現れました。

出来ていますね。

魔法を使用する時も同様にします。

f:id:kazuhironagai77:20200920220842p:plain

f:id:kazuhironagai77:20200920220851p:plain

テストします。

魔法を選択すると

f:id:kazuhironagai77:20200920220911p:plain

選択出来る魔法の一覧が消えます。

次のターンで魔法を選択すると使用出来る魔法の一覧が普通に表示されます。

f:id:kazuhironagai77:20200920220929p:plain

これで良いでしょう。

2. Design Part

家族が突然、私の誕生パーティを開いてくれる事になったので今週はここで中止します。残りは来週やります。