[UE4/UE5] GASでオンラインゲーム Part5 雪玉を渡す候補の相手を光らせて、雪玉を渡す

Post 2022年3月4日金曜日

GameplayAbility GASでオンラインシリーズ UE4 UE5 Unreal Engine オンラインゲーム

Part 1の一部になります。

前回の続き

今回はGameplay Ability System (通称GAS)を使って、雪玉を渡す相手を光らせて雪玉を渡します。

お約束
この記事作成にあたって使用した主なUnreal Engine バージョンUE4.27.2 / UE5 Preview1

本日のゴール

雪玉を渡す相手を光らせて雪玉を渡します。

今回スマートに解決できなかったなぁ。まあ仕方ないですけど。


参考文献

https://github.com/Pantong51/GASContent/blob/master/Tutorial_Attribute_Delegates.md

https://github.com/tranek/GASDocumentation/blob/master/README.md#412-setup-and-initialization


第一段階:雪玉を渡す候補の選定

これにはいくつか方法がありますが、思いつくのはMultiSphereTraceForObjectsを使う方法ですかね。これなら自分の周りにいるキャラを全て捜査することができるので、あとはそのキャラが味方かどうかを判定して・・・というやり方です。

これでもいいんですが、問題がありまして、このMulti〜を回し続ける必要があるんですね。
まあそれでもやれなくはないんですが、ちょっと面倒かなと思ったので別のアプローチをすることにしました。

少々面倒ですが、基本的な方法で、キャラにCollisionを追加して、そのCollisionにOverlapしたら配列にそのキャラを追加し、そのCollisionから抜けたら配列から抜くようにして、常に雪玉を渡す候補を変数として保持しておくことにします。

ちなみに敵キャラは雪玉をパスする対象になりません。このため、CollisionにOverlapしたキャラクターに対してCastして、Player Stateを取り出します。
このPlayer Stateにどのチームに所属しているかの情報が入っているのでそれを取り出して、自分のチームと同じなら配列にAddするという実装になっています。

実際にはPlayer StateにCastする必要はなく、Begin Play時に各キャラクターが、自分のPlayer Stateから自分のチーム番号を取り出して、適当に変数化しておけばいいんですが、下ではわかりやすくしております。
ちなみに、Begin Play時にClientは遅れてSpawnされるので、Begin Play時にPlayer Stateなどをゲットしようという場合には、0.4秒ほど(マシン性能による)遅れてからgetするように設定しましょうね。(15分悩みました)
実際の運用時は、プレイ開始時にはすでにどっちのチームかなんて決定しているはずなんで、問題はないと思いますが、ともかく気をつけましょう。

これでパスのターゲットはできました。


第二段階:雪玉を渡す候補を光らせる

まず"P キー"を押している間、先程作った配列変数の誰かをランダムに選んで(まあ配列の1番目でいいでしょう)、そのキャラを光らせたいですね。このGameplay EffectとGameplay Cueを作りましょう。

キャラクターの周囲を光らせるエフェクトについては、こちらのブログが参考になりそうです。

[UE4] PostProcessでObjectにOutlineをつける~前編~[UE4.18] / Qiita by @kanurapoison

UE4 誰でもわかるアウトライン入門/ alweiさん(神)


「オブジェクト アウトライン」でググると幸せになれそうです。Youtubeもありました。

こういった、アクターに対する視覚効果なんかはGameplay Cueの得意分野です。(→今回挫折しました笑)

早速やってみましょう。今回はPostProcessを使ってみます。

meshの周囲を囲うノード
どうも調べると、PostProcessにマテリアルを設定して、Set Render Custom DepthをOn/Offすればいいみたいですね。簡単やん。

あとはGameplay Cueと組み合わせるだけやーとやってたんですが、結論から言うと、頓挫しました。

実際の実装では、Gameplay Cueを一切使わなかったです結局。。。

---

以下供養のためのメモ

どうも勝手にReplicationされちゃうんですよねエフェクトが。GAをLocal専用にしてみたりしたんですが、そうなるとなぜかSet Render Custom Depthをオンオフするタイミングが思ったようにならなくて、謎な現象が頻発しました。(Serverでは問題なく起動していたのでまじで謎のままです。)

ちなみにGameplay Cue Notify ActorというC++のクラスを継承してBP化したものを「Gameplay Cue」として使います。

ポイントとして、"On Active" "On Remove"という開始時と終了時の処理(関数)を継承できるので、非常に便利なんですよね。なんで開始と終了時にSet Render Custom DepthをON/OFFしたんですけど、なぜかClient側だと、即時終了しちゃうんですよね。なぜや。ためしにGameplay CueにNiagaraをセットして使ってみたところ、そっちは問題なくClientでも動作しているんですよね。なので原因が全く謎のまま終わりました。

On Active関数

私が間違っているかもしれませんが、Gameplay Cueを使う場合は、基本的にNiagaraと組み合わせるのが良さそうです。間違ってるかもしれませんが!!

だれか原因がわかったら教えて下さい〜〜。

ちなみにGameplay Cueを起動するにはGameplay Effectを使う必要があって意外と面倒だったので、視覚効果だけ生じさせたい場合は使わないほうが楽かもしれません。(Game CueをSpawnさせればいいんですが、それだとNiagaraをSpawnさせるのとあまり変わらない)

---

実際の実装

すごい地味ですが、GA_Pass内で、Set Render Custom Depthノードを入りきりするだけです。すっごい地味だったので詳しくは割愛します。

光らせるのは、自分の画面だけなので、GA_Pass自体をLocalだけで動作するように設定します。一応Is locally Controlledノード使いましたけど。



第三段階:雪玉を渡す

雪玉を渡すこと自体はGameplay Effectでなんとかできると思いますね。
Gameplay Ability実行時に、渡すアニメーションを実施、無事に再生が終わったらコストとして雪玉を一つ消費して、相手側の雪玉を一つ増やせばいいわけです。

さて、Gameplay Effectを動作させる手順ですが、すでに雪玉でやっていますが、GA内で使う場合はちょっと違うんですよね。
ApplyGameplayEffectToTarget + Ability Target Data from Actor

このノードの組み合わせを使います。これでTarget DataにつないだアクターにGEを与えます。

しかーし
今回このノードは使いません。(おいおい)
なぜかは知りませんがRPC Run On Serverは、GA内で使えないんですよね。理由は謎ですが、GA内で何らかのRPC制御が働いているようです。

今回このGAはLocal動作オンリーで動作させているので、どうやってもAuthority側で実行することができないんですよね。やり方ご存知のかたがいたら教えて下さい。

なので、キャラのBP内でRPC Run On Serverのイベントを作って、Castしたキャラから引っ張ってこのイベントを呼び出します。
ApplyGameEffectToSelf

こっちで使うノードはいつものノードです。(ApplyGameEffectToSelf)
「Target」につなぐノードは対象のアクターではなくて、ASCなので、アクターから一旦持ってくる必要があります。
Get Ability System Component

詳しくはこっちのゴール2を見てください。

逆に自分の雪玉を減らす必要があるんで、それはGAのコストで実装します。

ちなみにパスする際に、雪玉がマックスじゃないかを判定する必要があり、そのためにAttributeを引っ張ってくる必要がありますが、それはASCから
Get Float Attribute from Ability System Component
このノードを引っ張ってくるだけです。

あるいはアクターから直接引っ張ってくることもできます。
Get Float Attribute
今回は不完全燃焼でした。
おわり