【Unreal Engine】オンラインセッション入門:LANで部屋を作り、別のPCから参加する

作成: 2026-07-23最終更新: 2026-09-07

UE5のCreate・Find・Join Sessionで、同じLANの2台から遊べる参加メニューを作ります。検索結果をボタンへ渡す手順、0件・失敗時の戻し方、SessionとReplicationの違いを図解。SteamやEOSでインターネットへ広げる際の役割も整理します。

マルチプレイの入門で、2つの画面に同じ扉の開閉を映せた。次は別のPCでも参加したくなります。そのために作るのが、「部屋を作る」「部屋を探す」というゲームの入口です。

この記事では、同じLANにつないだ2台で、片方が作った部屋をもう片方の一覧に表示し、選んで参加するメニューを作ります。LAN は、家庭や教室などの限られた範囲のネットワークです。まずはここで、相手を見つけて一緒に遊ぶまでをつなげましょう。

ホストが用意した部屋へ、別のプレイヤーが参加する

この記事でわかること

  • Sessionと、ゲーム内の状態を同期する仕組みの違い
  • Create・Find・Join Sessionを使う順番
  • 検索結果を、参加ボタンのある行へ渡す方法
  • 0件・失敗・退出を扱い、次のテストへ進む方法
  • インターネットへ広げるときのSteam・EOSの役割

実践はBlueprintのThird Personプロジェクトと、基本的なUMGの操作を前提にします。Steam・EOSの導入は後半で全体像を扱い、手を動かす範囲はLANに絞ります。

Sponsored

部屋を見つけることと、同じ世界で遊ぶこと

Session(セッション) は、一緒に遊ぶ部屋の情報を管理する仕組みです。「誰がホストか」「何人入れるか」「どこへ参加するか」といった情報を扱います。レベルの中に置く部屋や、画面に表示するメニューそのものではありません。

レプリケーション入門PIE(Play In Editor) では、エディタが接続先を用意してくれました。別々に起動したゲームでは、その入口も自分で作ります。

部屋の検索、通信の接続、ゲーム内の同期を分けて考える
役割何を扱うか今回の例
部屋の情報相手を探し、参加先を選ぶSession
ゲームの接続相手と通信できる経路を作るLAN上のホストへ接続
ゲーム内の同期キャラクターや扉の状態をそろえるReplication・RPC

Sessionに参加できても、任意の扉が自動で同期されるわけではありません。逆に、扉の同期ができていても、参加先を探すメニューは別に必要です。

3つの操作を、ホストと参加者で分ける

ホストは Create Session で部屋を登録します。その成功後、ゲームレベルを listen オプション付きで開き、他のプレイヤーからの接続を待ちます。ホスト自身も遊ぶ、Listen Serverの構成です。

参加者は Find Sessions で部屋を検索し、選んだ結果を Join Session に渡します。ホストのCreateと、参加者のFind・Joinは、それぞれのPCで動く処理 です。

ホストは作成後にlistenで待ち、参加者は検索結果を選んで参加する

以降の配線図は、各節で説明する部分を抜き出しています。前後の処理と省略した入力は、本文・表に沿ってつなぎます。

これらは 非同期 のノードです。呼び出した直後には、結果がまだ出ていません。結果に応じた処理は On Success/On Failure へつなぎます。開始直後の実行出力と、完了したときの出力を取り違えないようにしましょう。

今回使うNullと、Steam・EOSの違い

Online Subsystem は、UEからオンライン機能を呼び出すための窓口です。裏側で使うサービスによって、検索の方法や利用できる機能が変わります。同じ名前のノードでも、どのサービスを使っているかが重要です。

選択肢今回の位置づけ主な準備
NullLANの部屋を検索する最初の実験プロジェクトでNullを選び、LAN設定をそろえる
SteamSteam利用者向けの部屋・招待・接続機能へ広げるSteamworks、アプリID、UE側のプラグインと通信設定
EOS複数ストアなどをまたぐオンライン機能を検討するEpic側の製品設定、認証、使う機能と通信設定

Nullは、LAN内で部屋を見つける実験に使えます。Use LANをオフにするだけで、インターネット上の部屋を検索できるようにはなりません。 また、「LAN検索が届かないこと」と「IPアドレスを指定した直接接続が可能か」は別の話です。

NullのLAN検索は同じLANで試し、別の家への検索とは分ける

