「結果画面」を作り込む:数字・比較・次の行動
遊びをつくる執筆にClaudeを使用しています。

ゲームが終わった直後、プレイヤーは画面から何を読み取りたいのでしょうか。点数が一つだけ出る画面を考えてみます。プレイヤーはまず「で、これは良かったのか」と思います。次に「なぜこの点なのか」、最後に「もう一回やるべきか、やめるべきか」と考えます。結果画面の仕事は、この三つの疑問に、出てくる順に答えることです。 この記事では、結果画面を最初から完成形にせず、要素を一つずつ足します。足すたびに「プレイヤーの次の疑問に答えられたか」を確かめます。順番は、数字(いくつ?)、比較(良かった?)、内訳(なぜ?)、次の行動(どうする?)です。順番を入れ替えると、読み手が混乱しやすくなります。たとえば比較より先に内訳を出すと、基準のない減点の一覧を読まされることになります。 コードはブラウザだけで動く最小構成です。外部ライブラリもサーバーも使いません。手順0〜4の断片を、同じ <script> の中に上から順に貼ってください。1つの index.html として保存して開けば動きます。
手順0と1:土台を作り、数字を一つだけ出す
最初に、表示部品を配列に並べるだけの土台を作ります。部品を後から足せる形にしておくと、「要素を一つずつ足す」作業がそのまま一行の追加になります。
手順0:土台(<script> は最後まで閉じません)
<div id="result"></div>
<script>
let best = null, last = null; // 画面を開いている間だけ保持
const target = 80; // 目標点。自分のゲームに合わせて決める
const el = document.getElementById("result");
const parts = []; // 表示部品を順に並べる
function showResult(r) {
el.innerHTML = parts.map(f => f(r)).join("");
last = r.score; // 次回の比較用。表示のあとで更新する
if (best === null || r.score > best) best = r.score;
}last と best を更新するのは、表示したあとです。表示の前に更新すると、比較の対象が今回の点数自身になってしまいます。これは後の手順2で起こりやすい誤りの一つです。
手順1:数字を一つだけ出す
parts.push(r => `<h2>${r.score} 点</h2>`);ここで一度ブラウザで確かめます。この時点の結果画面は、数字が一つあるだけです。この状態を基準として覚えておいてください。以降の手順で足した要素が、本当に読み手の助けになっているかを、この基準画面と見比べて判断します。
数字には、次の三点を決めておきます。
- 単位を付けます。「72」より「72 点」「14 手」「38 秒」のほうが、何の数字かを読み手が考えずに済みます。
- 大きく、一か所に置きます。結果画面で最初に目が行く場所は一つにします。
- 「大きいほど良い」か「小さいほど良い」かを決めます。手数や時間は小さいほうが良い数字です。この向きは手順2の比較で必ず効いてきます。
向きが決まっていない数字は、比較を足した途端に壊れます。点数のゲームなら大きいほうが良いので、このコードは大きいほうを良いとして書いています。手数や時間のゲームに流用する場合は、手順2の比較の向きを逆にしてください。
手順2:比較を足す
数字だけでは、良かったのか悪かったのか分かりません。比較の基準は大きく三つあります。前回の自分、これまでのベスト、決めておいた目標です。
アソバースでは、ゲーム内スコアの共通ランキングは提供されていません。そのため、投稿作品の結果画面で比べる相手は、基本的にプレイヤー自身の過去か、作者が決めた目標になります。これは弱点ではなく、設計の方針として使えます。「昨日の自分より進んだか」は、他人との順位よりも、もう一回遊ぶ理由になりやすい比較だからです。
手順2:前回比・ベスト・目標差
parts.push(r => {
if (last === null) return "<p>初回の記録です。</p>";
const d = r.score - last;
let s = `<p>前回比 ${d > 0 ? "+" : ""}${d}</p>`;
if (best !== null && r.score > best) s += "<p>ベスト更新</p>";
s += `<p>目標まであと ${Math.max(0, target - r.score)} 点</p>`;
return s;
});初回は last が空なので、比較の文を出さずに別の一文に切り替えています。ここを忘れると「前回比 NaN」のような崩れた表示が出ます。
公式作品の設計から読み取れることを一つ挙げます。「月夜の配達」には各夜の最少区間数の記録があり、「小さな軌道」には前回の軌道を細い実線で重ねる表示があります。どちらも「前回」や「最少」という比較の基準を、プレイ画面や記録の中に置いている作りです。実際の結果画面にどう出るかは、作品を開いて確かめてください。
比較の基準を増やしすぎないことも大切です。三つ全部を出すと、読み手はどれを見ればよいか迷います。最初は「前回比」か「目標まであと」のどちらか一つで十分です。
記録をどこまで残すか
上のコードの best は、ページを開いている間だけ残ります。アソバースの公式作品でも、保存があるのは「余白の庭」「WAVE / WAVE」「かたちのあいだ」の3作品で、他の10作品の記録は画面を開いている間だけです。また、アップロードした作品の中の localStorage / sessionStorage は一時メモリー向けの互換処理なので、永続的な保存先としては当てにしません。
ベスト記録を次回の起動後にも残したいときは、クラウドセーブを使う方法があります。アップロードしたゲームにはSDKが自動で追加され、ログイン中のプレイヤーなら作品ごとに128KiBまでのJSONを保存できます。ベスト点数ひとつなら容量はまったく問題になりません。具体的な呼び出し方は、現在の投稿ガイドで確認してください。ゲストの進行は端末内に保存され、ログイン後のアカウントへ自動では混ざらない点も、仕様として押さえておきます。
手順3:内訳を足す
比較で「良かった/悪かった」が分かると、次に出る疑問は「なぜ」です。内訳は、その疑問への答えです。ここで大切なのは、内訳の合計が数字と必ず一致することです。
手順3:内訳の一覧
parts.push(r => "<ul>" + r.items.map(i => `<li>${i.label}:${i.pts}</li>`).join("") + "</ul>");r.items は { label: "ミス 2 回", pts: -30 } のような配列で、ゲーム側が結果を作るときに一緒に渡します。スコアを内訳の合計から作るようにしておけば、表示のずれは起こりません。この記事のデモコードも、そうなっています。
内訳を作りやすいスコア設計には、共通点があります。「こだまの森」には、聴き直しで15点減、間違いで30点減(3回で終了)という減点の仕組みがあります。減点の理由が少数の種類に分かれているので、結果画面に「聴き直し ×2:−30」「間違い ×1:−30」と並べやすい構造です。これは設計から読み取れる範囲の話で、実際の画面の細部は作品を開いて確かめてください。
内訳の項目数は、多くても4〜5行にとどめます。細かすぎる内訳は、読んでも次の行動につながりません。「次に何を変えれば点が上がるか」が分かる粒度で切るのが目安です。
手順4:次の行動を足す
最後の要素が、次の行動へのボタンです。結果画面を見終わったプレイヤーは、ここで遊び続けるかどうかを決めます。
手順4:ボタンとテスト用の呼び出し
parts.push(() => '<button onclick="startGame()">もう一度</button>');
function startGame() {
const miss = Math.floor(Math.random() * 4); // 仮のミス回数
const items = [{ label: "基本点", pts: 100 }, { label: `ミス ${miss} 回`, pts: -15 * miss }];
showResult({ score: items[0].pts + items[1].pts, items });
}
startGame();
</script>startGame は、自分のゲームの開始処理に置き換えてください。ここでは動作確認のために、ミス回数を乱数で作る仮の関数にしています。ファイルを開いて「もう一度」を何回か押すと、初回の表示、前回比、ベスト更新、目標差が順に切り替わります。
次の行動のボタンには、設計上の判断が三つあります。
- 最も押してほしいボタンを一つだけ大きくします。多くの場合は「もう一度」です。
- 結果に応じてボタンを出し分けます。ミスが多かったなら「ゆっくり版で練習」、ベストを更新したなら「同じ条件でもう一度」のように、直前の結果と意味がつながる行動を並べます。
- 補助的な行動(メニューへ戻る、難易度を変える)は小さく、少し離して置きます。
「かたちのあいだ」には、同じ配置での再挑戦と、時計の一時停止があります。「やり直す」を同じ条件で選べるかどうかは、結果画面のボタンを設計するときの重要な判断材料になります。同じ条件でもう一度挑めるなら、前回との比較がそのまま意味を持つからです。
操作の面では、プレイ中に連打していたキーやボタンと同じ位置に「もう一度」を置くと、結果を読む前に押してしまう誤操作が起こりえます。ボタンの位置を少しずらすか、短い待ち時間を入れるかを検討します。
演出を足すときの注意
数字のカウントアップや紙吹雪などの演出は、ここまでの手順が終わってから足します。アソバースでは「動きを抑える」設定が用意されており、公式作品もこれに対応しています。自作で演出を入れるなら、matchMedia("(prefers-reduced-motion: reduce)") で設定を確認し、動きを抑える設定のときは最終の数字をすぐに表示してください。演出がなくても情報が全部読めることが前提です。
確かめ方と起こりやすい誤り
作ったあとは、足した要素が本当に効いているかを、自分の手で確かめます。次の手順で記録を取ります。
- 友人やテストプレイヤーに、結果画面だけが違う二つの版(手順1だけの版と、手順4まで入れた版)を、同じゲームで遊んでもらいます。
- 各回で、結果画面が出てから「次のボタンを押す」までの秒数を、ストップウォッチで計ります。単位は秒、1人あたり各版3回以上を目安にします。
- 結果画面で最初に目が行った場所と、「なぜその点だったか」を言葉で説明できたかを、聞き取りメモに残します。
- 結果の読み方です。手順4の版でボタンまでの時間が長くなっていても、悪いとは限りません。内訳を読んでいる時間かもしれないからです。「説明できたか」と合わせて判断します。逆に時間が極端に短く、説明もできていないなら、読まれずに飛ばされている可能性があります。
台数も人数も少ないテストなので、結果は傾向を見る材料にとどめ、断定には使わないでください。
起こりやすい誤りは次のとおりです。
- ベスト更新の判定を、best を更新した後に行っています。常に同点になり、「ベスト更新」が出ません。
- 初回の last が空のまま計算し、「NaN」が表示されます。
- 内訳の合計とスコアが食い違っています。スコアは内訳から作ってください。
- 数字、比較、内訳、ボタンを同じ大きさで並べています。最初に見せたいものから順に、大きさに差をつけます。
- 失敗の直後に、長い演出や説教めいた文言を出しています。次の行動を押すまでの手間が増え、離脱の原因になります。
- 手数や時間のゲームで、比較の向きを大きいほうが良いままにしています。手順1で決めた向きを、比較の判定に反映してください。
次の行動
自分のゲームの終了処理で、startGame の部分を実際の開始関数に置き換え、結果オブジェクト(score と items)を渡す形に整えてみてください。まず手順1だけの版を保存し、そこから手順2、3、4と一つずつ足して、そのたびに数回遊んでみます。
アソバースへ投稿するときは、直下の index.html を入口にして、素材は相対パスで参照します。投稿前に、公開済みの公式作品の終わりの画面を何本か開き、どの要素がどの順に出るかを見比べると、自作の足し引きの判断がしやすくなります。

