UE4の勉強記録

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

「Unreal Engine4.xを使用してRPGを作成する」の3章の3.4を勉強する part 5

<前文>

f:id:kazuhironagai77:20190623210036p:plain

ネット上にあるUE4チュートリアルは全部見ていると思っていたのですが、全く知らなかった2つのチュートリアルを最近発見しました。Visual novel tutorialとBlueprint multiplayerです。Visual novel tutorialは名前の通りUE4を使用したVisual Novelの作成方法のチュートリアルです。まだ一番最初しか見ていませんが大変詳しく解説されています。Blueprint multiplayerは公式のチュートリアルで、こちらも一番最初しか見ていませんが、steamのサーバーを利用してマルチプレイのゲームを作成する方法を教えているみたいです。

Visual Novelは本の虫だった私が唯一興味があるゲームの分野なので、絶対勉強したいと思っています。またBlueprint multiplayerはsteamのサーバーを利用してマルチプレイを実行するみたいで、今のRPGのゲームはfirebaseを使用してデータの保存やログインを作成しようと考えている私ですが、ひょっとするとBlueprint multiplayerにもっと簡単な方法が載っているかもしれないと思っています。となるとこちらも勉強したいです。

<本文>

<目的>

3章3節の5、ターン制の戦闘(turn based combat)、ターゲットの選択(Target selection)を勉強します。

<方法と結果>

<Step.0>

前回まで使用していたCh2をそのまま今回も使用します。

<Step.1>

教科書には以下のように書かれていました。

GameCharacgterクラスにキャラクターがプレイヤーか敵であるかを決定するフィールドを追加します。

次にSelectTarget関数を追加します。

この関数はそのキャラクターがプレイヤーか敵かに基づいて、敵のパーティもしくは味方のパーティの当座の戦闘のインスタンスから最初の標的を選択します。

もう読んだままで何も解説は要らないですね。一つだけあえて述べるとすればfieldの事です。変数の事をfieldと呼ぶ事は知っていましたが、こちらの方が一般的な言い方なのでしょうか?私としてはfieldは久しぶりに聞いた気がします。

それではやって行きましょう。

f:id:kazuhironagai77:20190630184826p:plain

教科書のサンプルコード通りに変数と関数を一つずつ追加しました。この変数isPlayerがこのキャラクターがプレイヤーか敵かを表わすのですね。そしてSelectTarget()関数が標的を選択するわけですね。

f:id:kazuhironagai77:20190630184912p:plain

まずCreateGameCharacter(FCharacterInfo *…)関数内のisPlayerを初期化しました。この関数を使用する場合、キャラクターは必ずプレイヤーなのでisPlayerはtrueになります。教科書ではCreateGameCharacter()関数の事をコンストラクターと呼んでいますが、正直これには違和感があります。

次に

f:id:kazuhironagai77:20190630185024p:plain

をCreateGameCharacter(FEnemyInfo *…)関数に追加しました。この関数を使用する場合、キャラクターは必ず敵になるのでisPlayerはfalseになります。

<Step.2>

次にSelectTarget()関数を実装します。

f:id:kazuhironagai77:20190630185053p:plain

教科書の説明にあった

この関数はそのキャラクターがプレイヤーか敵かに基づいて、敵のパーティもしくは味方のパーティの当座の戦闘のインスタンスから最初の標的を選択します。

をそのまま実装しています。試しにビルドしてみると成功しました。

<Step.3>

これだけでは少ないので、次のダメージへの対応(Dealing damage)も勉強します。教科書には以下のように書かれています。

とうとうターゲットを選択する簡単な方法が得られたので、TestCombatActionクラスにダメージへの対応をさせましょう。

どうやって実行するのでしょうか?教科書を読んでいきましょう。まず教科書には、「キャラクターへのリファレンスを維持するために2、3のフィールドを追加します。」とあります。

f:id:kazuhironagai77:20190630185219p:plain

教科書のサンプルコード通りに2つのUGameCharacterクラスから作成した変数を追加しました。