同じWi-Fi名でも、ゲスト用ネットワークなどではPC同士の通信が分離されていることがあります。今回は、相互に通信できるLAN上の2台で試します。有線と無線の組み合わせでも、その条件を満たせば構いません。

準備:参加メニューとゲームレベルを分ける

LAN用の設定を明示する

UE5のBlueprint Third Personプロジェクトで進めます。すでにSteam・EOS用の設定があるプロジェクトは、コピーや別の試作用プロジェクトを使うと設定を追いやすくなります。

「Edit → Plugins」で Online Subsystem Null が有効か確認します。プロジェクトの Config/DefaultEngine.ini に、次を設定してエディタを再起動します。同じ項目がすでにあれば、その値を変更します。

[OnlineSubsystem]
DefaultPlatformService=Null

今回はOnline Subsystemの標準Blueprintノードを使います。似た名前の「Online Services」の導入手順や、追加プラグインのノードを混ぜずに進めてください。

部屋を作るL_Menuと、2人で遊ぶL_Gameを分ける。LAN用にDefaultPlatformServiceをNullにする

2つのレベルを用意する

レベル用途設定
L_Menu部屋を作る・探す画面新規の空レベル。ここだけメニューを表示
L_Game2人で遊ぶ場所Third Personのレベルを複製。Player Startを2個置く

L_GameはThird Person用のGameModeを使います。レプリケーション入門で作った BP_SharedDoor(全員で共有する扉)があるなら、ここへ置くと参加後の同期も試せます。L_Menu用にはGameMode Baseを親にした BP_MenuGameMode を作り、Default Pawn ClassをNoneにします。L_MenuのWorld Settingsで、GameMode Overrideにこれを指定します。

Project Settingsの「Maps & Modes」で Game Default MapをL_Menu にします。また、Packagingの List of maps to include in a packaged build にL_MenuとL_Gameを追加します。名前だけでOpen Levelするレベルも、配布するゲームへ含めるためです。パッケージ化の手順も参照できます。

メニューと検索結果の行を作る

作るWidgetは2つです。部屋一覧は、1件ごとに小さなWidgetを作って縦に並べます。

ActionsBoxに作成・検索ボタンとResultsBoxをまとめ、検索結果を行Widgetで並べる

Widget Blueprint WBP_SessionMenu に、次を配置します。グラフから使う部品は「Is Variable」をオンにしてください。

名前部品役割
ActionsBoxVertical Box下の2ボタンとResultsBoxをまとめる
HostButtonButton+Text「部屋を作る」
FindButtonButton+Text「部屋を探す」
ResultsBoxVertical Box見つかった部屋の行を入れる。最初は空
StatusTextText「部屋を作るか、探してください」。ActionsBoxの外へ置く

図の「部屋A・B」は表示例です。実際の表示名は、後で検索結果から取り出します。

Canvas Panelの下にStatusTextとActionsBoxを置き、ActionsBoxの子に2ボタンとResultsBoxを並べれば十分です。

L_MenuのLevel Blueprintで、BeginPlayから Create Widget(Class = WBP_SessionMenu)→ Add to Viewport とつなぎます。Create WidgetのOwning Playerには Get Player Controller(Player Index = 0)を渡し、Return ValueをAdd to ViewportのTargetへつなぎます。

続けて Set Input Mode UI Only を呼びます。Player Controllerは同じGet Player Controller、In Widget to FocusはCreate WidgetのReturn Valueです。そのControllerの Show Mouse Cursorをtrue にします。L_MenuをPlayし、メニューとマウスが見えれば準備できています。

WBP_SessionRow:検索結果1件分

Widget Blueprint WBP_SessionRow を作り、Button JoinButton の中へText RoomText を置きます。両方を変数として使えるようにし、さらに次の変数を追加します。

変数設定
SessionResultBlueprint Session ResultInstance EditableとExpose on Spawnをオン
MenuRefWBP_SessionMenu Object ReferenceInstance EditableとExpose on Spawnをオン

Blueprint Session Result は、検索で得た部屋の情報をまとめた構造体です。Joinにはこの値を渡します。表示用の部屋名だけでは、参加先を指定できません。

Expose on Spawn は、Widgetを作るときに値を渡せる設定です。Compileすると、後で置くCreate WidgetにSessionResultとMenuRefの入力が現れます。MenuRefは「この行を並べたメニュー」への参照として使います。

各行にSessionResultと親メニューへのMenuRefを保持する

