招待リンクで友達と遊ぶ仕組みの作り方
遊びをつくる執筆にClaudeを使用しています。

「友達と一緒に遊べるゲームを作りたい」という要望に応えるとき、最初の壁になるのが「どうやって同じ部屋に入ってもらうか」という問題です。アプリのインストールが不要なブラウザゲームであれば、招待リンクを送るだけで相手がすぐ参加できる仕組みが理想です。 招待リンクの本質は「部屋IDをURLに乗せて共有する」だけです。受け取った側がそのURLを開くと、ゲーム側がURLから部屋IDを読み取り、同じ部屋のシグナリングやデータ通信に自動接続します。この仕組みはサーバーレスのピアツーピア(WebRTC)でも、サーバー中継型(WebSocket)でもほぼ同じ考え方で実装できます。 この記事では「部屋IDの生成と共有」→「URLパラメータの読み取りと接続」→「招待リンクのUI設計」という順に、実装の判断基準と具体的な手順を説明します。
部屋IDの設計と生成
招待リンクの中心にあるのは部屋IDです。部屋IDには次の三つの要件があります。
- 推測されにくいこと:連番(room=1, room=2)だと他人の部屋に誤って入られるリスクがあります。
- 短くても一意であること:URLに含めて口頭でも共有しやすい長さが望ましいです。
- 期限や使い捨て性を持たせられること:長期間有効なIDはセキュリティ上好ましくない場面があります。
実用的な選択肢はランダムな英数字の文字列です。JavaScriptでは crypto.randomUUID() が利用できるブラウザであれば36文字のUUIDを生成できます。短くしたい場合は Math.random().toString(36).slice(2, 10) のような8文字程度の文字列でも、同時接続数が少ないカジュアルゲームなら衝突の可能性は十分小さくなります。
部屋IDの生成はホスト側(最初に部屋を作った人)だけが行うのが基本です。ゲストはURLから受け取ったIDを使うだけで、自分では生成しません。この役割の非対称性が後のUI設計にも影響します。
URLへの埋め込みと読み取り
生成した部屋IDをURLに乗せる方法はクエリパラメータが最もシンプルです。
https://example.com/game.html?room=ab3f9x2cホスト側がこのURLを組み立てて相手に渡します。JavaScriptでは次のように書けます。
const roomId = crypto.randomUUID();
const inviteUrl = `${location.origin}${location.pathname}?room=${roomId}`;ゲスト側がURLを開いたとき、ゲームの起動処理の冒頭で URLSearchParams を使ってIDを取り出します。
const params = new URLSearchParams(location.search);
const roomId = params.get('room');
if (roomId) {
// ゲストとして既存の部屋に参加する処理
} else {
// ホストとして新しい部屋を作る処理
}この分岐がゲームの最初の「役割振り分け」になります。roomId がある場合はゲスト、ない場合はホストとして初期化を進めます。
接続処理への組み込み方
部屋IDを取り出した後の実際の通信には、シグナリングサーバーを使うWebRTCかWebSocketのどちらかを選ぶことになります。いずれの場合も部屋IDは「どのチャンネルに接続するか」を指定するキーとして使います。
WebRTCの場合
PeerJSのような抽象化ライブラリを使うと、部屋IDをそのままピアIDとして扱えます。ホストは new Peer(roomId) で待ち受け、ゲストは peer.connect(roomId) で接続します。シグナリングの詳細はライブラリが隠蔽してくれるため、部屋IDさえ共有できれば接続が成立します。
WebSocketの場合
サーバー側でルーム管理を行う構成では、クライアントが接続直後に { type: 'join', room: roomId } のようなメッセージを送り、サーバーが同じ部屋IDを持つクライアントをグループ化します。Firebase RealtimeDatabaseやPartyKitのようなBaaSを使う場合も、部屋IDをドキュメントパスやルーム名として使う構造は同じです。
どちらの方式でも招待リンクの仕組み自体は変わりません。URLから取り出したIDを接続先のキーとして渡すだけです。
招待UIの設計で失敗しやすい点
技術的には単純でも、UIの設計で使い勝手が大きく変わります。よくある失敗を三つ挙げます。
1. リンクが目立たないゲームが始まってからリンクを探さなければならないと、共有のタイミングを逃します。ホストがゲームを開始した直後に「このリンクを友達に送ってください」というモーダルやバナーを出すのが効果的です。
2. コピーボタンがないURLをテキストで表示するだけでなく、「コピー」ボタンを置いて navigator.clipboard.writeText(inviteUrl) を実行できるようにします。モバイル環境では長押しでのコピーが難しいため、ボタンは必須と考えておくのが安全です。
3. ゲスト参加後の状態がわかりにくいゲストがURLを開いても、画面に変化がなければ「本当に繋がったのか」が不安になります。「○○が参加しました」のような接続確認メッセージをホスト・ゲスト双方に表示することで、繋がったことを明示します。接続待ち中はスピナーやカウントダウンを見せておくと離脱率が下がります。
部屋の有効期限と後始末
招待リンクを使ったゲームは、対戦が終わった後も同じURLが有効なままになりがちです。再アクセスした場合の挙動を設計しておかないと、ゲームが中途半端な状態で始まったり、別のゲストが割り込んだりします。
シンプルな解決策は1対1のゲームなら2人揃った時点で新規参加を拒否することです。ホスト側が接続済みのピア数を管理し、上限に達したら後から来た接続に対して { type: 'room_full' } を返し、ゲスト側はその応答を受けて「部屋が満員です」と表示します。
より厳密に管理したい場合は、部屋IDにタイムスタンプを付加してサーバー側で生存期間を制限する方法があります。ただしカジュアルなブラウザゲームであれば、まず「満室拒否だけ実装して公開し、問題が出たら期限管理を追加する」という段階的な進め方が現実的です。
次の行動
部屋IDの生成・URLへの埋め込み・URLSearchParams による読み取りという三つの部品から始めると、招待リンクの骨格は1時間以内に動かせます。まず1対1で接続確認できる最小構成を作り、接続完了メッセージとコピーボタンを加えた時点で友人に試してもらうのがおすすめです。完成したゲームはHTMLファイルまたはZIPファイルとしてアソバースに投稿し、実際のプレイヤーからフィードバックを集めながら改善を進めてください。
参考資料
- MDN Web Docs「URLSearchParams」
- MDN Web Docs「crypto.randomUUID()」
- PeerJS 公式ドキュメント
- PartyKit 公式ドキュメント



