マガジン

ブラウザゲームのセーブ機能の作り方:端末保存からクラウドまで

遊びをつくる

執筆にClaudeを使用しています。

プレイヤーの駒と小さなゲームの世界をつなぐ橋、上に浮かぶ雲形の器
記事のテーマをもとに制作したAI生成イラスト。

ブラウザゲームを作るとき、「セーブをどう実装するか」は早めに決めておかないと後から直しづらい部分です。端末に保存するだけなのか、複数デバイスで引き継げるようにするのか。その選択によって、使うAPIも、データ構造も、必要な工数もまったく異なります。 この記事では、セーブの実装方法を「端末保存」「外部クラウド」「プラットフォームSDK連携」の3層に整理し、それぞれの仕組み・向いているゲームの種類・実装時の注意点を順に説明します。ゲームを一から作る人だけでなく、既存のゲームにセーブ機能を追加しようとしている人にも参考になるよう、判断基準を具体的に示します。

この記事の目次
  1. セーブ方式を選ぶ前に決めておくこと
  2. 端末保存の仕組みと使い分け
  3. 外部クラウドを使ったセーブの実装方針
  4. セーブデータの設計でよく失敗する点
  5. アソバースのSDKを使ったクラウドセーブ
  6. 次の行動
  7. 参考資料

セーブ方式を選ぶ前に決めておくこと

実装に入る前に、次の3点を決めると選択肢が絞れます。

1. セーブデータをどこに置くか「プレイしたその端末にだけ残ればいい」のか、「スマホとPCで同じデータを使いたい」のかで、方式が変わります。端末保存で済むなら外部サービスは不要です。

2. データ量と更新頻度ハイスコア1件を保存するだけなのか、マップ全体の状態・インベントリ・フラグを細かく保存するのかで、選ぶストレージの種類が変わります。細かいデータを毎秒書き込むなら、書き込みコストが低い手段を選ぶ必要があります。

3. ログイン要件を受け入れられるかクラウド保存は原則としてユーザーの識別(ログイン)が必要です。「ログイン不要で遊べること」を重視するなら、端末保存が現実的です。

この3点の答えが出たら、以下の各方式と照らし合わせてください。

端末保存の仕組みと使い分け

ブラウザが標準で持つ端末保存の手段は主に3つあります。

localStorage

文字列をキーと値のペアで保存します。容量はブラウザによって異なりますが、一般的に数MB程度です。同一オリジン(ドメイン)内であればどのページからでも読み書きでき、ブラウザを閉じてもデータは消えません。

js
// 保存
localStorage.setItem('saveData', JSON.stringify({ level: 3, hp: 80 }));

// 読み込み
const data = JSON.parse(localStorage.getItem('saveData') ?? 'null');

ハイスコア・クリア済みステージ・設定値など、構造がシンプルなデータに向いています。注意点は、シークレットモードやプライベートブラウズでは閉じたときに消えること、そして同じドメインを複数ゲームで共有している場合はキー名が衝突することです。キー名にゲーム固有のプレフィックス(例:mygame_v1_save)を付ける習慣をつけておくと安全です。

sessionStorage

localStorageと同じAPIですが、タブを閉じるとデータが消えます。セーブ用途より「直前のステージ情報を一時保持する」といった使い方に向いています。

IndexedDB

ブラウザ内蔵のデータベースです。localStorageより大容量で、バイナリデータや構造化データも扱えます。マップ全体の状態・大量のアイテムデータ・オートセーブの履歴など、保存量が多い場合に選びます。

APIが非同期かつやや複雑なため、直接触るよりidbなどの薄いラッパーライブラリを使うほうが開発速度が上がります。容量上限はブラウザとOSの空き容量によって変わるため、公式ドキュメントで最新の仕様を確認してください。

外部クラウドを使ったセーブの実装方針

端末をまたいでデータを同期したい場合は、外部のクラウドサービスにデータを預けます。代表的なパターンを紹介します。

Firebase Realtime Database / Firestore

Googleが提供するBaaS(バックエンド・アズ・ア・サービス)です。Firebaseの認証機能と組み合わせると「Googleアカウントでログイン → そのUIDをキーにセーブデータを保存」という流れを比較的短いコードで実現できます。

