マガジン

対戦履歴の保存と表示:何を残すか

遊びをつくる

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

机上の二つの端末の間に、小さなゲームの駒と記録カードが並ぶイラスト。
記事のテーマをもとに制作したAI生成イメージ。実際のゲーム画面ではありません。

対戦ゲームに履歴機能を付けようとしたとき、最初に悩むのは「何を保存するか」という設計の問いです。勝敗だけを記録するのか、盤面の全手順を再生できるようにするのか、どこまで残すかによって実装の複雑さもストレージの負荷も大きく変わります。 この記事では、対戦履歴の設計を「目的ごとに何を残すべきか」という判断軸から整理します。実装の出発点となるデータ構造の考え方と、表示側の設計で失敗しやすいポイントも合わせて説明します。

この記事の目次
  1. 履歴を「何のために残すか」を先に決める
  2. 保存するデータの単位と構造
  3. 保存先の選択と容量の見積もり
  4. 表示設計で失敗しやすいポイント
  5. 削除・非公開の設計も忘れずに
  6. 次の行動
  7. 参考資料

履歴を「何のために残すか」を先に決める

設計を始める前に、履歴の用途を明確にしておくことが重要です。用途があいまいなまま実装すると、あとから「やっぱりリプレイも見せたい」と追加しようとしたときにデータ構造から作り直す羽目になります。

主な用途は次の三つに分かれます。

  • 実績・統計の表示:勝率、対局数、連勝記録などを集計して見せる。プロフィール画面や「今月の成績」欄に使う用途です。
  • 対局一覧の閲覧:いつ誰と対戦してどちらが勝ったかを時系列で確認できるようにする。SNSのタイムラインに近いイメージです。
  • 棋譜・リプレイの再生:手順を記録しておき、あとから試合の流れを再現する。チェスや囲碁のゲームで見かける機能です。

三つを同時に実現しようとするとデータ量が増えますが、「統計だけ」であれば保存するのは数値のみで済みます。まず用途の優先順位を決め、その用途に必要な最小限のデータを設計することが、後から壊れにくい履歴機能への近道です。

保存するデータの単位と構造

用途が決まったら、一試合分のデータをどう持つかを設計します。ここでは「対局一覧の閲覧」と「リプレイ再生」の二段階を例に、それぞれのデータ構造の考え方を整理します。

対局一覧に必要な最小セット

一覧表示だけなら、一試合を表すレコードに必要なフィールドはおおむね次の程度です。

  • 試合ID(一意な識別子)
  • 参加プレイヤーのID(または名前)
  • 勝者のID、または引き分けを示すフラグ
  • 試合終了時刻のタイムスタンプ
  • ゲームの種類(複数ゲームを一元管理するなら必要)

このセットを一行として保存しておけば、「直近10件の対局」や「特定プレイヤーとの勝率」を表示することは十分可能です。ファイルサイズも小さく、クライアント側でのフィルタリングも容易です。

リプレイに必要な手順記録

リプレイを実現するには、試合の経過を手順ごとに記録する別テーブル(またはネストされた配列)が必要になります。チェスなら「e2-e4」のような指し手のリスト、カードゲームなら「どのカードをいつ使ったか」のイベント列です。

重要な判断点は、「盤面のスナップショットを保存するか、手順だけを保存するか」です。

  • 手順のみ:データ量は少ないが、再生時に初期状態から手順を追って盤面を復元する処理が必要。
  • スナップショット付き:一定間隔で盤面全体を保存しておくことで途中から再生できる。データ量は増える。

カジュアルなゲームであれば手順のみで十分なことがほとんどです。手順数が数十程度ならば初手から再生してもユーザーは違和感を感じません。手順が数百を超えるような長期戦のゲームでは、途中からシークできる仕組みが必要になるため、スナップショット設計が現実的です。

保存先の選択と容量の見積もり

ブラウザゲームで履歴を保存する場合、主な保存先はサーバー側のデータベース、クライアント側のlocalStorage、またはその両方です。

localStorageはサーバー不要で手軽ですが、容量の上限が一般的に数MBと小さく、ブラウザやデバイスをまたいで共有できません。「そのデバイスだけで楽しむ1人用の統計記録」ならば有効な選択肢です。対戦記録は相手と共有される性質のデータなので、本来はサーバー側に保存するのが自然です。

サーバー側に保存するとき、容量の増え方を事前に見積もることが大切です。一試合あたりの記録が1KBだとすると、1万試合で約10MBです。手順記録を含めると一試合あたり10〜100KBになるゲームもあります。試合数の想定と単価をかけ合わせて、ストレージプランが現実的かどうかを確認しておきましょう。古い履歴を一定期間で削除するか圧縮するかの方針も、設計初期に決めておくと後が楽です。

アソバースのSDKを使う場合、クラウドセーブはSDKで対応したゲームだけが利用できます。プレイ履歴とゲーム内部のセーブは別物として扱われるため、詳細な対局記録を保持したい場合はゲーム側で保存先を設計する必要があります。公式ドキュメントで最新の仕様を確認してください。

表示設計で失敗しやすいポイント

データを保存できても、表示が使いにくければ履歴機能は機能しません。よくある失敗を三点挙げます。

情報量が多すぎる一覧:全フィールドをそのまま並べた表は読む気を失わせます。一覧には「日時・対戦相手・勝敗」の三点だけを見せ、詳細はタップで展開する二段階構成が使いやすい設計です。

時刻の表示形式が機械的すぎる:2026-10-20T14:32:00ZのようなISO形式はログとしては正確ですが、画面に出すには「3日前」「10月20日」のような人が読みやすい形式に変換する処理が必要です。JavaScriptであればIntl.RelativeTimeFormatやIntl.DateTimeFormatを使うことで、ロケールに合わせた表示を実現できます。

「自分が勝ったか負けたか」が即座にわからない:一覧を見てすぐに勝敗を把握できるよう、色・アイコン・ラベルで視覚的に区別することが基本です。「Win / Lose / Draw」の三択を色分けするだけでスキャン速度が大幅に上がります。テキストだけに頼った設計は、リストが長くなるほど読み疲れを招きます。

削除・非公開の設計も忘れずに

対戦履歴は個人のプレイデータです。プレイヤーが自分の記録を削除したい場合に対応できる設計にしておくことが、長く運用するうえで重要です。

最低限考えておきたい点は次の二つです。一つ目は、プレイヤーが自分の履歴を個別に削除できるか、または全消去できるかです。二つ目は、削除したとき相手側の履歴に残るデータをどう扱うかです。「この試合は相手がアカウントを削除した対局」として残すか、ともに消すかはポリシーとして決める必要があります。

また、履歴を「公開・非公開」で切り替えられる設計にしておくと、プレイヤーが自分のペースで使えるようになります。全試合を公開するのか、自分だけが見られるのか、この選択肢があるだけでゲームへの安心感が変わります。

次の行動

まず「この履歴機能は実績表示のためか、リプレイのためか」を決め、用途に合った最小データセットを設計してください。保存先とデータ量の見積もりはその直後に行うと、後からの設計変更を防ぎやすくなります。作ったゲームをアソバースに投稿する場合は、履歴の保存先としてSDKのクラウドセーブを使うかどうかを公式ドキュメントで確認してから実装を始めると、手戻りを減らせます。

参考資料

  • MDN Web Docs(Intl.RelativeTimeFormat、Intl.DateTimeFormat)
  • アソバース 公式開発者ドキュメント(SDK・クラウドセーブ仕様)