マガジン

背景を一枚変えるだけで難易度は変わるか:見つけにくさの実験

遊びをつくる

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

速さ、選択肢、ミスの許容を三つの異なる仕掛けで表したゲーム模型のイラスト。
記事のテーマをもとに制作したAI生成イラスト。

動く敵をよけるゲームで、背景を無地から森の模様に差し替えた場面を考えてみます。差し替えた途端に、テストプレイの人が敵を見落とすようになりました。これは「難易度が上がった」のでしょうか。それとも、操作や判断の難しさは変わらず、画面が見づらくなっただけなのでしょうか。 この二つは、見分けないと対処が逆になります。敵の速度を落としても見落としは減らないかもしれません。背景の模様を薄くしても、模様に紛れた敵を探す緊張感が失われるだけかもしれません。そこで、背景の模様だけを変えて、動く標的を見つけるまでの時間がどう動くかを測ります。 この記事は、その実験の設計書です。結果は書きません。単独で動く計測ページのコードと、記録の取り方、結果の読み方、誤りやすい点を順に示します。読み終えたら、自分の画面で答えを出せる形にしています。

この記事の目次
  1. 問いを測れる形にする
  2. 準備するもの:統制する要素と変える要素
  3. 手順:計測ページを作って動かす
  4. 記録の取り方
  5. 結果の読み方
  6. 誤りやすい点
  7. 次の行動

問いを測れる形にする

「見つけにくい」という感覚は、そのままでは測れません。まず、観察できる数字に置き換えます。

  • 反応時間:標的が現れてから、プレイヤーが標的をクリック(タップ)するまでのミリ秒です。
  • 見逃し:制限時間内に標的をクリックできなかった試行の数です。
  • 誤クリック:標的ではない場所を押した回数です。

問いは次のように絞ります。「標的の色・大きさ・速度を固定したまま、背景の模様だけを4種類に変えると、反応時間・見逃し・誤クリックはどう変わるか」です。変える要素は背景の模様の1点だけにします。

背景は次の4種類にします。

  1. 無地(基準にする条件です)
  2. 細かい縞(周期8ピクセル)
  3. 大きな市松(1マス40ピクセル)
  4. まばらなドット(3ピクセル四方の点)

標的は半径10ピクセル、直径20ピクセルの円です。縞の周期は標的より小さく、市松の1マスは標的より大きくなります。つまり、模様の大きさと標的の大きさの関係が条件ごとに違います。「標的と同じくらいの大きさの模様ほど紛れやすいのでは」といった仮説は、この実験で確かめられます。ただし仮説は仮説にとどめ、数字を見てから判断します。

準備するもの:統制する要素と変える要素

必要なのは、ブラウザと表計算ソフト(またはメモ帳)だけです。変える要素は背景の模様1つで、それ以外は固定します。

  • 変える、項目:背景の模様、固定のしかた:4種類を試行ごとにランダムに入れ替えます
  • 固定、項目:標的の色・大きさ・速度、固定のしかた:コードの定数のままにします
  • 固定、項目:出現位置の範囲、固定のしかた:画面の端を除いた一定範囲でランダムにします
  • 固定、項目:画面の大きさ・明るさ、固定のしかた:実験中はブラウザの拡大率とディスプレイ設定を変えません
  • 固定、項目:使う機器、固定のしかた:同じ端末・同じ入力方法(マウスなら最後までマウス)にします

もう一つ、見落としやすい固定項目があります。背景のベース色と模様の色の差です。この計測ページでは、ベースが #8a9a8a、模様が #7a8a7a で、差は小さくしてあります。標的の #d9822b とは色相がはっきり違います。模様の色を濃くすると、模様そのものが目立つので、「模様の種類」ではなく「コントラストの強さ」を測ってしまいます。色を変えたいときは、1回の実験で1か所だけにします。

手順:計測ページを作って動かす

