← 一覧に戻る

Webゲーム開発におけるセーブ機能とオンラインランキングの実装手法(LocalStorageとFirebaseの活用)

Webゲームにランキング機能を付けたい。

でも、そのためだけにサーバーを契約し、APIを作り、データベースを管理するのは大変です。

わたしが開発している「ぴろぴろ競馬RX」でも同じ課題がありました。

そこで採用したのが、LocalStorageとFirebaseを組み合わせたサーバーレス構成です。

結果として、ほぼ無料に近いコストでセーブ機能と全国ランキングを実装できました。

この記事では、実際の構成やチート対策の考え方も含めて紹介します。

ブラウザで手軽に遊べるWebゲーム(HTML5/JavaScriptゲーム)において、「進捗を保存できるセーブ機能」と「世界中のプレイヤーと競い合えるランキング機能」は、プレイヤーのエンゲージメントと継続率を爆発的に高める極めて重要な機能です。今回は、「ぴろぴろ競馬RX」で実際に採用している、フロントエンド(LocalStorage)とサーバーレス(Firebase)を組み合わせた軽量かつ実用的な実装手法について技術的に解説します。

1. LocalStorageを用いたブラウザ側セーブ機能の構築

Webゲームにおいて、プレイヤーのゲーム進捗(獲得したメダル数、所持キャラクター、クリア状況など)を保存することは、継続してプレイしてもらうために不可欠です。「ぴろぴろ競馬RX」では、手軽さとレスポンスの速さを考慮し、ブラウザが標準で提供するLocalStorageを採用しています。

LocalStorageは、JavaScriptから非常にシンプルなAPIでデータの読み書きができるキー・バリュー型の保存領域です。以下のようにデータをJSON形式の文字列に変換して保存します。

// セーブデータの保存
const saveData = { medals: 500, unlockedHorses: ['horseA', 'horseB'] };
localStorage.setItem('piropiro_racing_save', JSON.stringify(saveData));

// セーブデータの読み込み
const savedJson = localStorage.getItem('piropiro_racing_save');
if (savedJson) {
    const data = JSON.parse(savedJson);
    console.log(`メダル数: ${data.medals}`);
}

2. クライアントサイドでのセーブデータ管理の限界と対策

LocalStorageは、手軽で完全に無料という大きなメリットがありますが、クライアント側の領域に保存されるため、知識のあるユーザーであればブラウザの開発者ツールなどを通じて容易にデータ(メダル数など)を書き換えることができてしまいます。このセキュリティリスクに対しては、以下のようなアプローチで対策を行います。

  • ハッシュ値(チェックサム)の併用: セーブデータそのものに加えて、データの各項目に秘密の鍵(ソルト)を混ぜ合わせた「ハッシュ値」を計算して保存します。読み込み時にデータから再計算したハッシュ値が一致しない場合、改ざんと判定してデータをリセットします。
  • データの暗号化: 保存するJSONデータを暗号化した上でLocalStorageに格納し、パッと見で中身が直接視認・編集されるのを防ぎます。(※こちらも復号キーがフロントエンド側に存在するため、高度な解析者に対する完全な防御にはなりません)
  • サーバー側でのセーブデータ管理(本質的な対策): 最も強固で本格的な対策は、そもそもクライアント側にセーブデータを直接管理させないことです。Firebase Authenticationなどのユーザー認証と紐付け、セキュアなデータベース(Cloud Firestore)側でデータを保存・同期し、書き込み時のロジック検証をサーバー側で厳格に行います。

「ぴろぴろ競馬RX」では現在、プレイヤーの気軽なプレイフィールと完全匿名での素早いゲーム開始を優先し、LocalStorageを用いたローカル保存を採用しています。しかし、全国ランキングの公正さを高めるための今後の開発ロードマップとして、データの整合性検証(ハッシュチェック)の導入や、認証を用いたサーバー側管理へのアップグレード設計を進めています。

3. Firebase Firestoreを利用したリアルタイム全国ランキングの構築

ゲームのモチベーションを最高潮に高めるのが「全国オンラインランキング」です。「ぴろぴろ競馬RX」では、バックエンドの開発・運用コストを極限まで下げるために、Firebaseが提供するドキュメント指向NoSQLデータベース「Cloud Firestore」を採用しています。

Firestoreは、サーバーを用意することなく、フロントエンドのJavaScriptから直接SDKを介してデータベースの読み書きが行えるサービスです。適切な「セキュリティルール」を記述・適用することで、データへのアクセス権限や不正な書き込みを制御できます。実装の流れは以下の通りです。

  1. データの送信: レース後に新記録(伝説の勇者誕生など)が達成された際、Firebase SDKを利用して `rankings` コレクションにプレイヤー名、スコア、タイムスタンプを書き込みます。(※メダル最大所持数などのセーブデータは自動で送信されるわけではなく、プレイヤーが希望して手動セーブを実行した際にLocalStorageへ保存される仕組みです)
  2. クエリとソート: データベース側で自動的にインデックスが貼られており、`orderBy("score", "desc").limit(50)` のようにクエリを叩くだけで、上位50名のデータを瞬時に取得できます。
  3. セキュリティルールの設定: フロントエンドから直接書き込めるため、悪意のあるユーザーがAPIを模倣してスコアを直接送信するチートリスクがあります。そのため、Firestoreの「セキュリティルール」を記述し、送信されるスコアの型や許容範囲を検証し、不正なデータ構造や異常値の登録を防ぎます。また過去の自身のデータ(UIDに紐づくデータ)以外を他人が勝手に更新できないように保護しています。

なお、Firestoreのセキュリティルールによって不正な直接書き込みを一定程度防ぐことはできますが、ゲームロジック自体がクライアント側のブラウザ上で動作する以上、完全なチート防止は困難です。より公平性を厳密に担保する場合は、Cloud Functionsなどを用いたサーバー側でのレース結果検証ロジックの実装(スコア算出の正当性チェック)が必要になります。

4. 技術の組み合わせによるアジリティの向上

もしこれらの機能を、自分でLinuxサーバーを借り、Node.jsやPythonでバックエンドAPIを開発し、MySQLなどのデータベースを設計して構築しようとすると、サーバー維持費がかかるだけでなく、セキュリティ脆弱性の担保や負荷分散対策など、個人開発者にとっては膨大な時間とコストが必要になります。

しかし、LocalStorage(完全無料・サーバー不要)+Firebase(従量課金、無料枠が非常に大きい)というアプローチを採ることで、個人開発規模では十分なスケーラビリティとセキュリティを確保したランキングシステムを、実質コストゼロで、かつ数日の開発期間で作り上げることが可能になりました。

5. まとめ

モダンなWeb技術とサーバーレスプラットフォームの登場により、現在ではフロントエンドエンジニア一人でも本格的な「マルチプレイヤー要素」を持つWebゲームを構築できます。「ぴろぴろ競馬RX」も、このような技術的な工夫の上に成り立っています。当ブログが、Webゲーム開発やフロントエンドでのアプリケーション設計を目指す開発者の方々の参考になれば幸いです!

あなたなら、セーブデータ管理にLocalStorageを使いますか?

それとも最初から認証+クラウド保存を選びますか?

ブログ一覧に戻る ゲームをプレイする