マガジン

「一日の記録」を作り込む:夜ごと・日ごとの記録の設計

遊びをつくる

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

遊んだ記録を示すカード列と、途中の位置を残した迷路盤を並べた写真風イメージ。
記事のテーマをもとに制作したAI生成イラスト。

「月夜の配達」には3つの夜があり、夜ごとに最少区間数が記録されます。同じ仕組みで「今日の記録」を作りたくなったとき、そのままコピーすれば足りるのでしょうか。実際には、夜は3つで固定ですが、日は放っておいても増え続けます。この違いが、記録の設計をいくつか変えます。 この記事では、月夜の配達の夜の記録を参考にして、日単位の記録を最小のコードで作ります。決めるのは、記録する項目、日の鍵(キー)、更新のルール、画面への出し方、保存の範囲の5つです。 手順の途中で出てくる数字やサンプルは、動作確認用のダミーです。実際にどんな値が妥当かは、自分のゲームで記録を取って確かめてください。

この記事の目次
  1. 月夜の配達の「夜の記録」から借りるもの
  2. 手順1〜2:項目と「日の鍵」を決める
  3. 手順3〜4:最小のコードで記録する
  4. 手順5〜6:画面に出し、保存の範囲を決める
  5. 起こりやすい失敗と、自分で確かめる方法
  6. 次の行動
  7. 参考資料

月夜の配達の「夜の記録」から借りるもの

月夜の配達は、小包3つ、バッグ2枠、有限の燃料(1区間で燃料1)で夜の経路を解くパズルです。公式の案内で確認できる記録は、各夜の最少区間数がプレイ中だけ残る、という点です。ここから読み取れることは3つあります。

  • 記録は「夜」という単位に結びついています。夜が変われば、比べる相手も変わります。
  • 記録の中身は「少ないほどよい一つの数」です。1区間で燃料1を使うので、区間数の少なさは燃料の節約と同じ意味になり、理由が説明しやすい数になっています。
  • 画面を開いている間だけの記録なので、重い保存の仕組みなしで成り立っています。

日単位に移すときは、この3点を問い直します。比べる単位は何か。残す数は何か。どこまで残すか。以降の手順は、この3つの問いに順に答えていく形です。

手順1〜2:項目と「日の鍵」を決める

手順1:その日の記録に入れる項目を、5つ以内で決めます。

月夜の配達の最少区間数にあたる「良し悪しを表す数」を1つ選び、それに行動の数を足します。たとえば次のとおりです。

  • 挑戦回数(plays)
  • クリア回数(clears)
  • 最少の数(best)。月夜の配達なら区間数にあたります
  • ヒントの使用回数(hints)
  • 戻した回数(undos)

月夜の配達にはヒントと一歩戻る機能があります。そのため、最少の数と並べて「ヒントや戻しをどれだけ使ったか」を持つと、同じ最少でも内容の違いが見えます。ただし、項目を増やすほど、画面に出す説明と、更新のコードの負担が増えます。最初は5つまでにとどめます。

手順2:日の鍵を「年-月-日」の文字列にし、基準の時刻を決めます。

鍵は 2026-10-22 のような文字列にします。ここで決めておくことが1つあります。日付の切り替わりを、遊ぶ人の端末の時刻に合わせるのか、世界共通の時刻に合わせるのかです。遊ぶ人自身の「今日」を見せたい記録なら、端末の日付が自然です。ただし、端末の時計を変えれば鍵も変わります。共通ランキングのような競い合いに使う記録では、この性質は弱点になります。

なお、アソバースにはゲーム内スコアの共通ランキングがありません。この記事の日記録は、あくまで本人が自分の変化を見るためのものとして設計します。

手順3〜4:最小のコードで記録する

手順3:下のコードを1つのHTMLファイルとして保存し、ブラウザで開きます。 外部ライブラリは使わず、単独で動きます。ボタンを押すと、ダミーの1回分の結果が今日の記録に加わります。

html
<!doctype html>
<meta charset="utf-8">
<p id="out"></p>
<button id="done">今日の一回を終える</button>
<script>
const state = { version: 2, days: {} };

function todayKey(d = new Date()) {
  const m = String(d.getMonth() + 1).padStart(2, "0");
  const day = String(d.getDate()).padStart(2, "0");
  return `${d.getFullYear()}-${m}-${day}`;
}

function recordRun(run, key = todayKey()) {
  const day = state.days[key] ||=
    { plays: 0, clears: 0, best: null, hints: 0, undos: 0 };
  day.plays += 1;
  day.hints += run.hints;
  day.undos += run.undos;
  if (run.cleared) {
    day.clears += 1;
    if (day.best === null || run.steps < day.best) day.best = run.steps;
  }
  return day;
}