次のコードを test.html という名前で保存し、ブラウザで開きます。4種類の背景を20回ずつ、計80試行を、順番をランダムに混ぜて出題します。標的は出現してから横に動き、端で跳ね返ります。80試行が終わると、結果がCSV形式(カンマ区切り)で画面下に表示されます。

html
<canvas id="c" width="480" height="320"></canvas>
<pre id="o"></pre>
<script>
const c=document.getElementById("c"),g=c.getContext("2d");
const BG=["無地","縞","市松","ドット"],N=20,log=[],order=[];
let t=0,tg=null,start=0,miss=0,last=0;
for(let i=0;i<N;i++)for(let b=0;b<4;b++)order.push(b);
for(let i=order.length-1;i>0;i--){const j=Math.floor(Math.random()*(i+1));[order[i],order[j]]=[order[j],order[i]];}
function bg(k){
  g.fillStyle="#8a9a8a";g.fillRect(0,0,480,320);g.fillStyle="#7a8a7a";
  if(k==1)for(let x=0;x<480;x+=8)g.fillRect(x,0,4,320);
  if(k==2)for(let x=0;x<480;x+=40)for(let y=0;y<320;y+=40)if((x+y)%80==0)g.fillRect(x,y,40,40);
  if(k==3)for(let i=0;i<900;i++)g.fillRect((i*97)%480,(i*53)%320,3,3);
}
function next(){
  if(t>=order.length){o.textContent="条件,反応ms,誤クリック\n"+log.map(r=>r.join(",")).join("\n");return;}
  tg=null;miss=0;
  setTimeout(()=>{tg={x:60+Math.random()*360,y:40+Math.random()*240,vx:Math.random()<.5?80:-80};start=performance.now();},800+Math.random()*1000);
}
function finish(ms){
  log.push([BG[order[t]],ms===null?"":Math.round(ms),miss]);tg=null;t++;next();
}
function draw(now){
  if(t>=order.length)return;
  const dt=(now-last)/1000;last=now;bg(order[t]);
  if(tg){
    tg.x+=tg.vx*dt;if(tg.x<20||tg.x>460)tg.vx*=-1;
    g.fillStyle="#d9822b";g.beginPath();g.arc(tg.x,tg.y,10,0,7);g.fill();
    if(performance.now()-start>4000)finish(null);
  }
  requestAnimationFrame(draw);
}
c.onclick=e=>{
  if(!tg)return;
  const r=c.getBoundingClientRect(),x=(e.clientX-r.left)*480/r.width,y=(e.clientY-r.top)*320/r.height;
  if(Math.hypot(x-tg.x,y-tg.y)<=20)finish(performance.now()-start);else miss++;
};
next();requestAnimationFrame(draw);
</script>

実施の流れは次のとおりです。

  1. 標的が出る前の0.8〜1.8秒は、背景だけが表示されます。この待ち時間はランダムなので、出現のタイミングを予測できません。
  2. 標的が現れたら、できるだけ早くクリックします。標的の中心から20ピクセル以内が命中です。
  3. 4秒以内に当てられなければ、見逃しとして記録され、次の試行へ進みます。
  4. 最初の10試行ほどは操作に慣れるための期間なので、分析から外します。その旨を、記録表に「練習」と書いて区別しておきます。
  5. 80試行を一度に続けると疲れます。途中で休みたい場合は、ページを閉じずに休めるよう、実験の前に水分や休憩の時間を決めておきます。

記録の取り方

画面下に出たCSVをコピーして、表計算ソフトに貼り付けます。各行が1試行です。「条件」の列で並べ替えると、条件ごとの20行が並びます。反応msの列が空欄の行は、見逃しです。

記録するのは次の項目です。

  • 条件ごとの反応時間の中央値(平均値ではありません。たまたま気を抜いた1回の長い反応が平均を引き上げるので、中央値のほうが安定します)
  • 条件ごとの見逃し数(20試行のうち何回か)
  • 条件ごとの誤クリック数の合計
  • 条件ごとの反応時間の最小値と最大値(散らばりを見るために使います)

