BLOGブログ

2020.06.03UE4/ C++

[UE4]GameplayAbilitySystemでコンボ攻撃を作る

執筆バージョン: Unreal Engine 4.24

ハローアンリアル!エンジニアの片平です。
今回はBPで組むと複雑になりがちなアクションゲームのコンボ攻撃の処理を、GameplayAbilitySystemAbilityTag機能を使って作成してみました。

GameplayAbilitySystemとは

RPGやMOBA等で頻繁に使用されるアビリティを管理するシステムです。

アビリティとは、キャラクターが繰り出す攻撃、スキル、アイテム使用などのひとつひとつの「行為」です。
また、アビリティによって引き起こされるアトリビュート(=キャラクターの持つ数値、ステータス)の変化、発生するエフェクトなどの見た目上の挙動など関連する要素を効率的に実装することができます。

まだベータな機能ではありますが、FortniteやParagonなどの大型タイトルでも採用されているそうです。

今回は詳細や導入は省きます。上記の記事をご参照ください。
リファレンスプロジェクトとしてはActionRPGが非常に参考になります。

カバーする範囲が広い分、全体を把握しようと思うとかなり覚えることが多いですが、今回はGameplayAbilityComponentGameplayAbilityのみを使用します。
GameplayEffect、GameplayAttribute、GameplayCue、GameplayTask、GameplayEventについては知らなくても構いません。

セットアップにはC++が必須となります。

AbilltyTagとは

GameplayAbilityに設定することができるTag(GameplayTag)です。

AbilityTagでAbilityの呼び出しや実行制限などの制御ができます。
つまり、Tagの設定だけでステート管理をすることができます

今回使用する設定項目の効果について下記にまとめました。

AbilityTags Ability自身が持っているTag
Cancel Abilities with Tag Abilityが実行されているときに、このTagをもつAbilityをキャンセルする
Block abilities with Tag Abilityが実行されているときに、このTagを持つAbilityを実行させない
Activation Owned Tags Abilityを実行している間、所有者にこのTagが付与される
Activation Required Tags 所有者がこのTagを持っているときのみ実行できる。
Activation Blocked Tags 所有者がこのTagを持っているときは実行できない。

コンボ攻撃を作成する

プロジェクト作成

ThirdPersonテンプレートからC++プロジェクトを作成します。
今回はBlogComboというプロジェクト名で作成しました。

アニメーションアセットを用意

今回はマーケットプレイスのやたらかっこいいアニメーションアセットを使用しました。

Frank Action RPG Sword 1 (Basic Set)

以下のアニメーションを使用しています。

  • コンボ1段目:52_Frank_ActionRPG_Sword_Combo_B1
  • コンボ2段目:53_Frank_ActionRPG_Sword_Combo_B2
  • コンボ3段目:54_Frank_ActionRPG_Sword_Combo_B3

ThirdPersonのMannequinで使用できるように上記のアニメーションをリターゲットしておきます。
今回のアニメーションはrootに移動が入っているのでEnableRootMotionにチェックを入れておきました。

GameplayAbilitySystemプラグイン有効化

GameplayAbilitySystem はプラグインによって提供されています。
プラグイン設定からGameplay → GameplayAbilitiesのEnabledにチェックを入れて、指示通りエディタを再起動してください。

GameplayAbilitySystemセットアップ

セットアップに関してはおかわり はくまい様の記事で非常に分かりやすくまとめられているため、そちらをご参照ください。

GameplayAbilityを拡張する都合上、(プロジェクト名).Build.csのPublicDependencyModuleNames.AddRangeには、GameplayAbilitiesの他、GameplayTagsGameplayTasksも追加しておいてください。

ThirdPersonテンプレートから作成していると、ThirdPersonCharacterの親となるCharacterクラス(ここではBlogComboCharacter)が出来ていると思うので、こちらにC++でGameplayAbilityComponentを追加します。

ビルドが終わると継承しているThirdPersonCharacterにもAbilitySystemComponentが追加されます。

AbilityTagの追加/削除ができるようにGameplayAbilityを拡張

デフォルトのGameplayAbilityではBP側から任意のタイミングでAbilityTagの追加/削除ができないためGameplayAbilityを継承したクラスで拡張します。

BlogComboGameplayAbility.h

BlogComboGameplayAbility.cpp

これでBPからAbilityTagの追加/削除ができるようになりました。

コンボ1段目の作成

AnimationMontageの作成

コンボ1段目のAnimationMontageを作成します。

作成したAnimationMontangeに1段目のコンボで使用するアニメーションを追加します。

AnimationBluePrintの編集

ThirdPerson_AnimBPを開き、AnimGraphを以下のようにつなぎ変えます。

これでDefaultSlotでAnimationMontageを再生することができるようになります。

GameplayAbilityの作成

先ほど作成したBlogComboGameplayAbilityを継承したBPを作成します。