実装の大まかな流れは次のとおりです。

  1. Firebaseプロジェクトを作成し、JavaScriptのSDKをHTMLに読み込む
  2. 認証(signInWithPopupなど)でユーザーUIDを取得する
  3. doc(db, 'saves', uid) のようなパスにセーブデータをオブジェクトとして書き込む
  4. ゲーム起動時に同じパスから読み込んでゲーム状態を復元する

無料枠の範囲と制限については公式サイトで最新の条件を確認してください。小規模なゲームであれば無料枠の範囲で運用できることが多いですが、プレイヤーが増えたときの読み書き回数には注意が必要です。

Supabase

PostgreSQLをベースにしたオープンソースのBaaSです。Firebaseに近い感覚で使えますが、データがリレーショナルな構造を持つため、複雑なセーブデータの検索・集計がしやすいという特徴があります。ランキング集計などと組み合わせる場合に向いています。

セーブデータの設計でよく失敗する点

方式を選んだあとも、データ構造の設計でつまずくケースがあります。

バージョン管理を入れておく

ゲームをアップデートしたとき、古いセーブデータと新しいデータ構造が合わなくなることがあります。セーブデータには必ず version フィールドを持たせ、読み込み時にバージョンを確認して変換処理(マイグレーション)を挟む習慣をつけてください。

js
const DEFAULT_SAVE = { version: 1, level: 1, flags: {} };

function loadSave() {
  const raw = JSON.parse(localStorage.getItem('save') ?? 'null');
  if (!raw) return { ...DEFAULT_SAVE };
  if (raw.version < 1) return migrate_v0_to_v1(raw);
  return raw;
}

オートセーブの間隔を慎重に決める

ステージクリア時・重要なイベント発生時など「意味のある区切り」でセーブするのが基本です。毎フレーム書き込むとlocalStorageでも処理が重くなる場合があります。クラウド保存であれば書き込み回数がコストに直結するため、デバウンス(一定時間内の連続呼び出しをまとめる)を使って書き込みを間引く実装が有効です。

セーブ失敗時のフォールバック

クラウド書き込みが失敗した場合は、localStorageにも同じデータを保存しておく「ローカルキャッシュ」パターンが安全です。次回の通信成功時にクラウドへ同期する仕組みにしておくと、オフライン時でもゲームを続けられます。

アソバースのSDKを使ったクラウドセーブ

アソバースでは、作者がSDKに対応した実装を行ったゲームに限り、アソバースのアカウントと連携したクラウドセーブ機能を利用できます。アソバースのログインが自動でゲーム内に適用されるわけではなく、SDKを使って明示的に連携する必要があります。

この方式の利点は、プレイヤーがアソバースにログインしている状態であれば追加のアカウント登録なしにセーブデータを同期できる点です。プレイヤーの負担を下げながらクラウドセーブを提供したい場合に検討する価値があります。独自の外部BaaSと組み合わせるか、アソバースSDKだけで完結させるかは、ゲームの規模とプレイヤー層に応じて判断してください。

プレイ履歴(どのゲームを遊んだかのプラットフォーム側の記録)とゲーム内部のセーブデータは別物です。SDKで連携しない場合、プレイヤーがアソバースにログインしていてもゲーム内のセーブはゲーム自身が管理する必要があります。

次の行動

まずゲームのセーブ要件(端末保存で足りるか・ログイン必須にできるか・データ量はどの程度か)を一枚のメモに書き出し、この記事の3方式と照らし合わせてみてください。端末保存で足りるなら今日からでもlocalStorageの実装を始められます。クラウドが必要なら、FirebaseまたはSupabaseの公式ドキュメントでクイックスタートを確認するのが最初の一歩です。アソバースへの投稿を予定しているならば、SDKドキュメントも併せて参照し、クラウドセーブ連携の実装タイミングを検討してみてください。

参考資料

  • MDN Web Docs「Window: localStorage プロパティ」
  • MDN Web Docs「IndexedDB API」
  • Firebase 公式ドキュメント(Authentication・Firestore)
  • Supabase 公式ドキュメント
  • アソバース SDK 公式ドキュメント