同じコードで2つの遊び方ができるか——設定値を一つ変えて確かめる実験
遊びをつくる執筆にClaudeを使用しています。

落ちてくる光を、左右に動く受け皿で受け止めるミニゲームを考えてみます。受け止めると加点され、逃すと減点されます。ここで設定値を一つだけ変え、「触れたら減点、避けきれたら加点」にしたとします。画面も操作も落下の順番も変わっていません。それでもプレイヤーは、別の遊びだと感じるでしょうか。 この記事は、その答えを書くものではありません。答えは、読者が自分で手を動かして記録を取ることで出ます。コードは短いHTML一枚です。変えるのは TOUCH_VALUE という数値一つだけです。「受け止める遊び」と「避ける遊び」は、本当に別の遊びとして成立しているのか。それを判断するために、何を準備し、何を記録し、どう読むかを順に示します。
この実験で確かめる問い
中心にする問いは次の一つです。
設定値を一つ変えるだけで、プレイヤーの動き方は変わるのか。
スコアの比較は、この問いの答えにはなりません。今回のコードでは、触れたときに TOUCH_VALUE を加え、床まで落ちたときに TOUCH_VALUE を引きます。同じ操作を繰り返せば、得点は符号が逆になるだけです。つまりスコアは、遊びが分かれたかどうかの証拠として弱いのです。見るべきなのは、プレイヤーの動きに違いが出るかどうかです。
そこで「別の遊びになった」と言える条件を、遊ぶ前に決めておきます。この記事では次の二つを手がかりにします。
- 操作中の受け皿の位置が、落ちてくる光に対してどう違うか(数値で記録します)
- 遊んでいる最中に意識していたことが違うか(一言メモで記録します)
結果を見てから基準を決めると、都合のよい解釈を選びやすくなります。基準は先に書き出しておきます。
準備するもの
- テキストエディタ(メモ帳でも構いません)
- ブラウザ(普段使うもの一つに固定します)
- 入力装置(キーボードの左右キーに固定します。マウスやタッチと混ぜません)
- 記録用の紙か表計算ソフト
次のコードを index.html として保存します。外部ライブラリは使わず、このファイル一つで動きます。
<canvas id="c" width="320" height="400" style="touch-action:none;background:#123"></canvas>
<script>
const TOUCH_VALUE = 1; // 1なら受け止める遊び、-1なら避ける遊び
const g = document.getElementById('c').getContext('2d');
const cv = g.canvas;
let px = 160, score = 0, drops = [], t = 0, left = 1800, seed = 12345;
let gap = 0, n = 0; // 記録用: 最も低い落下物との横のずれ
function rnd() { seed = (seed * 1664525 + 1013904223) % 4294967296; return seed / 4294967296; }
const keys = {};
addEventListener('keydown', e => keys[e.key] = true);
addEventListener('keyup', e => keys[e.key] = false);
cv.addEventListener('pointermove', e => { px = e.offsetX * 320 / cv.clientWidth; });
function step() {
if (left <= 0) return;
left--; t++;
if (keys.ArrowLeft) px -= 4;
if (keys.ArrowRight) px += 4;
px = Math.max(25, Math.min(295, px));
if (t % 30 === 0) drops.push({ x: 10 + rnd() * 300, y: 0 });
for (const d of drops) d.y += 3;
if (drops.length) {
const low = drops.reduce((a, b) => b.y > a.y ? b : a);
gap += Math.abs(low.x - px); n++;
}
drops = drops.filter(d => {
if (d.y > 360 && d.y < 380 && Math.abs(d.x - px) < 25) { score += TOUCH_VALUE; return false; }
if (d.y >= 400) { score -= TOUCH_VALUE; return false; }
return true;
});
}
function draw() {
g.clearRect(0, 0, 320, 400);
g.fillStyle = '#fd6';
for (const d of drops) { g.beginPath(); g.arc(d.x, d.y, 8, 0, 7); g.fill(); }
g.fillStyle = '#8cf'; g.fillRect(px - 25, 370, 50, 10);
g.fillStyle = '#fff'; g.font = '14px sans-serif';
g.fillText('得点 ' + score + ' 残り ' + Math.ceil(left / 60) + '秒', 8, 18);
if (left <= 0) g.fillText('平均ずれ ' + Math.round(gap / n) + 'px', 8, 38);
}
function loop() { step(); draw(); requestAnimationFrame(loop); }
loop();
</script>このコードの設計上のポイントは三つあります。
- 乱数の種(seed)を固定しています。 光の落ちる位置と順番は、どのモードでも毎回同じです。違いが出たとき、原因を落下の偶然ではなく設定値に絞れます。
- 「触れた」と「逃した」の扱いを、符号だけで反転させています。 判定の式を二通り書き分けていないので、分岐が増えず、同じコードという条件が保たれます。
- 30秒で終わります。 画面の左上に得点と残り時間が出て、終了後は「平均ずれ」が出ます。これは、毎フレームの「最も低い光」と受け皿の横方向の距離の平均です。値が小さいほど、受け皿が光の真下に近い位置にいたことを表します。
手順
1. 一度だけ動作を確かめる
TOUCH_VALUE を 1 にしたまま index.html をブラウザで開き、左右キーで受け皿が動くことを確認します。30秒後に「平均ずれ」が表示されれば準備完了です。ここでのプレイは記録に含めません。操作に慣れるための練習です。
2. 二つのモードを同じ回数ずつ遊ぶ
モードAを TOUCH_VALUE = 1(受け止める)、モードBを TOUCH_VALUE = -1(避ける)とします。それぞれ5回、合計10回遊びます。順番は慣れの影響を打ち消すため、次のように入れ替えます。
A B B A A B B A A B
値を書き換えたら、ファイルを保存してブラウザを再読み込みします。再読み込みを忘れると、前のモードのまま遊んでしまいます。
3. 毎回、遊び終えた直後に記録する
画面の数値を書き写し、続けて一言メモを書きます。メモは記憶が新しいうちに書きます。10回分をまとめて後から思い出すと、感想が平均化されてしまいます。
4. 5回ずつそろったら一度止める
結果を読む前に、記録の欠けがないか確認します。ここまでは解釈をしません。
記録の取り方
次の表の形で記録します。
- 1、モード:A、得点:、平均ずれ(px):、一言メモ:
- 2、モード:B、得点:、平均ずれ(px):、一言メモ:
一言メモは自由記述ですが、書く観点を先にそろえておくと比べやすくなります。次の三つのうち、当てはまるものを書きます。
- 視線がどこにあったか(落ちてくる光、受け皿、画面全体)
- 受け皿をどの位置に置こうとしていたか(光の真下、光から離れた場所、中央など)
- 一番あわてた場面はどこか
「面白かった」「難しかった」だけの感想は、判断の材料になりにくいので避けます。
記録の単位は、得点が整数、平均ずれが画面上のピクセル値です。10回遊んだ記録を、モードごとに並べて見られるようにします。
結果の読み方と誤りやすい点
読み方は、事前に決めた条件に照らして整理します。次の表は、判断の目安です。
- 平均ずれがモード間で近く、メモの内容も似ている、読み取れること:操作の質が変わっていない可能性があります、次の判断:設定値だけでは別の遊びになっていないと考え、別の実験で変数を足すかを検討します
- 平均ずれに違いがあり、メモにも違う動きが書かれている、読み取れること:動き方が分かれた手がかりになります、次の判断:回数を増やして再現するかを確かめます
- 平均ずれには違いがあるが、メモは似ている、読み取れること:数値の違いと感覚の違いがずれています、次の判断:指標が実態を表しているかを疑います
- 片方のモードで受け皿がほとんど動かない、読み取れること:動かずに済む戦略に収束している可能性があります、次の判断:遊びとして成立しているかを別の観点で見直します
表の行を機械的に当てはめるのではなく、あくまで次に何を確かめるかを決める材料として使ってください。5回ずつの記録では、断定できる範囲に限りがあります。
起こりやすい誤りを挙げます。
- スコアの大小で比較してしまう。 先に述べたとおり、得点は符号が逆になるだけの構造です。得点の高低は、遊びが分かれた証拠にはなりません。
- TOUCH_VALUE 以外も触ってしまう。 速度や落下間隔を同時に変えると、どの変更が効いたのかわからなくなります。変えるのは一つだけです。
- 「平均ずれ」を過信する。 この指標は「最も低い光」だけを見ています。避けるモードでは、プレイヤーは複数の光を見ながら動くかもしれません。指標が遊びの実態を取りこぼしていないかは、メモと突き合わせて確認します。
- 固定した乱数の列に慣れてしまう。 同じ順番で光が落ちるので、回数を重ねると位置を覚える可能性があります。ABBAの入れ替え順は、その影響をモード間で均すための工夫です。それでも不安なら、seed の値を変えて、別の列で再度確かめます。
- 入力装置が混ざる。 コードはマウスの移動でも受け皿が動く作りです。キーボードで遊んでいる途中にマウスが動くと、位置が飛びます。キーボードに固定すると決めたら、マウスは触らないようにします。
- フレームレートの違い。 動きは requestAnimationFrame に合わせて進む作りです。画面のリフレッシュレートが高い環境では、速く進む場合があります。同じ環境で最後まで通して記録します。
次の行動
まず index.html を保存し、TOUCH_VALUE の 1 と -1 を切り替えて、ABBAの順で10回遊んでください。記録がそろったら、先に決めた基準に照らして、遊びが分かれたかを判断します。分かれたと感じた場合は、HTMLを一つのファイルにまとめたまま、アソバースの投稿画面にアップロードして試せます。直下の index.html が入口になるので、ZIPにする場合もこの名前にします。

