【UE5】GameplayAbilitySystemを使ったコンボ攻撃通知の実装【GAS】
いい感じのコンボシステムができたので備忘録的にかきかき
以前にもGASについて書いてるからこっちも参照してね
【UE5】GamePlayAbilitySystemによるコンボ攻撃の実装とそれに利用する小ネタ 前編【GAS】 - ネリスさん備忘録
【UE5】GamePlayAbilitySystemによるコンボ攻撃の実装とそれに利用する小ネタ 後編【GAS】 - ネリスさん備忘録
基本的なコンボのつなぎは上記の通りなので割愛。
- 前置き
- 当たり判定表示用のAnimNotifyStateを作成する
- 通知を受け取り攻撃判定を発生させる処理をAbilityに実装する
- Abilityに渡したいデータの構造体を作成する
- 渡したいデータの構造体を持つObjectクラスを作成する
- Abilityにデータを渡す
- Abilityが受け取ったデータを使い当たり判定を生成する
- まとめ
前置き
具体的に言うと、Montage内で攻撃判定のサイズ、効果時間等を指定できるというもの
その気になれば当たり判定の形状、ダメージ量、当たり判定のなんかまでMontage内でコントロールできるし、好きなデータをAbilityに渡すことができる。
アビリティ側を徹底したらMontageを増やすだけでアクションを追加できると思う。
そもそも、こういう仕組みを作ろうと思ったのは、当たり判定生成の処理があまりにも冗長で、扱いにくいものだったためである。
↑のような方法で攻撃判定を実装していたが、連撃だとか違う種類のダメージを与えようとすると通知時に設定したNotifyNameでSwitchして当たり判定を生成する処理がその回数分増殖していくのは見るに堪えない…
そこで、使いまわしをしつつパラメータをMontage側で指定することで
Ability側の処理を一つだけで済むように改修したのがコレ。
このブロックだけで何度でも当たり判定を生成できるため、Ability側の処理がスッキリする。
ベースクラスにマクロや関数で実装してしまえば当たり判定生成の処理はノード1個置くだけで終わりというレベルにまでできるだろう。
BaseDamageは試験的に直接値を入れてるだけなので、これもMontage側で指定できるよ
今回説明するため、以前作ったコンボ攻撃は使わず
新しくスキル攻撃を1つ作成する
冒頭でもあった大きく振りかぶってたたきつける攻撃を作る。
Montageの作成までは割愛する
当たり判定表示用のAnimNotifyStateを作成する
コンテンツブラウザで右クリックして
「AnimNotifyState」で検索してBPを作成
名前は「ANS_SpawnDamageCollision」としておく。
クラスを開いたら、変数を3つ作成する
LocationOffset:当たり判定の中心点
BoxExtent:当たり判定のサイズ
BoxRotation:当たり判定の回転角度
それぞれの変数はMontage側から編集したいため
「インスタンス編集可能」「スポーン時に公開」にチェックを入れておく
この変数宣言自体は最低限必要なものなので、必要に応じて増やしてね
それが終わったら
関数の横あたりにあるオーバーライドからReceived_NotifyBeginを選択し関数をオーバーライドする。
この関数はMontageでNotifyStateが開始した瞬間に呼ばれるもの
オーバーライドした後はこんな感じにノードを組む
TotalDurationはNotifyStateの実行時間なので、これをそのまま表示時間、判定の発生時間に使える
ここまで出来たらMontageの通知ステートを追加から
ANS_SpawnDamageCollisionを配置する
いい感じの長さにしたら
それぞれのパラメータを設定する
これでMontage内で当たり判定表示ができた
次はデータを渡される側のAbilityを実装していく
通知を受け取り攻撃判定を発生させる処理をAbilityに実装する
場所はAbilityに戻って、Montageを再生している後ろにWaitGameplayEventノードを置く
これにより、どこかでSendGameplayEventtoActorノードが呼び出された場合にこのノードが起動する。
EventTagにはAnimation.Notify.Collisionとつけておく。名前は任意のものでOK
そしてその後ろに当たり判定を生成する処理を追加する
自分は当たり判定をActor化しているので、これを繋いでいる
後はこの当たり判定に渡すべき値をMontageから渡せるようになればOK
Abilityに渡したいデータの構造体を作成する
で、どうやってMontageからAbilityに値を渡すかに関して
MontageがAnimNotifyStateを呼び出し、SendGameplayEventtoActorを呼ぶことでAbilityへ通知が送れるのだが、ここで問題が一つある
AnimNotifyState内ではActorをSpawnすることができないため
当たり判定用のCollisionを作成してダメージを与えるといったダイレクトな手段はとりにくい。
そのため、AnimNotifyState内でも生成できるObject型に構造体を格納して、それを渡すことで実現する
構造体の内容はこんな感じ。
与えたい情報は場所、大きさ、回転、あと発生時間。
渡したいデータの構造体を持つObjectクラスを作成する
Object型のクラスを生成する
そして先ほど作った構造体をメンバ変数として設定する
これだけ!
あくまで格納しているだけのものなので、特別な処理は書いてない
自分はこのパラメータを取得するためにインターフェースを追加したりしてるがお好みでどうぞ
Abilityにデータを渡す
AnimNotifyStateのほうに戻り、こんな感じでデータ格納用Objectにデータを入れて生成し、SendGameplayEventtoActorのOptionalObjectにつなげる
下段の処理はプレイヤーからみて設定したLocationを設定できるよう計算している
先述の通りAnimNotifyの中ではActorは生成できないが、Object型は生成できるため
こういったデータの渡し方が可能となる。
生成したObjectが残り続けるとかが無ければいいんだけどね。
Abilityが受け取ったデータを使い当たり判定を生成する
Abilityのほうに行き、大体こんな感じに…
WaitGameplayEventノードのPayload戻り値にはNotifyStateで設定したObjectが入っているはずなので、Castするなりインターフェースを使うなりして当たり判定用の構造体を引き出す
こうやって任意の値を引き出すことができるので、当たり判定のみならず
なんか色々とできそうな構成だった
まとめ
今回はAbilitySystemと絡めたMontage→Abilityへのデータの渡し方として紹介したけど
考え方だけでいえばMontage→AnimNotifyStateまではAbilitySystemは関係ないし、そこからAbilitySystemではなくGetOwnerからアニメーションを持つActorをとれるので、作り方次第ではキャラクターに対して任意の値を渡すこともでき、使い方は無限大
もしAbilitySystemを中継しない場合はObjectを作る必要もなく、Set関数とかを作ってやれば足りるのでもう少し楽だったかもね
AbilitySystemの回からここまで、バチクソに長い…
動画で一本にしてここまでを通したら1時間ぐらいかかるんじゃないかな?
しかし今回、説明が行ったり来たりしてしまって妙に長いし…
でも先に作ることだけやると、何で作ってるかわからんし…
全体を俯瞰してみせるのが最初だったか。
ともかくこれでこの記事は終了。
やる人がいるかわからんけど、何かの参考にでもなれば。