WBP_SessionRowのEvent Constructでは、SessionResultのGetを Get Server Name のResultへつなぎます。Return ValueをTextへ変換してRoomTextの Set Text に渡し、ConstructからSet Textへ実行線をつなぎます。これはサービスから得た表示名で、今回自作した部屋名ではありません。

処理中は、メニューの操作を止める

WBP_SessionMenuに関数 SetMenuBusy を作り、Boolean入力 Busy を追加します。入口から Set Is Enabled を呼び、TargetをActionsBox、In Is Enabledを NOT Boolean に通したBusyにします。

Busyがtrueの処理中は操作を止め、falseに戻したら再び選べる

NOT Booleanはtrueとfalseを反転します。「処理中」をtrueにすると「操作可能」はfalseになる、という組み合わせです。

Busyがtrueなら、ActionsBoxの子のボタンも押せなくなります。検索中に再検索したり、参加中に別の部屋を選んだりするのを防げます。StatusTextはその外に置いたので、処理中の説明はそのまま表示できます。

もう1つ、関数 FinishMenuAction を作り、Text型の入力 Message を追加します。入口からSet Textへ進み、TargetにStatusTextのGet、In TextにMessageを渡します。その後でSetMenuBusy(Busy = false、Target = Self)を呼びます。以後はこの関数で、結果の説明と操作の再開をまとめます。

Sponsored

ホスト:部屋を作って、接続を待つ

ここからはWBP_SessionMenuのEvent Graphです。HostButtonのOn Clickedから、SetMenuBusy(true)→ StatusTextのSet Text(「部屋を作成中…」)→ Create Session とつなぎます。

Create Sessionの入力
Player ControllerこのWidgetの Get Owning Player
Public Connections2(ホストを含む定員)
Use LANオン
Use Lobbies if Available項目があればオフ。今回はLAN Sessionを使う

Get Owning Player は、このWidgetに設定したプレイヤーのControllerを返します。先ほどCreate WidgetのOwning Playerを指定したのは、このためです。

Create Sessionの On Success から Open Level (by Name) へつなぎます。Level Nameは L_Game、Absoluteはオン、展開したOptionsには listen を入力します。引用符や先頭の ? は入力しません。

Create Sessionの成功からlisten付きOpen Levelへ、失敗からメニューの操作復帰へ進む

On Failureは、FinishMenuAction(Message =「部屋を作れませんでした」)へつなぎます。失敗したときはメニューを残し、再操作できる状態へ戻します。

Create Sessionだけでは、遊ぶレベルの待ち受けは始まりません。部屋を登録してから、L_GameをListen Serverとして開く ところまでがホストの準備です。

L_GameのLevel Blueprintでは、BeginPlayからGet Player Controller(0)を使って Set Input Mode Game Only を呼び、Show Mouse Cursorをfalseにします。これは各PCの操作をゲームへ戻すための処理です。L_GameではメニューWidgetを作りません。

参加側:部屋を探して、一覧を作る

FindButtonのOn Clickedから、SetMenuBusy(true)→ ResultsBoxの Clear Children → StatusTextのSet Text(「検索中…」)→ Find Sessions とつなぎます。Clear Childrenは、前回表示した行を取り除く処理です。

Find Sessionsの入力
Player ControllerGet Owning Player
Max Results20
Use LANオン
Use Lobbies項目があればオフ

検索成功でも、0件の場合がある

On SuccessからBranchへ進み、Resultsの Lengthが0より大きいか をConditionにします。Lengthは配列の件数です。ResultsからLengthを作り、その出力を整数の > のAへ入れ、Bを0にします。

ResultsのLengthを0と比較し、1件以上あるかを調べる

比較結果のReturn ValueをBranchのConditionへつなぎます。

検索成功後の0件と検索処理の失敗を別のメッセージにする

FalseならFinishMenuAction(「部屋が見つかりませんでした」)へ進みます。On Failureも別のFinishMenuAction(「検索に失敗しました」)へつなぎます。検索ができなかったことと、検索したけれど部屋がなかったことを分けます。

1件ずつ、行Widgetへ渡す

BranchのTrueから For Each Loop へつなぎ、Find SessionsのResultsをArrayへ渡します。Loop Bodyから Create Widget(Class = WBP_SessionRow)を呼び、次のようにつなぎます。

Create Widgetの入力接続元
Owning PlayerGet Owning Player
SessionResultFor Each LoopのArray Element
MenuRefSelf(WBP_SessionMenu自身)
For Each Loopの結果をCreate WidgetのSessionResultへ渡し、SelfとOwning Playerも設定する