実験は、日を変えて少なくとも2回行います。1回だけの結果では、その日の体調や集中力の影響を切り分けられません。同じ向きの差が2回とも出るかどうかが、信頼できるかどうかの目安になります。

自分以外の人に頼む場合は、人ごとに別の表を作り、その人の中で条件を比べます。人の反応の速さには個人差があるので、人をまたいで平均すると、差が見えにくくなります。

結果の読み方

数字が出たら、次の順で読みます。

まず、基準の「無地」の20試行が、どれくらい散らばっているかを見ます。無地だけでも、反応時間は毎回ある程度ぶれます。ほかの条件の中央値の差が、無地の散らばりの幅の中に収まっているなら、「差がある」とは言えません。

次に、反応時間・見逃し・誤クリックの組み合わせで、何が起きているかを読みます。

  • 反応時間が長く、見逃しも多い、読み方の候補:標的が模様に埋もれて、探すのに時間がかかっています。「見つけにくさ」が難易度として効いている可能性があります
  • 反応時間は長いが、見逃しは変わらない、読み方の候補:時間はかかりますが、最終的には見つかっています。制限時間が短いゲームでは難易度に響き、長いゲームでは影響が小さいと考えられます
  • 反応時間は変わらず、誤クリックが多い、読み方の候補:標的は見つけていますが、模様の一部を標的と取り違えています。見やすさというより、紛らわしさの問題です
  • どの指標にも差がない、読み方の候補:この模様の大きさ・色・標的の速度では、差が出ませんでした。標的を小さくする、色の差を縮めるなど、別の条件で再実験できます

ここで大切なのは、「見つけにくい」と「難しくて面白い」が別物だという点です。見つけにくさは、プレイヤーの腕では解決できない要素です。探しても見つからず、攻略の工夫の余地がなければ、それは難易度というより理不尽さとして受け取られやすくなります。差が出た条件は、「採用する」「採用しない」の二択ではなく、標的の色を少し濃くするなど、見つけやすさの調整つまみを足す手がかりとして使えます。

誤りやすい点

結果をゆがめる原因を、あらかじめ並べておきます。

  • 模様の被覆率の違い:縞と市松は面積のおよそ半分が模様で、ドットはまばらです。被覆率が違う分、模様の大きさや形と別の要素が混ざっています。厳密に比べたいときは、ドットの数を増やして被覆率をそろえます。
  • 模様の平均色の違い:模様の色は背景より少し暗いので、模様が多い条件ほど、画面全体の見た目の明るさがわずかに変わります。標的との局所的なコントラストも変わります。
  • 練習効果:80試行を繰り返すと、慣れて全体に速くなります。条件の順序をランダムにしてあるのは、この影響が特定の条件に偏らないようにするためです。順序を固定する改造はしないでください。
  • 機器と入力の違い:スマートフォンのタップと、マウスのクリックでは、反応にかかる時間が違います。実験の途中で機器を変えると、条件の差ではなく機器の差が混ざります。
  • 表示までの遅れ:計測ページが測るのは、標的を描画した時点から入力までの時間で、画面表示や入力機器の遅れは含まれていません。絶対値は少し大きめに出ます。ただし、遅れは全条件に共通なので、条件間の比較は成り立ちます。
  • 画面の拡大・縮小:ブラウザの拡大率を変えると、標的や模様の見かけの大きさが変わります。途中で変えないでください。
  • 色の見え方の個人差:色の見分けやすさは人によって異なります。自分の結果を、すべてのプレイヤーに一般化しないでください。

次の行動

自作ゲームの背景を一枚だけ別の模様に差し替え、そのまま同じ手順で計測ページの標的を自分のゲームの敵の色と大きさに置き換えて確かめてみてください。差が出た条件は、見つけにくさを意図した演出として残すか、色を調整して見やすくするかを選べます。まずは2回、日を変えて測り、同じ向きの差が出るかどうかを確認するところから始めます。