LoginSignup
6
5

[UE4]ログインからログアウトまで!オンラインゲームのフローを作る!

Last updated at Posted at 2023-12-11

はじめに

この記事では"UnrealEngine4"でのオンラインゲーム開発における「セッションの作成から破棄まで」を取り扱います。
本記事の段階でUE5.3がリリースされています。本記事の内容はUE5で利用できる部分もございますが、参考程度にご利用ください。

注意

本記事が初投稿になります。
至らない部分もありますが、お手柔らかにお願いします。

前提

  • UnrealEngine4.27.2を使用しています
    image.png
  • プラグインなどは一切使用していません
  • C++を追記したり改変したりしていません
  • 本記事では変数やアクターの同期(レプリケート)などのオンラインゲーム開発のインゲームに関する内容は扱いません
  • 本記事はlistenサーバーを前提とした設計となります

結果|この記事で得られるもの

オンラインマルチゲームを開発する際に必要となる「セッションの作成から破棄までの流れ」がわかります。

後日にはなりますがサンプルプロジェクトを配布する予定です。

本題

1.プロジェクト準備

プレイヤーキャラクターやレベルがないと確認がやりづらいので「ThirdPersonTemplate」をおすすめします。
今回はC++を利用しないのでBlueprintのプロジェクトを作成します。

2.タイトル用のレベル「L_TitleMap」を作成する

image.png
image.png
作成するレベルは「空のレベル」で問題ないです。

3.タイトル用UIになる「WBP_Title」を作成する

タイトル用のWidgetを作成します。
image.png

デザイン(WBP_Title)

image.png
タイトルテキストとボタンが3つあればどんなデザインでも問題ありません。
各ボタンには、グラフで操作をする際にわかりやすいように、名前を付けるのがベストです。
image.png

  • Btn_CreateSession
    セッションの作成(ホストになって部屋を立てる人)のボタンです
  • Btn_FindSession
    セッションの検索画面(部屋を探す人)を開くボタンです
  • Btn_QuitGame
    ゲームを終了するボタンです
    と命名しました

4.セッション作成画面「WBP_CreateSession」を作成する

セッション作成を行うための設定画面を作成します
※プレイ人数やLAN/WANの接続方法の切り替えを行える画面になるため、仕様によっては必要ありません。
image.png

デザイン(WBP_CreateSession)

image.png
セッションを作成するホスト側の設定項目になります。
参加できる最大人数と接続方法を設定できるようにボタンを配置します
image.png

グラフ(WBP_CreateSession)

グラフの全体です。画像のようにノードを配置していきます。
各ボタンのOnClickedイベントに対して記述していきます。
image.png
ボタンのイベントは、変数でイベント出したいボタンをクリックして画面下に出てくるOnClickedの+マークを押すことで出すことができます。
image.png

セッションの作成

image.png
『Create Session』を実行することで、ホストとしてオンラインに接続し、部屋(Session)を作成することができます。"Public Connections"には参加できる最大人数を設定しますが、デザインしたように数を変動できるようにしたいので変数化したものを入れておきます。"Use LAN"はLANかWANかを選択でき、Trueの状態ではLAN回線でアクセスを行います。家庭内や職場など限られた環境内であればLANがTrueの状態で問題ありません。
具体的にはSteam Subsystemなどを利用する場合にはfalseで使用することがあると思います。
https://docs.unrealengine.com/4.27/ja/ProgrammingAndScripting/Online/Steam/

セッションの作成に成功した場合は、レベルを開きます。
OpenLevelノードで実行をしますが、今回はoptionsに「listen」と記述します。
レベルを開いた段階でホストとして認識され、後述するFind Sessionでの検索に引っかかるようになります。
開くレベルは特に特別なものである必要はなく「ThirdPersonExampleMap」で問題ありません。
今回は「ThirdPersonExampleMap」をコピーした「L_GameMap」を開くようにしています。

タイトル画面への遷移

image.png
UXとしてタイトルに戻れるほうがいいので、タイトルWidgetを開いて、この画面(WBP_CreateSession)を閉じるように記述しておきます。

LANとWANの切り替え

image.png
左右矢印(> / <)をクリックした際に、LANとWANが切り替わるように先ほど作成した「Use LAN?」の変数を切り替えられるようにしておきます

最大人数の設定

image.png
こちらも矢印を押したときに人数を変えられるようにするのですが、今回は関数化しています。
image.png
挙動としてこちらが設定した最大人数を超えてほしくなかったのでClampでの制御にしています。

