第15回ぷちコン「たぬ吉の大冒険」振り返りその3<GameplayEvent、GameplayTask編>
注》この記事はこの記事の続きです。
この記事では第15回ぷちコンの振り返りとして、「GameplayEvent」と「GameplayTask」の解説をしていきます。
お品書き
・GameplayEvent、GameplayTaskを実装してみる
注》今回解説する部分は結構ネットワーク分野と関連しているため、自分でも理解できていない部分が比較的多いです。ご容赦ください。
・GameplayEventについて
GameplayEventはGameplayAbilitySystemにおいてGameplayTagを使用した特殊な使い方をできるStructureです。GameplayEventの情報はよくPayloadと呼ばれ中身はこうなっています。
EventTagはGameplayEventにおいて最も中心的な役割を持つGameplayTagです。これについては後で解説します。
そして実は以下の項目全ては一応の型は決められているものの、どう使うかはユーザーに委ねられています。例えばInstigatorというActor型の項目があります。攻撃などの時は例えば攻撃する側がここに登録されることが多いし、その方が問題も起きにくいと思いますが、しかし攻撃される側を登録しても全く影響はありません。このデータ型をどのように使うかはほぼ完全に使用者次第となっています(少しだけ例外はありますが…)。そしてもちろん普通のVariable変数として扱うことも可能です。
さて、問題は一番上のEventTagでして、これだけは少し毛色が違います。GameplayEventは基本的にSendGameplayEventToActorというノードを介して扱います。
SendGameplayEventToActorは特定のActorにGameplayEventの情報を送るものですが、EventTagに特に何の指定もしていない場合、EventTagにはSendGameplayEventToActorのEventTagが入ります。ではActorに送ったPayloadですがその受け取りはどのような形で行われるのでしょうか?
使い方の一つはGameplayAbilityのActivateです。そう、GameplayEventからGameplayAbilityをActivateすることができます。それではこれから"GAS_Test"プロジェクト内でZキーを押すとActivateしていた攻撃を今度はGameplayEventからActivateさせられるようにしてみましょう。
まずGASCharacterのEventGraph内です。元の状態はこうなっています。これを…
このようにします。Payloadはとりあえず何も入れなくて大丈夫です。もちろんこれだけではZキーを押しても何も起こりません。次はGPA_Attackに移動します。
さあこれが元の状態です。まずは先頭のEventActivateAbilityを削除します。このノードがあると絶対にGameplayEventによるActivateは起こらないようになっています!必ず削除してください!そして今度はEventActivateAbilityFromEventというノードを同じように配置します。
しかしまだ何も起こりません。GameplayEventによるActivateを引き起こすには更にClassDefaultsのTriggersカテゴリのAbilityTriggersを追加し、TriggerTagにキーとなるEventTagを設定します。それから、これは初期状態でそうなっているので問題ないかと思いますが、TriggerSourceはGameplayEventにしておきます。
さあ、これで準備が整いました。実行してZキーを押してみましょう。以前と同じように攻撃が発動するはずです。この方法の利点はPayloadによって多くの情報をAbilityに持ち込める点にあるでしょう。
これだけの情報をActorからAbility内に持ち込めます。また、この方法でAbilityを呼び出すと、AbilityのClassDefaults->TagsカテゴリにあるSourceRequired/BlockedTagsとTargetRequired/BlockedTagsに意味が生まれます。
PayLoad内にInstigatorTagsとTargetTagsという項目がありますが、これがつまりAbility内におけるSourceTagsとTargetTagsですRequiredの場合はInstigatorTagsやTargetTagsにそのTagが登録されていなければ発動せず、逆にBlockedの場合はInstigatorTagやTargetTagsにそのTagが登録されていれば発動しません。
GameplayEventについてはWaitGameplayEventというノードを使う活用方法もあるのですが、WaitGameplayEventはGameplayTaskに属するノードなので、次はGameplayTaskについて解説します。
・GameplayTaskについて
正直良く分かってないんだ。
GameplayTaskはGameplayAbilitySystem内で非同期処理を実現するための仕組みで、特にAbility内のみで呼ばれるものはAbilityTaskと呼ばれます。というか自作しない限り全部これです。
Taskは自作することもできますが、すでにかなりの数がノードとして実装されています。GameplayAbility内で"wait"で検索してみると多さが分かるでしょう。まあDelegateのようなことをするものだということは分かるし、名前である程度使い方が分かるものも多いですが、Targeting関連の部分は正直自分にはよく分かりませんし、更に言うと…
この2つのノードの違いは何かと聞かれても、僕には説明できません。AbilityTaskノードには全て付いていますが、AsyncTaskのPinが付いている理由も分かりません。繋がるノードは多いようなので、恐らく何かできるんでしょう(適当)。
自作についてはえーっと…(目が泳ぐ)…あー…
ま、とはいえある程度使い方が分かるノードも存在しています。今回はその中でGameplayEventの情報を受け取るWaitGameplayEventを使用していきます。
・GameplayEvent、GameplayTaskを実装してみる
今まで作成してきたAbilityの中身はおおよそこんな感じでした。
PlayMontageにいろいろなExecutionPinが付いているので、EndAbilityを繋げることができていますが、ではこういったPinが無かった場合どうすればいいでしょう?
具体的にはTimelineを使用してアニメーションを作り、Timelineが終了したらEndAbilityしたいのです。しかしTimelineはAbilityでは扱えずActor内での実装になります。まあTimelineを発動するだけなら特に問題にはならないのですが、問題は発動したTimelineの終了をどうAbilityに知らせるか、です。現状でこれを通知する手段がありません。
今回はGameplayEventとGameplayTaskであるWaitGameplayEventを使用してこの通知を行い、「武器が大きくなる」というTimelineを使用したアニメーションを作成します。
まずは下準備として装備した武器の大きさを小さくします。
0.5倍にすればまるでナイフのようになります。それではTimelineを作成しましょう。
Timelineの中身はこうなっています。
新しいAbilityを作成します。名前はGPA_ExpandWeaponとしました。
とりあえずノードをここまで組みます。本来はBPInterfaceを用意した方がいいのですが、面倒なのでCastしました。続いてWaitGameplayEventを使用し、
このようにします。Payloadに情報を乗せることはできますが、この場合は必要ありません。Tagsカテゴリはこのように…
これをAbilityListに登録して…
CキーでActivateするようにします。
そしてTimelineが終了したらSendGameplayEventToActorで"Event.OnTimelineFinished"のTagを自身に送るようにします。
実行してみると…
Cキーを押す度に剣が大きくなったり小さくなったりしています。このようにActor内のTimelineの状態を取得するのにGameplayTask、GameplayEventは使用できます。
ふー、GameplayTaskとGameplayEventは比較的楽でしたね。というかTaskについてはまだ分かっていないことが多くて下手なこと書けないというのはありますが…ネットワークをうまく使えればGameplayTaskをC++でゴリゴリ自作するなんてことになるんでしょうか?
というわけで次回はGameplayCueです。やったー!最後だ!
ご指摘、ご質問、ご意見などあればコメントにお願いします。
続きの記事はこちら