UE4の勉強記録

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

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

<前文>

f:id:kazuhironagai77:20190623210036p:plain

私はゲームを全くしないので良くは知らないのですが、近年、日本ではゲームの売れ行きはあまり良くないようですね。もう誰もゲームをやらないしプレイされるゲームは携帯のポチポチだけと言われているみたいです。最近はその携帯のゲームの売り上げも落ちているようですね。ただし最近読んだ記事によると、実際はゲームの開発者(インディゲームの開発者も含めても)の収入は上昇かつ安定して来ている統計結果が出ているそうです。その記事によるとゲームの開発者は実際のゲームから儲けを出すよりもそのゲームを制作する時に開発したシステムやアセットをゲームエンジンのストアで売る事で収入が上昇かつ安定して来ているそうです。この記事はアメリカの話なので日本の事情と一緒に語る事は出来ないかもしれませんが大変興味深い内容だと思いました。

前回紹介したUE4のFirebaseのプラグインなんか2万円以上しますが実際に自分で作成しなければならないとなったら時間換算で2万円以上の出費を強いられるのは確実です。だから「買っちゃおうかな。」と思いますよね。さらに顧客のデータを扱うわけですから自分が書いたコードに問題があってそのせいで顧客のデータが消えたり漏えいしてしまったりしたら大変です。そういう責任の所在的な意味でもプラグインの購入は魅力的です。アセットだって一から全て自分で作成していたら大変です。さらにアセットの場合は著作権の問題も全て自分で対応しないといけなくなりますよね。3Dのデータを抜かれてインターネットに放流されても他の会社に自分のアセットを不法に使用されたとしても対策を打つのは簡単ではないですよね。更に逆に貴方のアセットは我々の著作物を侵害している箇所があります。と他の会社から警告を受ける可能性も考えなければならないといけませんよね。こうなるとやっぱりストアから購入する事はそういう厄介事をすべて購入先の会社がやってくれるので魅力的です。

こうやって考えてみるとゲームエンジンのストアが発展していくのは消費者側からも結構嬉しい事ですね。となるとWin-Winの関係になるのでゲームの開発者がシステムやアセットをゲームエンジンのストアで売る事で安定した収入を得る傾向はかなり続くと思われます。

それでは勉強して行きましょう。

<本文>

<目的>

3章3節の4、ターン制の戦闘(turn based combat)、意思の決定(Making decisions)を勉強します。

<方法と結果>

<Step.0>

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

<Step.1>

教科書の説明によればアクションの実行(Performing actions)で行ったのと同じように意思の決定(Decision Making)のためにインターフェイスを作成します。まずDicisionMakersと言う名前の新しいフォルダーをSource/RPG/Combatに作成します。そこにICombatActionクラスに似た空のIDecisionMakerクラスを作成します。

フォルダーを作成します。VSのSolution ExplorerにあるSolutions and Folders(以下に示す図)をクリックして

f:id:kazuhironagai77:20190623210230p:plain

実際のフォルダーを表示します。

f:id:kazuhironagai77:20190623210256p:plain

Combatフォルダー内にDecisionMakersフォルダーを作成します。

f:id:kazuhironagai77:20190623210347p:plain

UE4エディター上からC++ウィザードを開き生の新しいC++クラスを作成します。名前はIDecisionMakerです。

f:id:kazuhironagai77:20190623210414p:plain

こんな感じに出来ました。

f:id:kazuhironagai77:20190623210436p:plain

教科書のサンプルコードをコピーします。

f:id:kazuhironagai77:20190623210510p:plain

f:id:kazuhironagai77:20190623210521p:plain

試しにビルドした所成功しました。

<Step.2>

Source/RPG/Combat/ DicisionMakers内にTestDecisionMakerをC++クラスで作成します。前回どのように作成したのか覚えていないのですが、普通にUE4エディター上のC++ウィザードから作成します。

f:id:kazuhironagai77:20190623210557p:plain

更に、教科書にあるサンプルコードをコピーします。

f:id:kazuhironagai77:20190623210635p:plain

f:id:kazuhironagai77:20190623210643p:plain

試しにビルドしてみると成功しました。

<Step.3>

次にGame Characterクラス内におけるIDecisionMakerへのポインターを追加します。そしてGameCharacterヘッダー内でdecision makerを使用するためにBeginMakeDecision()関数とMakeDecision()関数を調節します。

教科書のサンプルコード通りにGameCharacterクラス内のコードを変更します。

f:id:kazuhironagai77:20190623210727p:plain

f:id:kazuhironagai77:20190623210736p:plain

f:id:kazuhironagai77:20190623210746p:plain

をヘッダーファイルに追加しました。

f:id:kazuhironagai77:20190623210808p:plain

ソースファイルそれぞれの関数内の実装を変更しました。

<Step.4>

それぞれのパーティが戦闘の決定が出来るようにTestDecisionMakerをGameCharacterクラスのソースファイル内にインクルードします。

f:id:kazuhironagai77:20190623210853p:plain

最後にキャラクターのためにコンストラクター内でdecision makerを割り当てます。

f:id:kazuhironagai77:20190623210921p:plain

をCreateGameCharacter()関数内に追加しました。教科書ではこの関数の事をコンストラクターと呼んでいますがメンバー関数ですね。UGameCharacterクラスのオブジェクトを初期化するのにNewObject()関数を使用していますし。

同様に、

f:id:kazuhironagai77:20190623210948p:plain

内からも

f:id:kazuhironagai77:20190623211016p:plain

を追加します。

これでこの節で実装しなければならないコードは終わりです。

テストをしてみます。

f:id:kazuhironagai77:20190623211039p:plain

これが正しいのか分かりませんね。考察で一つ一つの流れを見てみましょう。

<考察>

前回と同じように流れを追っていきます。

途中までは前回と全く同じですのでUGameCharacter クラスであるcurrentTickTargetのBeginMakeDecision()関数を呼び出す所から始めます。

f:id:kazuhironagai77:20190623211108p:plain

今度はdecisionMakerからBeginMakeDecision()関数を呼び出します。

f:id:kazuhironagai77:20190623211139p:plain

decisionMaker変数はIDecisionMakerクラスから作成されているので、

f:id:kazuhironagai77:20190623211201p:plain

を実行します。

次にcombatEngineクラスのtick関数に戻りUGameCharacter クラスであるcurrentTickTargetのMakeDecision()関数を呼び出します。

f:id:kazuhironagai77:20190623211231p:plain

繰り返しますがdecisionMaker変数はIDecisionMakerクラスから作成されているので、以下の関数が実行されます。

f:id:kazuhironagai77:20190623211254p:plain

この関数は単にtrueを返すだけですね。

f:id:kazuhironagai77:20190623211318p:plain

この後は前回と同じで

f:id:kazuhironagai77:20190623211339p:plain

を実行する時にdoes nothingをプリントアウトしているようです。

やっと全体の流れが見えて来ました。見方ならそれぞれの職業、敵ならそれぞれの種族で戦闘中に出来る事が違うわけです。それを総て別々に作成すると膨大な未整理のクラスが出来てしまうので、IDecisionMakerインターフェイスとICombatActionインターフェイスを最初に作りそれぞれを継承したクラスにそれぞれの種族や職業で出来る事を定義していこうと言う事のようです。