デザイン(WBP_CreateSession)

最後にデザインに戻って、動的に変更したいテキストに変数を割り当てていきます。
image.png
image.png
👆画像のように、コンテンツ>Text の右にある[バインド]から紐づけていくのですが、一部の変数(int型やText型)は関数を作成せずに、変数を直接指定できるので便利です。
image.png
LAN/WANの切り替えは、Bool型でやっているので関数が必要になります。[バインディングを作成]から関数を作ります。
image.png

これで「WBP_Create Session」は終了です。

5.タイトル画面から作成画面に遷移できるようにする

グラフ(WBP_Title)

「WBP_Title」に戻り、”セッションを作る”を押したときに、「WBP_CreateSession」が開くようにします。
image.png

6.タイトルUIを表示する

L_TitleMapが起動した際にタイトルUIを表示させます。
レベルブループリントに記述しても問題はありませんが、今回はゲームモードに記述しています。
タイトル用のゲームモード「GM_Title」を作成して、Event BeginPlayにタイトルUIを表示する処理を記述します。
image.png
image.png
L_TitleMapのワールドセッティングで設定しておきます。
image.png

7.確認

「L_TitleMap」でプレイし、正常にレベルが開くかを確認しておきます
CreateSession.gif

8.セッションを探す画面を作成する

セッションを探すための画面を作成するのですが、各セッションをリストとして表示したいので、
画面となる「WBP_FindSession」とリストの項目となる「WBP_SessionData」の2つのWidgetを作成します。
image.png

デザイン(WBP_FindSession)

image.png
image.png
必要なものは、

  • 更新ボタン
  • 検索するセッションの数が指定できるところ
  • LAN/WANの検索の切り替え
  • リストを出すことができるもの(今回はVerticalBoxを使用)
  • 戻るボタン
    になります
    検索中にロード画面を出したいので、CicularThrobberを画面の中央に置いておきます。
    image.png

デザイン(WBP_SessionData)

VerticalBoxに取り付ける用のWidgetになります。
セッションの内容を表示して、ボタンを押すことで参加ができるという流れにします。
image.png
image.png
非常にシンプルなもので、

  • セッションを立てた人の名前
  • 現在の参加人数
  • セッションに参加できる最大人数
  • 現在のPing
  • 参加ボタン
    をHorizontalBoxで横並びにしています。

グラフ(WBP_SessionData)

WBP_FindSessionで取得したセッションのデータをこのWidgetで受け取り、その内容を表示するだけになります。
セッションの情報は"Blueprint Session Result型"に格納されますので、変数を作っておきます。
image.png
image.png
「インスタンス編集可能」と「スポーン時に公開」にチェックを入れておきましょう。
こうすることでCreate Widgetから作成するタイミングで変数に値をセットすることができて便利です。
image.png
それぞれのテキストに対して値を入れていきましょう。
作成したSessionの変数から現在のセッションの状態が取得できます。
image.png

セッションへの参加は「Join Session」ノードを使用します。
image.png
参加する方(クライアント)はOn Successになった時点で自動的にホストのレベルへ遷移するため、OpenLevelは不要になります。

これで参加するロジックができたので検索のほうを作っていきます。

グラフ(WBP_FindSession)

image.png

セッションの検索

image.png
「更新」ボタンが押されたときに、まずはVerticalBoxを初期化します。
その後、FindSessionノードを利用して、生成されているセッションを取得します。
MaxResultで検索する数を指定することができます。
100などの大きな数字を入れることができますが、数字を大きくすると検索時間が長くなってしまうため、テスト規模なら3~10くらいで十分です。

動的に変更ができるように、MaxResultとUseLANは変数にしておきます。

また、デザインで配置したVerticalBoxやTextBoxなどはデザインの"詳細"にある「Is Variable」のチェックを入れることで変数としてグラフで変更を加えることが可能です
image.png

FindSessionの結果である"Result"から「ForEachLoop」ノードにつなげていきます。
image.png
FindSessionからは 「実行タイミング」「成功時」「失敗時」 の実行ピンがでているので、それぞれを繋げています。
一番上の実行タイミングでは、ロード中の表現として「Circular Throbber(CT_Loading)」を表示し、[更新]ボタンや検索数を変更できるボタンを停止するためにSet Is Enabledを繋げています。一番下の失敗タイミングはその逆になります。
真ん中の成功タイミングではCreate Widgetから「WBP_SessionData」を生成し、VerticalBoxにAdd Childでリストとして登録します。Widgetの生成時に、検索結果のSessionをCreate Widgetのピンにさしておきます。