続けて Add Child to Vertical Box を呼びます。TargetはResultsBox、ContentはCreate WidgetのReturn Valueです。

Add Child to Vertical Boxの入力接続元
実行入力Create Widgetの実行出力
Target(追加先)ResultsBoxのGet
Content(追加するもの)Create WidgetのReturn Value

Array Elementは、今取り出している部屋1件分です。それを行に保存することで、「この行を押したら、この部屋へ」という対応ができます。

For Each Loopの Completed から、FinishMenuAction(「参加する部屋を選んでください」)を呼びます。操作を戻すのは全ての行を作った後です。ループの途中でJoin Sessionを呼ぶ必要はありません。

選んだ行の部屋へ参加する

WBP_SessionMenuのEvent GraphにCustom Event JoinSelectedSession を作ります。入力は SelectedResult、型はBlueprint Session Resultです。非同期のJoin Sessionを呼ぶため、通常の関数ではなくCustom Eventにします。Compileしておきます。

WBP_SessionRowへ戻り、JoinButtonのOn Clickedから JoinSelectedSession を呼びます。TargetはMenuRef、SelectedResultはその行のSessionResultです。

行のクリックからMenuRefのJoinSelectedSessionへSessionResultを渡す

WBP_SessionMenuのJoinSelectedSessionでは、SetMenuBusy(true)→ StatusTextのSet Text(「参加中…」)→ Join Session とつなぎます。Player ControllerにはGet Owning Player、Search ResultにはイベントのSelectedResultを渡します。

イベントのSelectedResultをJoin SessionのSearch Resultへ渡す接続の抜粋

On SuccessではStatusTextを「接続先へ移動中…」にします。標準のJoin Sessionノードは、接続先への移動も行います。参加側からL_GameをOpen Levelし直さない ようにしてください。それではホストと同名のレベルを、自分の環境で別に開くことになります。

On FailureではResultsBoxをClear Childrenし、FinishMenuAction(「参加できませんでした。もう一度検索してください」)を呼びます。検索後にホストが終了したり、部屋が満員になったりすることもあるため、古い行をそのまま再利用しない形にします。失敗後もSessionが残る場合は、後半のDestroy Sessionによる片付けが必要です。最初の切り分けではアプリを終了して、起動し直す方法でも確認できます。

2台で、作成から参加まで確かめる

全BlueprintをCompileして保存し、Development構成でパッケージ化します。同じ出力フォルダ一式を、同じLANの2台のPCへコピーしてください。

  1. 両方でゲームを起動し、L_Menuのメニューが出ることを確認します。
  2. PC Aで「部屋を作る」を押します。L_Gameへ移り、キャラクターを操作できればホストの準備ができています。
  3. PC Bで「部屋を探す」を押します。結果の行を選び、L_Gameへ移動することを確認します。
  4. 両画面に2人のキャラクターが現れ、相手の移動が見えることを確認します。共有扉も置いた場合は、PC Bから開けて両方で変わるか試します。
  5. いったん両方のアプリを終了してやり直します。今度はホストを作る前に検索し、0件の表示から再検索できることも試します。
LAN上の別々のPCが同じ世界へ参加する確認イメージ

PIEや同じPCの複数プロセスも開発中の確認には使えます。ただし、それだけでは別PC間の検索や通信条件を確かめられません。この記事の到達点は、別々のPCで同じ部屋に参加できたこと です。

失敗した段階で、見る場所を変える

症状最初に確認する場所
ボタンが押せない・画面が出ないL_MenuでのWidget作成、Owning Player、UI用の入力設定
Create/Findそのものが失敗有効なOnline Subsystem、Controller入力、Output Logのエラー
検索結果が0件ホストの作成成功、双方のUse LAN、相互通信できるLANか
検索結果の行が出ないLengthの分岐、For Each Loop、ResultsBoxへのAdd Child
行は出るが参加できないその行のSessionResultを渡したか、ホストが待ち受けているか、満員でないか
パッケージ版でレベル移動に失敗L_Menu/L_Gameをパッケージへ含めたか、Level Nameが正しいか
参加したが扉だけ同期しないSessionの先のReplicationとRPC

別PCから見つからない場合は、OSのファイアウォールで このゲームの実行ファイルの通信 を、使っているネットワークに対して許可できているか確認します。全体を無効にする必要はありません。ゲストWi-Fiの端末分離や、VPNで経路が変わっていないかも見ます。

Sponsored

退出と、接続が切れたときの片付け