次にTargetをパラメーターに取るコンストラクターを作成します。

作成しました。サンプルコードではこのコンストラクターはヘッダーファイルの一番最後で宣言されていたので、以下に示すようにサンプルコードと同じようにヘッダーファイルの最後で宣言しました。

f:id:kazuhironagai77:20190630185335p:plain

<Step.4>

Step.3で宣言したTestCombatActionクラス内の変数や関数などを実装していきます。

まずはBeginExecuteAction()関数を更新します。

f:id:kazuhironagai77:20190630185403p:plain

追加されたコードは今追加した二つの変数CharacterとTargetに関するものです。まずcharacter変数を初期化します。そしてtarget変数のHPが0以下ならこのキャラクターにあるSelectTarget()関数を使用して新しいtargetを選びます。もしtargetは存在しない場合は何もしません。Targetが存在する場合はそのtargetのHPを10だけ引きます。

次にコンストラクター内でTarget変数を初期化します。

f:id:kazuhironagai77:20190630185438p:plain

これによるとTestCombatActionクラスを初期化した時にパラメーターとしてパスしたキャラクターがTargetとして指定されるみたいですね。でもこの方法だと味方にも攻撃出来てしまうかもしれませんね。

次にTestDecisionMaker クラスのBeginMakeDecision()関数内を、Targetを選びそしてそのTargetをTestCombatActionのコンストラクターにパス出来る様に変更します。

f:id:kazuhironagai77:20190630185527p:plain

サンプルコード通りにTestDecisionMaker() 関数を変更しました。

なるほど、これで敵のグループしか攻撃できなくなりましたね。しかしこの方法だとどの敵に攻撃するかはプレイヤーは選べませんね。ここも実際のRPGゲームを作成する時は改良が必要になりますね。

それでは教科書にあるようにテストをしてみましょう。

f:id:kazuhironagai77:20190630185559p:plain

結果は上記のようになりました。教科書の結果と同じですね。これでも少ないですが丁度テストした所なので今週はここでお終いにします。

<考察>

BeginMakeDecision()関数、MakeDecision()関数、BeginExecuteAction()関数、そしてExecuteAction()関数がそれぞれ具体的に何をするのかが分からないとこれらの関数を最初に作成したときに嘆いた事があります。今回、これらの関数の実装が追加された事で大分これらの関数の戦闘における役割が見えて来ました。これらの関数について今回は考察します。

BeginMakeDecision()関数

f:id:kazuhironagai77:20190630185632p:plain

意思の決定を始める。と言われてもそれじゃ何もする必要はないじゃん。と思ってしまいますが、この関数は攻撃する相手を決定するのが目的のようです。確かに何処かで攻撃する相手を決定する必要はあります。この教科書では最初にそれを決定するようです。ただしこの方法だと攻撃する相手は順番で勝手に決まってしまいますのでターン制のRPGとしてはちょっと物足りない作りになってしまいます。

MakeDecision()関数

f:id:kazuhironagai77:20190630185653p:plain

次の関数はまだ実装されていませんが、攻撃する敵が決まっているので次にする事は大体想像つきますね。攻撃の手段の選択を此処でするのでしょうね。剣で攻撃するのか魔法で攻撃するのかをここで決定するのでしょう。となると魔法で回復する場合はどうなるのでしょうか?回復する相手は自分か仲間になるのでtargetを変更する必要が出て来ますね。となるともこの関数ももう少し複雑になっていくのかもしれません。

BeginExecuteAction()関数

f:id:kazuhironagai77:20190630185713p:plain

この関数のちょっと不思議な所はここで敵のダメージを計算してしまう所です。この関数はあくまでアクションの実行を開始する関数なのでダメージは次の関数で与えるべきなのではないのかなー?と個人的には思います。これは一時的な処置なのでしょうか?

ExecuteAction()関数

f:id:kazuhironagai77:20190630185818p:plain

ここはまだ何をやるのか分かりませんね。ただダメージをBeginExecuteAction()関数で既に与えているのでアニメーションの処理ではないかと思っています。