作成したGameplayAbilityを開いて、以下のようにBPを組みます。

PlayMontageではMontage to Playに先ほど作成した1段目のAnimationMontageを指定します。

ClassDefaultsのTagsを以下のように設定します。

これによってAbility開始時にAbility.State.Combo1が所有者に付与され、Ability.Stateが付与されているときは実行できない、つまり二重に実行されるのを防ぐことができます。

Characterの設定

ThirdPersonCaracterを編集していきます。

以下のようにClassDefaultsのAbilities – Ability Listに先ほど作成したGameplayAbilityを追加します。

以下のようなBPを組みます。

Zキーを押すとTryActiveAbilitiesbyTagノードでAbility.Action.Attackを指定して実行します。
これでAbilityList内でAbilityTagにAbility.Action.Attackを持つものが実行されます。

武器を持たせないと雰囲気が出ないため適当に持たせましょう。

コンボ1段目完成!

以上の手順でZキーを押すと攻撃を繰り出すことができるようになります。

連打しても多重実行を禁止しているため、アニメーションが終わるまで再度実行はできません。

コンボ2段目の作成

コンボ1段目のAnimationMontageにNotifyの追加

2段目のコンボを作成するには1段目のAnimationMontageにNotifyを設定する必要があります。
今回は先行入力も入れたいので、下の画像のようにアニメーション中に2種類の通知が必要となります。

  • A.入力可能 … この期間に次の攻撃の入力が受け取れます。
  • B.次の攻撃に移行可能 … この期間に次の攻撃に移行することができます。

1段目のAnimationMontageのNotifiesのトラックを右クリックし、Add Notify State → Montage Notify Windowを追加します。

これを上記の「A.入力可能」の通知として、始点を振り切るちょっと前くらい、終点を振り切ったちょっとあとくらいに設定しておきます。
DetailからNotifyNameを「Combo1.Input」としておきます。

さらに+ボタンでトラックを増やし、Montage Notify Windowを追加します。
これを上記の「B.次の攻撃に移行可能」の通知として、始点を振り切る瞬間、終点をAの終点と同時に設定します。

DetailからNotifyNameを「Combo1.Branch」としておきます。

2段目のAnimationMontage作成

1段目と同様にAnimationMontageを作成します。

2段目のアニメーションをセットします。3段目のためにNotifyも追加しておきましょう。

1段目のGameplayAbilityに追加

PlayMontageのOnNotifyBegin、OnNotifyEndから伸ばす形で以下のようなBPを追加します。

OnNotifyBeginが呼ばれた時にはNotify対応するタグを追加し、RemoveGameplayTagsが呼ばれた時にはNotifyに対応するタグを消してます。

<対応するタグ>

  • Combo1.Input → Ability.Ready.Combo2
  • Combo1.Branch → Ability.Begin.Combo2

また、OnEndAbilityにもRemoveGameplayTagsを追加しましょう。

これでAbilityが終了したときに必ずAbility.Ready.Combo2、Ability.Begin.Combo2が消えるようになります。

2段目のGameplayAbilityの作成

2段目のGameplayAbilityを作成します。作成したBlogComboGameplayAbilityを継承します。

ClassDefaultsのTagsを以下のように設定します。

ActivationRequiredTagsにAbility.Ready.Combo2が入っているので、1段目のAnimationMontageで設定した「A.入力可能」の期間のみ実行することができます。

以下のようなBPを組みます。

WaitGameplayTagAddは指定したAbilityTagの追加があるまで待つノードです。
ここにAbility.Begin.Combo2を設定しているので、1段目のAnimationMonageで設定した「B.次の攻撃に移行可能」期間のみコンボアニメーションを再生できます。

Characterの設定

ThirdPersonCaracterのClassDefaultsのAbilities – Ability Listに2段目のGameplayAbilityを追加します。

コンボ2段目完成!

以上の手順で2段目のコンボができました。

連打すれば最速で2段目が出ます。ちょっと遅らせて入力すれば入力した瞬間2段目が出ます。

コンボ3段目以降の作成

3段目以降も基本的に2段目と同様の作成の手順で作成できます。

  • 前段のAnimMontageのNotify追加
  • 前段のGameplayAbilityでNotifyに対応したAbilityTagを追加/削除
  • AnimationMontageの作成
  • GameplayAbilityの作成
  • Characterへの設定

まとめ

というわけで今回はGameplayAbilitySystemのAbilityTagを使ってコンボ攻撃を作成してみました。
GamepalyAbilitySystemを使うことで非同期処理や効率的なネットワーク実装など様々なメリットが得られるのですが、今回はロジックを分散できる点が非常に嬉しいと実感できました。

CharacterのBPこれで済んじゃいますからね。

(参考)趣味で作ったプロジェクトのコンボ処理↓

GamepalyAbilitySystemは今回使ったもの以外にも便利な機能が盛りだくさんなので是非、活用してみてください!