🎮

サーバー代0円! P2Pと無料サービスだけでリアルタイム対戦オセロを作った話

に公開

概要

この記事では、サーバーコストを一切かけずにブラウザで動作するリアルタイム対戦ゲームを開発した際の技術的な構成と実装について解説します。WebRTC (PeerJS) によるP2P通信を主軸に、シグナリングサーバーをRender、フロントエンドをGitHub Pagesにデプロイすることで、完全無料で動作するブラウザオセロゲームを実現しました。

はじめに

皆さんは「ゴッドフィールド」というWebゲームをご存知でしょうか?ブラウザだけで手軽に遊べるターン制のオンライン対戦ゲームで、めちゃくちゃ楽しいです。

「こんなに面白いゲームを自分でも作ってみたい!」

そう思ったものの、お金がありません。一般的なオンラインゲームでは、プレイヤー間のやり取りを処理するために常時稼働するゲームサーバーが必要、この構成はサーバーの維持費がかかります。

何とか工夫して無料で同等のサービスを実現できないかと考えました。そこで、サーバーの負荷を減らす方法として、「対戦処理そのものをプレイヤー同士のPCで直接行わせる」というP2P (Peer-to-Peer) 通信のアイデアに至りました。

今回はこのP2Pの仕組みを使い、技術的な面白さを追求した対戦オセロゲームを開発しました。

P2P Othello の特徴

開発したゲームには以下の特徴があります。

  • サーバーレス対戦: WebRTC (PeerJS) を利用し、ゲーム中の通信はプレイヤー間で直接行われるため、低遅延です。
  • インストール不要: Web ブラウザさえあれば、PC でもスマートフォンでもプレイ可能です。
  • 簡単招待: 生成された URL を友達に送るだけで、簡単に対戦を始められます。
  • 完全無料: GitHub Pages と Render の無料枠を利用しているため、ホスティング費用はかかりません。

システム構成

このゲームは、静的ファイルをホスティングする「フロントエンド」と、プレイヤー間の初期接続を仲介する「シグナリングサーバー」の 2 つで構成されています。

役割 担当 利用技術・サービス
フロントエンド ゲーム本体の画面描画、操作ロジック GitHub Pages (HTML/CSS/JavaScript)
P2P 通信 プレイヤー間のデータ送受信 WebRTC (PeerJS)
シグナリング P2P 接続の仲介(マッチング) Render (Node.js + PeerServer)

システム構成とその通信の様子

P2P通信を確立するためには、まずお互いのIPアドレスなどの接続情報を交換する必要があります。この最初の「お見合い」を仲介するのが マッチング(シグナリング)サーバー の役割です。

一度プレイヤー間のP2P接続が確立されると、シグナリングサーバーは不要になります。ゲーム中の石を置くデータ(move)などは、Render のサーバーを経由せず、プレイヤーのブラウザ間で直接リアルタイムにやり取りされます。この仕組みにより、サーバーの負荷を最小限に抑え、Renderの無料プランでも十分に運用可能なシステムが実現できました。

WebRTCとは? なぜシグナリングサーバーが必要なのか?

WebRTC (Web Real-Time Communication) は、ブラウザ間で直接ビデオ、音声、そして任意のデータをやり取りするための技術です。P2P通信を実現するためのAPI群と考えると分かりやすいでしょう。

しかし、P2Pで通信を始めるには、一つ大きな壁があります。それは、「通信したい相手のIPアドレスをどうやって知るのか?」という問題です。

インターネット上のほとんどのデバイスは、ルーターやファイアウォールの内側にあり、プライベートIPアドレスしか持っていません。そのままでは外部のデバイスから直接アクセスすることはできません。

そこで登場するのがシグナリングサーバーです。

  1. お互いの紹介: 各クライアントはまずシグナリングサーバーに接続します。
  2. 接続情報の交換: シグナリングサーバーを介して、お互いのIPアドレスやポート番号といった接続に必要な情報(メタデータ)を交換します。このプロセスをシグナリングと呼びます。
  3. P2P接続確立: 接続情報を受け取ったクライアント同士は、STUN/TURNサーバー(NAT越えのための仕組み)を利用して直接通信路を確立しようと試みます。