タイトル画面への遷移

image.png
UXとしてタイトルに戻れるほうがいいので、タイトルWidgetを開いて、この画面(WBP_FindSession)を閉じるように記述しておきます。

チェックボックスでのLAN/WAN切り替え

image.png
デザインで配置したCheckBoxからはシンプルなイベントが発行できますので、Use LANの変数に入れておきます。

検索数の設定

image.png
矢印ボタンを押したときに検索数を変更できるように設定しておきます。
image.png
関数の内容は、WBP_CreateSessionで行った内容と同じです。
image.png
検索数を表示しているテキストと変数を紐づけておきます。

9.確認

ここからは2人以上のプレイヤーがオンラインで接続している想定で確認作業を行います。
L_TitleMapでプレイをする前に設定をしておきます。
image.png
プレイ人数は想定している人数を入れ、ネットモードはPlay Standaloneにしておきます。
image.png
ネットモードの「Play As Listen Server」はセッション作成/参加を返さずにプレイ確認をする際に設定 します。
※L_GameMapを開いて直接プレイをする場合には設定してください。
FindSession.gif
上のgifのように同じレベルでプレイできていることが確認できれば成功です。

10.めんどくさいところをやっていく

ここまでの工程は先駆者様の記事などが出てきて作りやすいのですが、ログアウトやそれに伴うエラー処理などを自分で考えて作っていかなければなりません。
あくまでもサンプル ではありますが、デフォルトのUEのノードだけで可能な限りエラーに対処できそうな流れを作っていきます。

11.ログアウトを確認するための準備

image.png
プレイヤーがUIからログアウトができる画面(ゲームメニュー画面)を作成します。
image.png
インゲームの確認をするために必要なクラスを作成しておきます。

  • BP_Player
    ThirdPersonCharacterをコピーしたものです。
  • CP_PlayerController
    PlayerControllerクラスを継承して作成します。オンラインゲームでは設計上の観点からPlayerControllerをしっかりと利用していくほうが後々楽になります。
  • BPI_GameController
    CP_PlayerControllerにアクセスするためのインターフェースです。

作成後、「GM_Sample(インゲーム用のゲームモード)」を作成し、BP_PlayerとCP_GameControllerを設定しておきます。
image.png

12.ゲームメニューUI「WBP_GameMenu」を作成する

image.png

デザイン(WBP_GameMenu)

image.png
今回はボタンが2つあればどんなものでも問題ありません。
image.png

グラフ(WBP_GameMenu)

image.png
このUIではWidget内に具体的な処理を記述せずに、"イベントディスパッチャー"を作成して呼び出すだけにしておきます。
image.png
また、クラスのデフォルト>詳細 から Is Focusableにチェックを入れておきます
image.png
image.png

13.ゲームメニューUIからログアウトできるようにする

BPI_GameControllerを編集

image.png
インターフェースとして"ShowGameMenuUI"関数を作成しておきます。

BP_Playerを編集

image.png
好きなボタンのインプットイベントから先ほど作成した"ShowGameMenuUI"を呼びだすように接続します。

CP_GameControllerを編集

全体図
image.png
BeginPlayに"Set Input Mode Game Only"を接続しておきます。
image.png
カスタムイベントを追加して、"Logout"と命名しておきます。
image.png
DestroySessionは、サーバー(セッションを立てたホスト)が実行するとセッションを破棄することができます。
クライアントの場合は、セッションに参加しているという情報そのものを破棄します。
DestorySession自体が俗にいうログアウトということではなく、レベル遷移を伴うことでゲームから離脱することができます。
ゲームに離脱せずにホストがDestorySessionのみを行った場合は、FindSessionの検索に引っかからないようになるため、特定のタイミングで呼ぶことで、公開していた部屋を閉じて途中参加をさせない、といったような処理にできます。
DestorySessionの成功時にOpenLevelでタイトルレベルに戻るように設定しておきます。

先ほど作成したインターフェース関数"ShowGameMenuUI"からゲームメニューWidgetの生成と表示を行います。
image.png
Widgetを多重に生成したり、表示したりしないような制御をしています。

その後ろには、Widget内のボタンが押されたときの挙動としてイベントディスパッチャーを紐づけておきます。
image.png
後述するCloseGameMenuUIもカスタムイベントから作成して、紐づけておきます。

ゲームメニューを閉じる処理(CloseGameMenuUI)を記述します。
image.png

14.確認

