株式会社ヒストリア様が開催しているUE5ぷちコンに応募した作品制作に対する振り返りです。
今回のテーマは「ゆうえんち」でした。
提出作品
「サイエンスバスターズ」というタイトルのゲームを作成しました。
ジャンルはライド型のシューティングゲームです。
<ダウンロード>
無料です。
BOOTHのサイトへ移動
<作品動画>
提出後に一部更新を加えました
コンセプト
テーマについては、素直に「遊園地」として解釈としました。
●作品のコンセプト
遊園地で遊ぶという滅多にない状況で、2人の力を合わせることで達成感を共有してもらうこと
●技術的なコンセプト
・オンラインマルチプレイゲームの実装経験を積むこと
・Gameplay Ability Systemを使用したマルチプレイゲームを実装すること
・Gameplay Ability Systemで過去作品に使用していなかった処理を作成すること
がんばったこと
●デバッグ
一番苦労した点です。
実装内容を変更したらServer / Clientの各々で動作確認を行う必要があることと、ServerとClientで処理を分ける必要がある箇所も存在するため確認項目自体も多くなるので、シングルプレイと比べて体感2倍は手間がかかったような気がしました。
●移動処理
今回は操作するキャラクターをライドにアタッチして、スプラインに沿ってライドを移動させるという移動手段となるので、上手く動作する設定を見つけるまでに色々試行錯誤しました。
・ライド:「Replicate Movement」をTrueにして、ReplicateしたTimelineComponentでServer/Client両方でSpline移動させる(Tickでも問題ないと思います)
・キャラクター:「Replicate Movement」をFalseにする
キャラクターの「Replicate Movement」をTrue + ライドの移動補完(Client、Server間の通信時間と速度に応じてClient側の移動距離を補正)でもPIEとStandalone Gameでは問題なく動作しましたが、パッケージで実行した時に、操作キャラクターが小刻みに震えるような挙動をしたので上記の設定に切り替えました。
●ペアの照準の表示
ペアのプレイヤー(操作していない方のプレイヤー)のマウスカーソルで指している位置を表示させる処理が該当します。
共通で破壊できる的が存在することと、互いの武器のショットを当てる必要があるので、ペアがどこを狙っているかを示す必要があるので、上記の処理を実装しました。
カーソルの移動(インプットイベント)は各操作プレイヤーでのみ実行されるので、実装内容としては以下になります。
①操作プレイヤーのマウスで指している位置を取得
②Server/Clientの両方に存在するアクタに、Remote Procedure Call (「Server (BPの表示名は「Run on Server」)」)で、マウスで指している位置を渡す
③ペアのプレイヤー方に②の位置を渡して照準のWidgetを移動させる
今回は①と③はPlayerController、②はPlayerStateを使用しました。
注意事項は以下の通りです。
・PlayerStateの「Net Update Frequency」の値をデフォルトより高い値にする(デフォルトでは位置変更が飛び飛びになるため)
・②で実装するイベントは”Unreliable”の設定をする(標準の位置は大まかに分かればよいので、ロストしてもゲーム進行上の支障はないため)
●自前のAbility Taskの作成
「Wait Gameplay Event」などのAbility Taskを使用すれば、Gameplay Abilityで特定の条件になるまで待機するような処理を作成できるため、Gameplay Ability単独で実装できる範囲が広がるので(例えば、アクションゲームのコンボ入力待ちの処理も作成可能)、カスタマイズできるようになった方が良いかと思いましたので、独自のAbility Taskを作成してみることにしました。
今回実装したAbility Taskは、Gameplay Abilityのエンジンプラグインで実装されているコードを流用できるので、実装難易度は高くないとは思います。
| 対象 | 処理内容 |
| チャージ判定 (WaitChargeInput) | 以下のタイミングで続きの処理を実行させる ・ショットのインプットボタンを押し続けた時間がチャージ判定となった時 ・ショットのインプットボタンをリリースした時 |
| ショット時のヒット対象取得 (WaitShootTargetData) | ・操作プレイヤーの場合:マウスカーソルの位置を元にショット時のヒット判定を実施 ・操作プレイヤー以外の場合:上記の操作プレイヤーのヒット判定結果を受け取るまで待機 |


●オンラインスコアランキングの作成(作品提出後に追加)
外部のデータサーバーを使用してオンラインランキングを作成しました。
初めてPHPを触ったので時間はかかりましたが、レコードの追加・取得・削除の3つは無事できました。
個人情報の極力含めないようにしたかったので、プレイヤーの識別情報はニックネームだけにしました。キー重複を考慮してUniversally Unique Identifier(UUID)をキーに設定しています。

ハマりポイント
実装時に困った or 注意した方がよい点について、ピックアップでの紹介になります。
●移動処理
「がんばったところ」で紹介した通りの内容です。
毎フレーム「Set Actor Location」で移動させることは、移動の同期においては相性が悪いのだと感じました。
●Gameplay AbilityにおけるRemote Procedure Call (RPC)の実行
Gameplay Abilityで「NetMulticast (BPの表示名は「Multicast」)」もしくは「Client (BPの表示名は「Run on owning client」)」のイベントを実装しても、Client側では処理は実行されません。
Gameplay Abilityで①~③を実行した時、③が動作しなかったので気づきました。
①(Server/Client両方) ショットの処理を実行
②(Serverのみ) 的にヒットした場合、的の破壊可否の判定を行う
③破壊できる場合、RPCでClientにも破壊エフェクトを表示(GameplayAbilityの設定依存かもしれないですが、GameplayCueを使用した時はClient側でエフェクトが表示されなかったためRPCの使用を試しました)
理由はGameplay AbilityはRemoteRole = “Simulated Proxy”のアクタ (今回ではClientにおける、Server側の操作プレイヤーが該当)には複製されないので、イベントの処理を実行する対象がないためです。
※「NetMulticast」でイベントを作成した時にコンパイル時に上記のエラーが表示されますが、「Client」で作成した場合にはエラーはでません。
的の破壊エフェクトの表示については、今回は的側で実装しました。
●Anim Notifyの実行対象
複製したアクターでアニメーションを再生する際、そのアニメーションに設定しているAnim Notifyも実行されるので、サーバーもしくは操作プレイヤーでのみ実行する処理を含めている場合は、対象外のアクタで処理が行われないようにする必要があります。
所感
マルチプレイゲームの実装にGameplay Ability Systemを使用することについて、アビリティの実行処理のトリガーやAbilityTaskの各種処理が考慮させた作りになっているため、シングルプレイでの実装時と比べて煩雑な処理を書かなくても良かったので、今後マルチプレイのゲームを作る際にも利用してよいと感じました。
マルチプレイゲーム実装における基礎的なところについては、チュートリアル・ドキュメントをあまり見ないで実装できたので身についてきたのでは思います。Gameplay Ability Systemにおけるマルチプレイの実行制御に関しては、今後Gameplay Ability Systemを使用する際にでも理解を深めていければと思いました。

コメント