Let's Enjoy Unreal Engine

Unreal Engineを使って遊んでみましょう

UE4 ネットワークでそれぞれの役割が違うマルチプレイヤーを実装する

3月20,21日と2日にかけて『全国ゲーム制作部合同ゲームジャム』というイベントを開きました。
2日間という短い時間でゲームを作るというイベントです。当日の様子は以下のまとめをご覧ください。

2016年03月20,21日 全国ゲーム制作部 合同ゲームジャム #ゲーム部合同ジャム #関ゲ部 #東ゲ部 #名古ゲ部 #琉ゲ部 - Togetterまとめ

そこで今回は以下のようなゲームを作りました。

www.youtube.com

今回はこのゲームについて少し解説したいと思います。

役割が違うプレイヤー

今回たった2日でネットワークマルチプレイヤーのゲームを作るということで、それだけでもかなりハードルが高かったのですが、なんと『プレイヤーはそれぞれ違う役割を持って協力しながらゲームを進める』といった内容の企画に早々と決まりました。

また普通のゲームジャムであればこの時点でこの企画は無理と蹴ってしまうところでしょう。
しかし自分は『普通の内容のゲームを作っても面白くない』と参加する前から思っていたので軽くその企画を受け入れました。

具体的なゲームのルールは、プレイヤーは『クラッシャー』と『サポーター』という役割の違うふたつのプレイヤーをそれぞれ操作します。ネットワークマルチプレイなので、ここでは同一PCですがそれぞれは別PCで動作させることが可能です。

『クラッシャー』はエナジーを放つことで敵を倒すことが可能ですが、敵の姿は見えません。しかし『サポーター』の索敵機能を使うことによって敵を発見することができます。
また『クラッシャー』のエナジーは撃つと減ってしまうので、『サポーター』の補給アイテムを取得することで回復させることが可能です。

ふたりで協力しつつ敵を殲滅させることが目的です。
ゲームはすべてブループリントのみでC++コードは一文字も書いていません。

f:id:alwei:20160323143254p:plain

今回作成したプレイヤーのひとりでこちらは『クラッシャー』。
3Dモデルは今回同じチームとなった、Fate Axisという格闘ゲームを長年作っておられる、六水条 剣さんの自作モデルをお借りしました。

f:id:alwei:20160323143810p:plain

もうひとりは『サポーター』という役割のプレイヤーですが、こちらはモデルなどはなく、単純にカメラだけを持つアクターとなっています。
普段はライントレースでのレイを飛ばしており、そのレイによって『クラッシャー』側からも位置を認識することができます。

このふたつのプレイヤーを操作していくことになります。

マッチング後のスポーン

まずはタイトル画面からマッチングを行ないます。ここでどちらのプレイヤーを選択するかを決めて同時にサーバー側とクライアント側へと分かれます。
マッチングの流れやネットワークの基本は公式ドキュメントや以前に自分が発表した内容のスライドを見てください。

www.slideshare.net

さて、マッチングをすると同時にプレイヤーをスポーンすることとなりますが、実はプレイヤーのアクターは最初から配置済みの状態となっています。
ここにマッチングが完了してマップにプレイヤーがスポーンしてきますが、これはすぐに破棄します。

プレイヤーがレベルにスポーンしたかを確認するのには、"GameMode"クラスのイベントで"Event OnRestartPlayer"というイベントがあります。"GameMode"クラスはサーバーのみしか存在しないクラスで、全体の流れを管理することができます。

あとはこれを使ってサーバーとクライアントで"Is Local Player Controller"ノードで分岐を行ないます。

f:id:alwei:20160323145042p:plain

"FindingSpawnCharacter"は自作のカスタムイベントです。内部では一度だけ『クラッシャー』と『サポーター』のアクターを検索し、リファレンス変数として保存します。
"Un Possess"ノードで現在のプレイヤーコントローラーが操作しているアクターを破棄します。

その直後にリファレンス変数として保存したそれぞれのプレイヤーキャラクターのアクターに"Possess"ノードで操作できるアクターとなります。

f:id:alwei:20160323145535p:plain

ここでクライアントとなる『クラッシャー』がログインしてくるまではゲームが開始しないように、イベントディスパッチャーを用意しておき、ログインが完了したら敵が動くようにイベントディスパッチャーから指示を出します。

これでいよいよゲームが開始します。

サーバーとクライアントで処理を分岐させる

今回のゲームではサーバー(サポーター)とクライアント(クラッシャー)で完全に違う処理を行なわせないといけません。
わかりやすいのは敵がクライアント側からは見えないというところです。

f:id:alwei:20160323150308p:plain

これは"Event BeginPlay"の段階で"Switch Has Authority"マクロで分岐し、"Set Actor Hidden In Game"ノードで敵の姿を見せなくします。

『サポーター』側では索敵行動をとると、周辺にエフェクトを発生させ、"MultiSphereTrace"ノードでヒットしたアクターを取得し、"Enemy"のタグを持つものだけを配列に保存しておきます。

f:id:alwei:20160323150704p:plain

念の為に撃ったタイミングで一度配列はクリアーしておきます。

f:id:alwei:20160323150743p:plain

タグを持つアクターだけを保存。ループ終了後にアクターの表示をトグルさせます。トグルと書いていますが、ここでは強制的にクライアントのみで表示をオンにさせています。

f:id:alwei:20160323151040p:plain

一度表示をオフにし、Delayで10秒待ってから再度表示をオンにします。この辺りはブループリントだと本当にサクっと作れて良いです。

ここで考えとして、とても重要なのは今操作しているアクターの権限をサーバーかクライアントのどちらが持っているか?ということです。
『サポーター』はサーバーなので、処理は自動的にクライアントへと複製されますが、『クラッシャー』はクライアントなので、『クラッシャー』内の処理はサーバーへと送信してあげなければいけません。

この辺りの考え方については、先に紹介したスライド内の『RPC(リモートプロシージャコール)』についてを読んでみてください。

変数のレプリケート

最後に変数のレプリケートについて。レプリケートとは変数をサーバーからクライアント上へと複製して送信までしてしまうことです。サーバー上で動いているアクターは変数の"レプリケーション"を設定するだけで自動的にクライアントへと情報が同期されます。

f:id:alwei:20160323152710p:plain

"Replicated"を設定すれば、サーバー上で変数を更新するだけで同期が行なわれます。"RepNotify"を設定した場合には変数が変更された際に変数名と同じ名前がついた関数がイベントのように、サーバーとクライアント両方で呼び出されることとなります。

もし、変数がクライアント上にしかなかった場合、この場合にはRPCイベントの"Run On Server"を使ってサーバー上へと変数の値を送信してあげましょう。

f:id:alwei:20160323153419p:plain

上記は単なる例です。まずはアクター自身がサーバーにあるものかクライアントにあるものかを理解して使えばそんなに難しくはないはず。

理解してしまえば一気に作れる

UE4のネットワークマルチプレイヤーの仕組みは本当に良くできており、一度理解してしまえば高速にマルチプレイヤーのゲームが作れてしまいます!
がんばればゲームジャムという短い時間でも十分なネットワークゲームができるはずです!

ぜひ一度UE4でのマルチプレイヤーゲームを作ってみてください。