セッションの作成→レベル遷移→セッション破棄(ログアウト)→セッションの作成/検索 が正常に行えるかを確認します。
LogoutDefault.gif

15.【問題解決1】切断された側がセッションの作成も参加もできない問題

Listenサーバー(PtoP)ではよくあることではありますが、セッションに参加しているときに、ホストがログアウトした場合、クライアントは直ちにゲームが終了されます。
UE4でもそのようになっており、ホストとの接続状況が悪くなった(ホストがログアウトした)場合、クライアントは『プロジェクト設定 > マップ&モード > ゲームのデフォルトマップ』に設定したレベルに遷移します。
image.png

この際、セッションがなくなって強制的に離脱することになったクライアントは「まだ」セッションに参加した履歴のようなものが残っており、セッションを作成したり、セッションに参加したりすることができなくなってしまいます。

この問題の解決は比較的簡単で「L_TitleMap」に遷移する度にセッションを破棄することで解決します。
image.png
「GM_Title」のEventBeginPlayにDestorySessionを記述しておきます。
image.png

これでこの問題は解決できますが、初めてゲームを起動した際にもDestorySessionが実行され、必ずOnFailureになってしまいます。実害はないのですが、設計上美しくないなぁと思うので、ネットワークエラーが発生したときのみ、DestroySessionを実行するという形にします。

GameInstanceを作成する

image.png
image.png
ネットワークエラーに関するイベントはGameInstanceで実行されているため、GameInstanceを継承した「GI_OnlineGameSample」を作成します。
image.png
プロジェクト設定から作成したGameInstanceを適用しておきます。

GameInstanceでは「ネットワークに問題が発生したときに発行されるイベント」と「レベルを移動した際に問題が発生したときに発行されるイベント」の2つがあります。
image.png
それらからは「原因」となる内容が取得できるため、エラーの内容によって実行する内容を変えることもできます。

今回は、「大雑把なエラー」を取得するため両方のイベントに「Error Occurred」という自作したBool型の変数を挿入しておきます。
image.png

ダイアログUIを作る

プレイヤーからするとなぜゲームがいきなり落ちてしまったのかわからないので、エラーで落ちた際には「エラー」であることを伝えてあげます。
「WBP_Dialog」を作成します。ダイアログは様々な場面で使えるため、汎用的なものにしておきます。

デザイン(WBP_Dialog)

image.png
image.png

グラフ(WBP_Dialog)

image.png
"Dialog Text"の変数はこのWidgetの生成時に変更したいので、「インスタンス編集可能」と「スポーン時に公開」にチェックを入れておきます。
image.png

GM_Titleを編集

準備が整ったので、エラーが出た際にだけ、ダイアログを表示してセッションを破棄できるようにします。

GameInstanceの"Error Occurred"を取得して処理を分岐します。
image.png
タイトルUIを生成するタイミングが"Error Occurred"のTrueとFalseで異なるため、「ShowTitleUI」というカスタムイベントを作成しています。

失敗時には「WBP_Dialog」を表示してセッションの破棄を行います。
image.png
破棄のタイミングはどこでも問題はないのですが、今回は「了解」のボタンを押したときのイベントに紐づける形で実装しました。ダイアログを出した後には"Error Occurred"はFalseにしておきます。

ダイアログに表示する文言(Dialog Text)は生成時に設定できるようにしているため、GameInstanceに作成した"Error Occurred"の変数と同じ要領でここでネットワークのエラー内容を表示することもできます。
image.png

16.確認

2人以上のプレイヤーがセッションに参加している状態で、ホストがログアウトした場合にクライアント側にダイアログが生成されます。また、クライアントは、そのまま継続してセッションの作成やセッションの検索が行える状態になります。
Dialog.gif

17.【問題解決2】セッション検索に出てきた部屋に参加しようとした際、そのセッションが破棄されていた場合に通知が取れない問題

後日更新予定になります。
(すいません)

さいごに

今回はUnrealEngineでのセッション作成から破棄までをどのように実装すればいいのだろうというところを書いてみました。
ゲームジャムなどの短期の開発なら問題ないかなと思っていますが、販売まで行く場合にはそのリリースするプラットフォームごとの制約などがあるため、様々な要件をクリアする必要があります。

中規模を超えるゲーム開発を考える際には、専用のエンジニアを立てるのはもちろん、有用なプラグインを利用していくことで、ゲーム開始までのフロー開発を抑え、インゲームの開発により注力できるのではないかと思います。

書き損ねた残りの問題解決方法は近日公開します!
サンプルプロジェクトの公開も12月中に!

6
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
5