<前文>
2週間ほど家庭の事情でUE4のC++の勉強が出来ませんでした。2週間経つと結構勉強したくなくなりますね。もう一度やり始めるのは大変です。UE4のC++に対する興味もかなり弱くなります。今回はリハビリのつもりでゆっくりやって行きます。
今回からGameplayAbilities APIの使用方法についてです。
今まで、必ずUE4のAPIを調べて来たのですが、GameplayAbilitiesのAPIが見つからないです。唯一見つかったのがここです。
でも、これってGameplay Ability Systemの事でGameplayAbilitiesと違うのかもしれません。しかもこのサイト次にプラグインの方法を説明しています。良く分からないです。
そう言えば、アクションRPGのゲームの作り方を勉強したくてネットを見ていた時、Gameplay Ability Systemの話が出てきたような気がします。アクションRPGのゲームの作り方は難しくて途中で読むのを辞めてしまいました。特にこのGameplay Ability Systemの部分が難しかった記憶があります。今週はあんまりやる気もありません。今回のGameplayAbilities APIがGameplay Ability Systemの話でない事を祈るばかりです。
<本文>
<目的>
GameplayAbilities API を使用してアクターのゲームプレイ能力(actor’s gameplay abilities)をゲームコントロール(game controls)からトリガー(trigger)します。もうこの時点で何を言っているのかあんまり分かりません。取り敢えず出来るところまでやって行きましょう。
Step.0
今回は新しいプロジェクトを作成します。プロジェクト名はChapter12Part8とします。
今回のレシピは何をするのか今一良く分かっていないので、教科書をまずよく読んでみます。私が理解した限りではGameplayAbilities APIを使用する事でゲームプレイ中のボタンを押すなどのイベントでアクターなどのアビリティ―をC++の関数から呼び出す事が出来ると言っているみたいです。ウーン。このアビリティ―が何を指しているのか今一分かりませんが、プレイヤーが操作するアクターがプレイヤーが押すボタンによって前後左右の行動や攻撃や防御をする事をアビリティ―と呼ぶのならこれは当たり前の事で、増々???と成ってしまいます。
思い出して来ました。前にアクションRPGのゲームの作り方を勉強した時にGameplay Ability Systemが出て来て、これはGame Programming Patternsに出てくるType Objectの事なのではないかと思ったのでした。
このtype Objectがどんなゲームデザインなのかもう忘れてしまったのですが、ゲームを作成するのに絶対必要なソフトウェアデザインだったはずです。それでGameplay Ability Systemを一生懸命勉強したのですが難しすぎてギブアップしました。
今、サラッとGame Programming PatternsのType Objectを読んでみたのですが、今回のレシピで述べているアクターのアビリティ―が関係あるのか良く分かりませんね。こんな複雑な内容は相当気合いが入っている時にしか勉強出来ないですから。特に今週は無理ですね。
取りあえず、アクターのアビリティ―は、アクターが前後左右の行動や攻撃や防御をプレイヤーの押したボタンなどによって行動する事を指していると仮定して次に行きます。
<準備>
本来ならば、教科書のGetting readyはサラッと読んで終わりにしてしまいますが、今回はGameplayAbilities APIが何なのか良く分からないので良く読んで以下にまとめました。
・ゲームのキャラのアビリティをEnumで表すらしいです。
・どのキーを押すとそのキャラクターが何をするのかを予め決定しておかないといけないそうです。
ウーン。あるキャラクターは攻撃ボタンを押したら火を噴きます。違うキャラクターは水を噴きます。これをGameplayAbilities APIを使ってプログラムするのでしょうか?まだ良く分かりませんね。
まず、当然ですがUGameplayAbilityクラスからの派生クラスを作成するようです。上記の説明によるとこの派生クラスは一つのアビリティ―に対して一つ必要だそうです。
UGameplayAbilityクラスからの派生クラスを作成するについてオーバーライドについて説明しています。
InputPressedメンバー関数: アビリティを発動するためのボタンに対応?
CheckCostメンバー関数: 魔法を使用するために十分なMPがあるかのチェック?
ApplyCostメンバー関数: MPから魔法を使用するのに必要なMPを引く?
ApplyCooldownメンバー関数: 魔法を使ってから次の魔法が使えるまでの魔法が使えない時間の指定?
とか想像出来ますが実際はどうでしょうか?
GameplayAbilitiesSetクラスからもオブジェクトを作成するようです。その目的については良く分かりませんが上記の説明についてはGameplayAbilityの派生クラスに対応するブループリントとアビリティ―を列挙したEnumを保持しDefaultInput.iniに指定した方法で動かす事が出来るそうです。
ここまでの説明で分かったことをまとめます。
・アビリティ―は列挙型(enum)で示します。
・UGameplayAbilityクラスからの派生クラスを作成します。この派生クラスで具体的なアビリティ―の内容を決定します。
・GameplayAbilitiesSetクラスからもオブジェクトを作成します。アビリティ―を列挙したenumとUGameplayAbilityクラスからの派生クラスを管理します。
このまとめがどこまで正しいか分かりませんが、全く情報がない場合よりマシですので正しいと仮定して次に行きます。
Step.1
これ見るたびに必ず思い出すのですがこの教科書で最初にUE4のAPIを使用するレシピで、UE4のAPIを使用する場合は必ずBuild.csにそのAPI名を追加しなければならない事が書いてなかった事です。そのレシピがエラーになる原因を解明するのは本当に大変でした。
GameplayAbilities APIのAPI名はGameplayAbilitiesだと思いますが念のためにサンプルコードの方も見てみましょう。
GameplayAbilitiesとなっていますね。以下に示すようにBuild.csにGameplayAbilitiesを追加しました。
ここで思い出したのですが、最初に述べたアクションRPGのゲームの作り方で出て来たGameplay Ability Systemのサイトで、
となっていました。今回のレシピで習うGameplayAbilities APIの使い方とアクションRPGのゲームの作り方で出て来たGameplay Ability Systemは同じ事でした。
はぁー。
これは結構大変なレシピになりそうですね。今週は出来るところまでやりましょう。
Gameplay Ability Systemと同じとなるとGameplayAbilityだけでなく、GameplayTagsとGameplayTasksも追加しないといけないみたいですね。更にplugInも追加しないといけないみたいですね。
まず、以下に示すようにGameplayTagsとGameplayTasksをBuild.csに追加しました。
Pluginを追加しました。
Step.2
サンプルコードを参考にしてUGameplayAbility_Attackクラスを作成します。
まず、以下に示すようにC++ウィザードからGameplayAblityクラスを選択します。
GameplayAbility_Attackと名付けます。サンプルコードがPublicになっていたので、Publicを選択しました。
以下に示すように出来ましたが、GameplayAbilityがエラーになっています。
以下に示すように出来ましたが、GameplayAbilityがエラーになっています。
以下に示すようにビルド出来ているのでそのままで行きます。
Step.3
サンプルコードを参考にしてオーバーライドしていきます。
まず、コンストラクターを作成します。
サンプルコードのGameplayAbility_Attackクラスは全てのコードをhファイルに書いていますが、ここではヘッダーとソースファイルに分けて書いて行きます。
こんな感じに書いて、ビルドしたら
エラーになってしまいました。
ウーン。取りあえず、VSをリフレッシュします。
まだエラーが出ているので、全部ヘッダーに戻しました。
まだエラーは出ていますが、ビルドしてみます。
ビルド出来ましたので次に行きます。
<CanActivateAbility>
まずこの関数から行きます。以下にサンプルコードの例を示します。
このメンバー関数、教科書のGetting readyでも説明されていませんし、ちょっとネットでこの関数を調べて見ましょう。
見つかりませんでした。
このAPIはプラグインのせいか情報が全然ネットにないですね。しょうがないのでそのままコピーします。
以下に示すようにヘッダーとソースファイルに分けてコピーしました。
ビルトします。
成功しました。
サンプルコードはUFunctionを使用していませんのでUFunction()はつけないでおきます。
どっかにこのメンバー関数の情報がもう少しないかなと思って元のコードをGameplayAbility.hから探してきました。
もし、このアビリティが今、始動出来るならTrueを返します。副作用はありません。
コメントはサンプルコードのコメントと同じでしたね。
サンプルコードの方はいつでもTrueを返す仕様になっています。ApplyCooldownメンバー関数との兼ね合いはどうなるのでしょうか?まだまだ全然分からないですね。
次にCanActivateAbilityメンバー関数のパラメーターを見てみます。
本来ならばUE4のAPIからそれぞれのパラメーターに使用されているクラスのremarkを読んだりするのですが、今回はそのAPIが見つからないので、直接コードを見ていきます。
<FGameplayAbilitySpecHandle>
そのポイントを特定の許可されたアビリティにハンドルします。
これらはグローバルかつユニークです。
まず、クラスではなく構造体(struct)でした。変数は
だけでした。これは単に整数を保持しているだけの構造体(struct)のようです。
次のパラメーターも調べて見ます。
<FGameplayAbilityActorInfo>
アビリティの一つを使用しているアクターのデータをキャッシュします。
・InitFromActor内のAActor*から初期化します。
・アビリティはどのアクターに付いているのかを知るために使用します。:例)代わりに特定のアクタークラスにカップルされます。
・これらは一般的にポリモーフィズムをサポートするためにポインターとしてパスされます。
・プロジェクトは作成されたデファルトの構造体(struct)のタイプをオーバーライドするためにUAbilitySystemBlobals::AllocAbilityActorInfoをオーバーライド出来ます。
正直何の事が分かりませんがこのアビリティを使用しているアクターの情報をキャッシュする構造体(struct)のようです。
Actorを保持する変数が確かにありますね。
次とその次のパラメーターはNullptrなので最後のoutのパラメーターを調べて見ましょう。
<FGameplayTagContainer>
タグのコンテナはFGameplayTagsの集まりを保持します。FGameplayTagsに追加する事で明示的にタグは保持されます。チャイルドのタグを追加する事から暗示的にタグは保持されます。
タグが何のタグなのかが良く分かりませんが、このタグの中にいろいろな情報を詰めて必要に応じて取り出すのでしょう。
<CheckCost>
以下にサンプルコードのこの関数を示します。
以下に示すように書き直しました。ヘッダーファイルのCheckCost関数の宣言部に実装部が見つかりませんと警告が出ていますが、無視しておきます。
ビルドしましたら、普通に出来ました。
CheckCost関数もネット内に全く解説がないので、実際のGameplayAbility.hのコードを見てみました。
コストをチェックします。もしアビリティのコストを払えるならTrueを返します。
ここのコメントもサンプルコードと同じでした。取りあえずコストをチェックしてTrueかFalseを返すメンバー関数と言う事は分かりました。
このメンバー関数もサンプルコードはTrueのみを返すように実装されていて、この関数の実際の使用方法は良く分かりません。
それではこの関数のパラメーターを調べて見ましょう。
<FGameplayAbilitySpecHandle>
CanActivateAbilityメンバー関数で使用したパラメーターです。
<FGameplayAbilityActorInfo>
これもCanActivateAbilityメンバー関数で使用したパラメーターです。
<FGameplayTagContainer>
これもCanActivateAbilityメンバー関数で使用したパラメーターです。
このメンバー関数はCanActivateAbilityメンバー関数と同じパラメーターをパスしていました。もしかしたらこれらのオーバーライドしたメンバー関数はどれも同じパラメーターをパスするのかもしれません。
<ActivateAbility>
サンプルコードの例を以下に示します。
今度の例はコメントが書かれていませんでした。
元のコードを見てみます。
実際にアビリティを始動します。これを直接呼ばないでください。
ここに、実際のアビリティの動作を実装するのでしょうか?これだけでは分からないですね。取りあえずパラメーターは調べておきましょう。
FGameplayAbilitySpecHandleとFGameplayAbilityActorInfoは他のメンバー関数と同じですね。FGameplayAbilityActivationInfoから調べます。
<FGameplayAbilityActivationInfo>
データが特定のアビリティの始動をトライします。
・我々が権限(authority)であるかどうか告げます。もし我々が予測している(predicting)なら、確認します。
・現在と前の予想鍵(prediction key)を保持します。
・一般的にプロジェクト内のサブクラス化はありえないです。
・値(value)でパスします。なぜならこの構造体(struct)は小さいからです。
となっていました。予想鍵(prediction key)とは何でしょうか?分からない事が更に増えた感じです。この構造体(struct)だけ値でパスしている理由だけは良く分かりました。
パラメーターを見ていると
予想鍵(prediction key)そのものがありました。 予想鍵(prediction key)があり、それをこのパラメーターが管理している事は分かりましたので次のパラメーターを調べます。
<FGameplayEventData>
まずこの構造体(struct)のコメントを見てみます。
タグを基にしたゲームプレイのイベントのためのメタデータ。それは他のアビリティを始動したり、アビリティ特有のロジックを実行したり出来る。
とありました。何らかのイベント発生に使用するみたいですね。
<中断>
今週はリハビリを兼ねての勉強なのでここまで中断します。あんまり進展はありませんでしたが、このレシピは結構難しい内容みたいで、今のちょっと頭があんまり働いていない状態でがんばってもいい成果は出ないでしょうし。来週はもうちょっと情報を 集めてから再トライしようと思います。
<今週の成果>
分かったことと言うか今週の成果をここにまとめます。
・GameplayAbilities のAPIはネットからは見つからないが、GameplayAbilities のクラスなどを定義した実際のコード内にきちんとしたRemarkが書かれておりそれを読めばAPIと同じレベルの情報は得る事が出来るようです。
・アクションRPGの解説で説明されているGameplay Ability Systemと今回のレシピで勉強している“GameplayAbilities API …”は同じ事を述べています。
・以下の推測が正しいと仮定して勉強を継続する予定です。
・アビリティ―は列挙型(enum)で示します。
・UGameplayAbilityクラスからの派生クラスを作成します。この派生クラスで具体的なアビリティ―の内容を決定します。
・GameplayAbilitiesSetクラスからもオブジェクトを作成します。アビリティ―を列挙したenumとUGameplayAbilityクラスからの派生クラスを管理します。
・Game Programming Patternsに出てくるType Objectとの関係については良く分からないです。この関係についての考察は一端保留して先にこのAPIの使用方法を理解します。
GameplayAbilitiesの関数や構造体(struct)のコメントを読んでいる途中で気が付いたのですが、このAPIはマルチプレイで沢山のクライアントがサーバーに接続した状態でのクライアント同士の戦闘をスムーズに行うために開発されたものかもしれません。そうだったら今の私には手に余る内容なので、ほどほどに勉強する事にします。