<前文>
寒いです。
<本文>
<目的>
今回のレシピはUAttributeSetを使用して状態(stats)を実装するそうです。確かGameplayAbilities and YouでUAttributeSetについての大変分かり易い解説があったはずです。今回も教科書のレシピの説明だけでは理解しにくいのでgame play ability system について解説した以下のサイトを参照しつつ進めていこうと思います。
公式サイトからの情報です。
・Gameplay Abilities in Action RPG
・GameplayAbilities and You (Unreal Wiki)
・Action RPG | Project Spotlight | Unreal Engine Livestream
(日本語)
・猫でも分かる UE4の新しいサンプル「Action RPG」について(p77~)
公式サイト以外でGameplay Ability Systemについて述べたサイト。
Tom Looman氏による解説
・Tutorial: Creating a RAGE Potion in Epic’s Action RPG
・Gameplay Ability System Tutorial with C++ & Blueprint [Unreal Engine 4 RPG Game]
SabreDartStudiosによる解説
・Intro to Gameplay Abilities in Unreal Engine 4
Unreal Sydneyによる解説
・Intro to the Unreal Engine Gameplay Abilities Module - Unreal Sydney Meetup
(日本語)
おかわりはくまい氏による解説
・GameplayAbilitiesの使い方(セットアップ編)
<方法>
Step.0
新しくこのレシピのためのプロジェクトを作成します。プロジェクト名はChapter12Part10とします。今回からUE4は21.2を使用します。
Step.1
もうこの手順はお馴染みになりましたね。Chapter12Part10.Build.csファイルを開いて"GameplayAbilities"をPublicDependencyModuleNames.AddRangeに追加します。
一応、GameplayAbilitiesだけでなくGameplayTagsとGameplayTasksも追加しておきます。
Step.2
以下に教科書に載っていたコードの最初の三行を示します。
これはUAttributeSetクラスからの派生クラスを作成せよ。と言う事です。クラスの名前はGameUnitAttributeSetとします。
あれ、AttributeSetクラスがない。と思ったらプラグインからGameplayAbilityを追加するのを忘れてました。
追加した後、AttributeSetクラスからGameUnitAttributeSetクラスを以下に示すように作成しました。
教科書通りに3つの変数とコンストラクターを追加しました。
コンストラクターの実装部はサンプルコードからそのまま写しました。
UPROPERTYの宣言に複製を可能にする指定子(specifiers)があるのでしょうか?UPROPERTYのサイトによると、
ありました。この指定子(Specifier)がマルチプレイのゲームなら必要になるのでしょう。
Step.3
アクタークラスからの派生クラスを作成する必要があるようですね。よく考えれば当たり前ですね。前回作成したwarriorクラスを参考にしてもう一度warriorクラスを作成します。
サンプルコードのwarriorクラスを見るとAbilitySystemComponet->InitStats(UGameUnitAttributeset::StaticClass(), NULL);を使用していました。前回のレシピでGameplayAbilitySet 並びにAbilitySystemComponetの宣言と初期化を既に行っているので今回も同様にしました。
手順3の続きには以下のように書かれています。
更に、サンプルのコードでも以下のようにPostInitializeComponents()関数内に書かれているので、
同様にコピーしました。
更にビルドするために必要なコードを追加しました。
試しにビルドしてみると
出来ました。
Step.4
これって、残りは次のレシピでと言う事でしょうか?
Step.5
訳が上手く出来ないですが、英文そのものが言いたい事はアクタークラスから作成したクラスはIAbilitySystemInterfaceからも継承しているようにしてくださいと言う事でしょう。
これで、今回のレシピは終りですので、続きは次のレシピでと言う事なのでしょうか?
<結果>
当然、次回に持ち越しです。
<考察>
考察と言うか解説と言うべきか、今回書いたコードを一つ一つ勉強していきます。まず最初はAttributeSetについてです。
Unreal Sydneyによる解説からGameplayAbilities APIは8大コンセプト、(AbilitySystemComponent, AttributeSets, GameplayTags, GameplayEffects, GameplayCues, GameplayAbilities, GameplayTasksとGameplayEvents)で構成されると判明しました。AttributeSetはその中の一つですので、しっかりここで勉強します。
まず、教科書ですが、以下に示すようにAttributeSetについて解説しています。
要するに、そのアクターが持つ攻撃力、防御力、HPなどの数値で定義されるそのアクター特有の特長をそのアクタークラスに設定するのではなくAttributeSetクラスに設定してそのAttributeSetクラスとアクタークラスを提携させて使用すると言う事みたいです。はい。もうどこかでこれは勉強しましたね。その時も述べたような気がしますが何で属性(attribute)なんですかね。属性(attribute)と聞くと、炎属性とか氷属性みたいな定量的じゃなく定性的な特徴を述べているように感じます。
もう理解した内容を見直す必要はないので、どのように実装するかを見てみます。
普通ですね。
次にこのattributeSetクラスをアクタークラスと提携するために、アクタークラス内で、
AbilitySystemComponent->…を実装します。これだけでアクタークラスとattributeSetクラスが提携出来たの?と疑問になりますが、どうやらこの後にGameplayEffectクラスを設定する必要があってその後で、アクタークラスとattributeSetクラスが提携出来るみたいです。
非常に短いですが、このレシピはここまでなのでこれで考察も終了です。
<おまけ>
今週はこれだけでは短いのでGameplayAbilities and You (Unreal Wiki)を勉強します。今まではサラッとしか読んでいないのでここでしっかり勉強しておこうと思います。特にアクターの設定について今の所、教科書の説明では良く分からないと言うか全く足りないような気がしますので、その部分を特に勉強したいです。
<イントロダクション>
イントロを読み直してみると沢山のgameplay ability system のチュートリアルを書いているサイトが一番に進めるサイトだけあって、学習者が知りたい内容がほとんど全て説明されていました。しかも簡潔かつ丁寧です。ただ私が初めて読んだときはあまり理解出来ませんでした。まずDotaと言うゲームを知らなかったので、マルチプレイにおける魔法の範囲攻撃やその後のクールダウンなどについて良く知らなかったからでした。
<プロジェクトのセット>
早速知らない事が書かれていました。Gameplay Abilityのプラグインを実行した後は、WindowにGameplayCue Editorが現れるそうです。
現れてました。
GameplayAbilityBPを選択しGameplayAbilityを更に選択してUse_Spell_1を作成しそのグラフ内でEvent ActivateAbilityノードとPrint Stringを連結させました。
<キャラクターのセット>
"GameplayAbilities"をbuild.csに加えました。更にUAbilitySystemComponentをアクタークラスに追加しました。
この部分は教科書のレシピでやったのと同じでした。更に、
を追加しました。GetAbilitySystemComponent()を追加しないとビルドエラーになる事は教科書のレシピには載ってなかったです。結構苦労して直した記憶があります。このチュートリアルはここまで丁寧に説明してあるのかとちょっと悔しくなりました。
AbilitySystemを初期化しました。
教科書で同様の初期化を行った時、FObjectInitializerクラスから作成したオブジェクトをコンストラクターのパラメーターとしてパスし、ObjectOfFObjectInitializer.CreateDeafaultSubobject…としたのでしたが、今回はFObjectInitializerクラスを使用していないですね。
を追加し、ビルドすると成功しました。
キャラクタークラスのBPを開くと、チュートリアルが述べているようにAbilitySystem(inheriterd)がありました。
ここまではOKのようですね。
<キャラクターのインプットにバインドする>
アビリティ―システムとキャラクターをバインドします。
ここは、重要な関数なので、もう一度分かっている事と分からない事をまとめておきたいと思います。
<分かっている事>
- 12章9節のPart5でまとめたように、BindActivationToInputComponent()関数はUInputComponentクラスから作成したInputとFGameplayAbilityInputBinds構造体から作成したInputBind内のアビリティをバインドします。
<分かっていない事>
- 教科書のレシピではforloopからGameplayAbilitySetにセットされている全てのAbilityをBindActivationToInputComponent()関数でバインドしていますが、このチュートリアルではしていません。この違いの意味は?
- 12章9節のPart4で述べたように、このチュートリアルではFGameplayAbilityInputBinds の4番目と5番目のパラメーターを指定していない。指定していないと-1になるはず。この意味は?
これは、このチュートリアルをやった後でまた考えてみようと思います。
チュートリアルのこの部分の最後の行に以下のように書かれていました。
アビリティシステムのアビリティの始動とプレイヤーインプットのバインドに成功した。
アビリティの中に始動(activation)が存在しそれとプレイヤーインプットがバインドすると。どうやら、プレイヤーインプットは直接アビリティとバインドする訳ではないみたいです。
<キャラクターにアビリティ―を与える>
キャラクターにアビリティの選択権を与えます。サッと見た感じですがチュートリアルのこの部分と教科書のこの部分は同じ目的を達成するためですが、やり方が大分違うように思えます。チュートリアルの方がよりシンプルで本質を説明しているように見えます。のであえてチュートリアルのみの方法に集中して学習します。
変数を作成します。
ここで重要な事は、TSubclassOf<UGameplayAbility>を使用する事です。GameplayAbilitiesクラスは一つのインスタンスしか作成出来ないので、TSubclassOf<UGameplayAbility>を使用するらしいです。
この変数は、BeginPlay関数内で使用されます。
GiveAbility関数は、教科書では矛盾された説明のあったいわくつきの関数ですがここではかなり興味深い解説がありました。更にGetDefaultObject()によってAbilityのオブジェクトをFGameAbilitySpecにパラメーターとしてパスする事についてなどについての貴重な解説もありました。それらについてのは考察で検討しようと思います。
チュートリアルにあるように、PossessedBY()関数を追加します。
ビルドします。
成功したので、残りのコードは追加しないで、行きます。
コンパイルします。
アクションインプットマップに”UseAbility1”を追加します。
そしてゲームを始めます。
とありますので、
を設定しました。
<結果>
ゲームを始めてみます。
ゲームはクラッシュしませんが、Helloもプリントされません。どこかに間違いがあるみたいです。
ウーン。それでは、直していきましょう。と思ったのですが、ちょうど区切りがいいので、ここからは来週やります。今週はここまでです。