マガジン

ゲームの設定とセーブを分けて保存する理由

遊びをつくる

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

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

ゲームを作るとき、「音量」「キー配置」「言語」といった設定と、「レベル」「所持アイテム」「クリア済みステージ」といった進行データを、同じオブジェクトにまとめて保存したくなることがあります。コードが短くなるように見えるからです。しかし実際に運用が始まると、この判断が原因で起きるバグや、プレイヤーの不満が増えていきます。 この記事では、設定データと進行データを分けて保存することの意味を、「なぜ分けるのか」という問いへの答えから出発して、具体的な設計判断と実装の考え方まで順に説明します。

この記事の目次
  1. 「設定」と「セーブ」は更新タイミングが根本的に違う
  2. 設定データが持つべき性質
  3. 実装上の分け方:最低限の考え方
  4. 分けるときに判断が必要な「グレーゾーン」
  5. 分けたことで生まれるメリットを整理する
  6. 次の行動

「設定」と「セーブ」は更新タイミングが根本的に違う

設定データとセーブデータの最大の違いは、いつ・なぜ書き換えるかです。

設定は、プレイヤーが能動的に操作画面を開いて変更するものです。1回のプレイセッションで一度も変わらないこともありますし、ゲームをクリアした後に音量だけ下げることもあります。変更頻度は低く、かつプレイの進行とは無関係に起こります。

セーブデータは逆で、ゲームの進行に合わせて継続的に更新されます。チェックポイント通過、アイテム取得、経験値の増減など、プレイ中のさまざまな出来事のたびに書き込みが走ります。更新頻度が高く、書き込みの失敗や中断によるデータ破損リスクも設定より高くなります。

この2種類を同じストレージキーに混在させると、セーブ処理が走るたびに設定も上書きされます。セーブに失敗したとき、設定まで失われます。ゲームを別端末で再開しようとしてセーブデータだけ移したら、設定がリセットされます。逆に設定を変えただけでセーブスロットの更新日時が変わり、「最後にプレイした時刻」の表示がずれます。こうした問題はすべて、更新タイミングの違いを無視したことから生まれます。

設定データが持つべき性質

設定には、セーブとは異なる三つの性質があります。

端末ローカルに残ってよい。音量やキー配置は、その端末の環境に紐づく情報です。クラウドに同期して別端末へ持ち越すかどうかは設計次第ですが、少なくとも「同期しない」という選択肢が成立します。セーブデータは多くの場合クラウド同期が必要ですが、設定は端末のlocalStorageなどに置いたままでも実用上の問題が起きにくい領域です。

ゲームをアンインストールしても消えないほうが望ましい場合がある。PC向けのアプリやブラウザゲームでは、キャッシュをクリアしたり別ブラウザで開いたりすると設定がリセットされます。これは許容されることが多いですが、プレイヤーがわざわざ変更した設定が失われることへの不満は小さくありません。保存先を意識して選ぶためにも、セーブと設定を分けておく必要があります。

デフォルト値へのリセットがセーブに影響しない。設定をリセットする機能は、初期不良対応や操作ミスの修正のために使われます。このとき「進行データも消える」という挙動になると、プレイヤーはリセット操作をためらいます。分離しておけば、設定のリセットはセーブに触らずに完結します。

実装上の分け方:最低限の考え方

コードレベルで設定とセーブを分ける方法はシンプルです。ストレージのキー名を別にする、それだけです。

// 例:localStorage を使う場合の概念
localStorage.setItem("settings_v1", JSON.stringify(settingsObject));
localStorage.setItem("save_slot1_v1", JSON.stringify(saveObject));

キー名にバージョン番号を付けておくと、後でデータ構造を変更したときの移行処理を書きやすくなります。settings_v1をsettings_v2に切り替えるとき、v1が残っていれば読んで変換し、なければデフォルトに戻す、という分岐が明確に書けます。セーブとバージョン管理が混在していると、この分岐が複雑になります。

クラウドストレージやゲームSDKを使う場合も同様です。保存先のパスやコレクション名を設定用とセーブ用で分けておくことで、それぞれに適した同期タイミング・容量上限・バックアップ戦略を選べます。たとえばセーブデータは変更のたびに即時同期し、設定はセッション終了時にまとめて同期するという方針をとれます。

分けるときに判断が必要な「グレーゾーン」

設定とセーブの境界が曖昧なデータも存在します。以下の3パターンは、どちらに置くかを意識的に決める必要があります。

チュートリアルの表示フラグ。「チュートリアルを見た」というフラグは、プレイの進行に属するためセーブに置くのが自然です。しかし「ヒントを常に表示する」という設定と混同されやすく、どちらに入れるか迷いやすいです。「プレイヤーが能動的にオン・オフできるか」を基準にすると判断しやすくなります。

グラフィック品質。端末の性能に応じて変えるものは設定ですが、ゲーム内のアンロック要素(特定のグラフィックモードを解除する等)が絡む場合はセーブ側の情報と連動します。アンロック状態はセーブに、表示品質の選択は設定に置き、参照時に組み合わせる設計が分かりやすいです。

最後にプレイしたスロット番号。「前回のセーブを続ける」機能のために最後に選んだスロット番号を記憶したい場合、これは設定でも進行データでもありません。専用の「メタ情報」として独立したキーに保存するか、設定オブジェクトの中の「UI状態」セクションに置く方法が一般的です。

分けたことで生まれるメリットを整理する

設計の手間が増えるように感じるかもしれませんが、分けたことで得られる具体的なメリットは次の通りです。

  • セーブデータの破損・削除が設定に波及しない
  • 設定のリセット・インポート・エクスポートをセーブと独立して実装できる
  • セーブスロットを複数持つゲームで、スロットをまたいで共有すべき情報(設定)とスロットごとに持つべき情報(進行)を明確に分離できる
  • バックアップや移行ツールを作るとき、対象を絞りやすい
  • 将来の仕様変更時に、影響範囲を小さく保てる

特にセーブスロットが複数あるゲームでは、設定が「スロット1のセーブ」に紐づいてしまうと、スロット2でプレイするたびに設定が変わる、という問題が起きます。設定はスロットの外に置く、という判断がここで生きてきます。

次の行動

今作っているゲームのストレージ保存処理を開き、設定に相当するデータとセーブに相当するデータが同じキーに混在していないか確認してみてください。混在していれば、キーを分割するだけでも将来のデバッグコストを大きく下げられます。アソバースのSDKを使ってクラウドセーブを実装する場合も、保存するオブジェクトの設計段階でこの分離を意識しておくと、後から構造を変える手間を減らせます。