一度P2Pのトンネルが確立されれば、シグナリングサーバーの役目は終わり、あとは当人同士で直接データをやり取りできます。このゲームでは、Render上のサーバーがこのシグナリングの役割だけを担っています。

PeerJSによる実装の簡略化

WebRTCのAPIを直接扱うのは、シグナリングの実装などを含めると非常に複雑です。そこで今回は、WebRTCを抽象化し、非常にシンプルなAPIでP2P通信を扱えるようにしたライブラリ PeerJS を採用しました。

フロントエンド(クライアント側)の実装

クライアント側のコードは驚くほどシンプルです。

main.js
// 自分のPeerオブジェクトを初期化
// 'peerjs-server.onrender.com' は自前でデプロイしたシグナリングサーバー
const peer = new Peer({
  host: 'peerjs-server.onrender.com',
  secure: true,
});

// シグナリングサーバーへの接続が完了すると'open'イベントが発火
peer.on('open', id => {
  // idが自分のID。これを相手に教える
  console.log('My peer ID is: ' + id);
});

// 相手から接続要求が来た時の処理
peer.on('connection', conn => {
  // データを受信した時の処理
  conn.on('data', data => {
    // dataには相手が置いた石の座標などが入ってくる
    console.log('Received:', data);
    // ゲーム盤面を更新する処理などをここに書く
  });
});

// 相手に接続しにいく処理
function connectToPeer(opponentId) {
  const conn = peer.connect(opponentId);
  // 接続が確立したら、データを送信できるようになる
  conn.on('open', () => {
    // 石を置いた時などにデータを送信する
    conn.send({ type: 'move', position: { x: 3, y: 4 } });
  });
}

PeerJSが内部でシグナリングサーバーとのやり取りや複雑な接続処理を全て行ってくれるため、開発者はon('connection')connect()といった直感的なメソッドでP2P通信を実装できます。

マッチングサーバー側の実装

Renderで動かしているサーバー側のコードはさらに短く、これだけです。

server.js
const { PeerServer } = require('peer');

const peerServer = PeerServer({
  port: 9000,
  path: '/',
});

console.log('PeerJS server running on port 9000');

PeerJSが提供するPeerServerを起動するだけで、シグナリングサーバーとして機能します。Renderの無料プランではWebサービスとしてデプロイするため、自動的にHTTPS化され、外部から安全にアクセスできるようになります。

プレイ方法

2 人のプレイヤー(A さん、B さん) で対戦を開始する手順です。

1. ゲームページを開く (A さん)

まず、A さんがゲームの URL にアクセスします。
少し待つと、Your ID の欄に固有の ID が表示されます。

Aさんのゲーム画面

2. 招待 URL をコピーする (A さん)

ID の隣にある 🔗 Share Link ボタンをクリックします。
対戦用の招待 URL がクリップボードにコピーされます。

Aさんのゲーム画面

デモurl:

https://kinn00kinn.github.io/osero_p2p_front.github.io/?connect_to=d5bdfc55-bbf0-4425-80e3-087291520299

3. URL を友達に送る (A さん → B さん)

コピーした URL を、LINE や Discord などのチャットで B さんに送ります。
URL を送った後、A さんはページを閉じたりリロードしたりせず、そのまま待機してください。

4. URL を開いて接続する (B さん)

B さんが A さんから送られてきた URL を開くと、「Opponent's ID」の欄に A さんの ID が自動で入力されています。
B さんは Connect ボタンをクリックします。

Bさんのゲーム画面

5. 対戦開始!

接続が成功すると、両者の画面でゲームが始まります。
先手は招待した側(A さん)で、黒石です。思う存分対戦をお楽しみください!

Aさんのゲーム画面

感想と今後の展望

今回、P2Pという技術を軸に据えることで、サーバーコストを一切かけずにリアルタイム対戦ゲームの雛形を構築できました。技術的な面白さを追求する、という点では非常に満足のいく開発体験でした。

一方で、本来の目的であった「面白いゲーム」の中身にまでは手が回らなかったのが心残りです。今後はこのP2P対戦の仕組みをベースにして、より複雑で戦略的な、自分だけのオリジナルゲーム開発に挑戦していきたいと考えています。

この記事が、WebRTCやP2P技術を使った開発に興味を持つきっかけになれば幸いです。
よかったらリポジトリにスターをお願いします!!

Discussion