function render() {
  const key = todayKey();
  const d = state.days[key];
  document.getElementById("out").textContent = d
    ? `${key}:${d.plays}回挑戦、${d.clears}回クリア、最少${d.best ?? "-"}、ヒント${d.hints}回、戻す${d.undos}回`
    : `${key}:まだ記録がありません`;
}

document.getElementById("done").onclick = () => {
  recordRun({ cleared: true, steps: 5 + Math.floor(Math.random() * 3), hints: 1, undos: 0 });
  render();
};
render();
</script>

手順4:更新のルールを、コードの上で確かめます。 次の3点を見てください。

  1. 最少の数は、クリアしたときだけ更新されます。未クリアの挑戦では best が null のままです。「0」と書くと最少として最良になってしまうため、null で「まだない」を表しています。
  2. 挑戦回数、ヒント、戻しは、クリアに関係なく足されます。失敗の積み重ねも一日の記録の一部だからです。
  3. recordRun の第2引数に鍵を渡せます。この口は、のちに日付をまたぐ場面を確かめるときに使います。

手順5〜6:画面に出し、保存の範囲を決める

手順5:「今日」と「これまでの最少」を並べて出します。 月夜の配達の夜の記録は、夜ごとに1つの最少値を示すものです。日の記録では、今日の最少と、過去の日を含めた最少の両方が意味を持ちます。過去分は次のように求めます。

js
const allBest = Math.min(...Object.values(state.days)
  .map(d => d.best).filter(v => v !== null));

記録が1件もない場合は、Math.min() が無限大を返します。表示の前に「記録なし」の分岐を入れてください。

手順6:保存の範囲を決め、日の数が増え続けない工夫を入れます。 公式の13作品では、記録が残る範囲は2通りです。余白の庭・WAVE / WAVE・かたちのあいだは保存があり、他の10作品は画面を開いている間だけです。日の記録を作るなら、次の3段階から選びます。

  • 画面を開いている間だけ、内容:上のコードのまま、向く場面:一回の遊びの中で、複数の挑戦を比べたいとき
  • 端末への保存、内容:ブラウザの保存機構を使う、向く場面:日をまたいで比べたいとき
  • クラウドセーブ、内容:SDKを通した作品ごとのJSON(128KiBまで)、向く場面:端末をまたいで続けたいとき

アソバースにアップロードしたゲームでは、アップロード作品内の localStorage と sessionStorage は一時メモリーの互換処理として扱われます。つまり、日をまたぐ記録は、そこだけでは当てにできません。日をまたいで残したいなら、SDKのクラウドセーブを使う設計にします。SDKの具体的な呼び出し方は、現在の公式案内で確認してください。

どの段階を選ぶ場合でも、保存する形には version を入れておきます。公式の13作品も、古い保存(version1)を新しい形式(version2)へ移行しています。項目を足したくなる日は必ず来るため、旧形式を読んで新形式へ直す口を最初から用意すると楽です。

起こりやすい失敗と、自分で確かめる方法

日の記録は、夜の記録にない種類のつまずきを抱えます。次の確認を、自分の手で行ってください。

  1. 日付をまたぐ確認。 recordRun に "2026-10-21" と "2026-10-22" の鍵を交互に渡し、日ごとに別の行ができるかを確かめます。端末の時計を動かす必要はありません。
  2. 0時前後の一回。 遊び始めが23時台で、クリアが0時を過ぎた挑戦を、どちらの日に数えるかを決めてください。「始めた日」と「終えた日」のどちらでも構いませんが、決めないまま作ると、日によってずれが出ます。
  3. データ量の確認。 日が増えるほど、保存するJSONは大きくなります。JSON.stringify(state).length で文字数を見て、128KiBの上限に対して余裕があるかを把握します。日数を何日分残すかは、その結果で決めてください。たとえば直近の何十日かだけを残し、古い日を削る方法があります。
  4. 0と「まだない」の区別。 最少の数が null のとき、画面で「0」と出ていないかを確認します。

次の行動

まず手順3のコードを動かし、自分のゲームで記録したい項目を5つ以内に絞ってください。次に、日付をまたぐ確認の1と3を実行して、鍵の決め方と保存量の見通しを立てます。公開前には、保存の範囲を紹介文に書くかどうかも検討しておくと、遊ぶ人の戸惑いが減ります。

参考資料

  • アソバース内の「月夜の配達」作品ページ(作品を開いて夜の記録の表示を確かめる)
  • アソバース公式の投稿ガイド(SDK・クラウドセーブの現在の案内)