ここまでの最小テストでは、アプリを終了してやり直しました。次にゲーム内へ「部屋から退出する」ボタンを足すときは、画面を戻す処理と、Sessionの片付けをセット にします。

使うのは Destroy Session です。ホストが呼ぶと部屋を閉じ、参加者が呼ぶとその参加者がSessionを抜けるための処理になります。参加者が退出しただけで、ホストの部屋全体を消すわけではありません。

Destroy Sessionの成功後にL_Menuへ戻り、失敗時は再操作できるようにする

退出ボタンのOn Clickedから、ボタンを無効化してDestroy Sessionを呼び、Player ControllerにそのWidgetのGet Owning Playerを渡します。On SuccessからL_MenuをOpen Level(Absoluteオン、Options空)します。On Failureでは失敗を表示して操作を戻し、再試行できるようにします。

ホストが終了したときは、参加側も接続を失います。Joinの成功は、その後の通信やレベル移動がずっと成功する保証ではありません。 GameInstanceEvent Network ErrorEvent Travel Error は、接続断や移動失敗を扱う入口になります。エラー内容を表示し、Sessionの片付けとメニューへの復帰を行う処理へつなげます。

退出やエラー処理を広げる段階では、これらをGameInstanceへまとめると、レベルを移動しても後始末を続けやすくなります。まずは「参加できる」までを確認し、その後で「切れても次の操作ができる」を加える順で進めましょう。

おまけ:インターネットへ広げるときに足すもの

別の家のPCへ接続する場合は、部屋の検索に加え、通信の経路も考えます。

家庭のルーターでよく使われる NAT は、家の中のアドレスと外側のアドレスを対応づける仕組みです。外から突然接続しようとしても、どのPCへ届けるかの対応がなく、届かない場合があります。これを越えて接続を成立させる工夫を、NAT越えと呼びます。

Relay(リレー) は、中継サーバを経由して通信する方式です。直接つなぐ方法や中継を、SteamやEOSの通信機能に任せる構成を検討できます。ただし、部屋が検索できるようになったことと、ゲームの通信がその経路を使っていることは別に確認します。

SteamやEOSによる部屋の管理と、直接接続やRelayによる通信経路の役割

Steam:Steamの利用者が集まる入口

Online Subsystem Steamでは、Steamの部屋・フレンド・招待などの機能と連携できます。アプリを識別する AppID、Steamworks側の設定、UEのプラグインや通信方式の設定をそろえます。

プラグインをオンにしただけで、フレンドからの招待画面やゲームの参加処理が全て完成するわけではありません。また、SessionとLobbyの設定にも違いがあります。使うUEのバージョンに対応した公式の導入資料を基に、別アカウント・別回線でも確認します。

EOS:ストアをまたぐ機能も検討できる

EOS(Epic Online Services) は、部屋や参加者の管理、認証、P2P通信などを提供するサービス群です。Epicの提供条件では無料で利用できますが、ゲームサーバのホスティング一式を無料で用意してくれる、という意味ではありません。

Epic側で製品を設定し、プレイヤーを識別する認証と、必要な機能をゲームへ組み込みます。複数ストアをまたぐ構成の候補になりますが、各プラットフォームの条件や、対応するUE側の連携方法も確認します。

中継サーバと、ゲームを動かすサーバは別

Relayは通信を中継します。一方、Dedicated Server(専用サーバ) は、プレイヤーとして遊ばず、ゲームの進行や状態の計算を担当します。ホストのPCをゲーム進行の中心にしたくない場合などに検討する構成です。

どちらも「サーバ」ですが、役割は違います。専用サーバを使うなら、その実行環境や運用も準備します。作品に必要な参加方法、人数、遊ぶ時間に合わせて選びましょう。同じ画面で遊ぶ作品なら、画面分割も別の選択肢です。

まとめ

ホストはCreate Sessionで部屋を作り、L_Gameをlistenで開きました。参加者はFind Sessionsの結果を行Widgetへ渡し、選んだ結果をJoin Sessionへ送ります。接続した後の扉やキャラクターは、Replicationの仕組みで共有します。

まずは同じLANの2台で、相手の部屋が一覧に現れ、一緒に歩けるところまで確かめてください。検索・参加・ゲーム内同期を分けて追えるようになると、次にSteamやEOSを使うときも、何を追加するのかが見えやすくなります。

参考:Create SessionFind SessionsJoin SessionOnline Sessionノードとエラー処理Steamの通信機能

Unreal Engine このセクションのノート98