【ゲーム】JavaScript:69 カラー順クリックゲーム

 「カラー順クリックゲーム」は、画面に表示されるカラーボタンを指示どおりの順番でクリックしていく反射神経+記憶力チャレンジゲームです。
 最初は3色からスタートし、正解ごとに色が1つずつ増えていき、最大10色に達すると完全クリア。1回でも間違えるとゲームオーバーとなり、クリアタイムのランキングも残せます。

遊び方・操作方法

  1. タイトル画面の「スタート」ボタンをクリック(または Enter/スペースキー)
  2. ゲーム画面で、画面上部に並ぶカラーボタンを「次にクリックすべき色」の順番どおりにクリック
  3. すべて正解すると色数が1増え、再びクリックチャレンジ
  4. 色数が10に達するとクリア、タイムを登録してランキング表示
  5. いずれかで間違えるとゲームオーバー、クリアできた段階までの色数と経過時間が表示される。

ルール

  • 制限時間は なし(ただしクリアタイムを計測)
  • クリック操作はマウス/タップ/キーボード(Enter/スペース)対応
  • 一度でも誤った色をクリックすると ゲームオーバー
  • すべて正解し色数10色を達成すると 完全クリア
  • クリアタイム上位3位までが ローカルストレージ に保存され、次回以降タイトル画面で参照可能

🎮ゲームプレイ

以下のリンク先から実際にプレイできます。

69 カラー順クリックゲーム

素材のダウンロード

以下のリンクから使用する素材をダウンロードできます。

color_order_click_title.pngcolor_order_click_bg.png

ゲーム画面イメージ

プログラム全文(color_order_click.html)

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>🟥🟩🟦 カラー順クリックゲーム 🟦🟩🟥</title>
  <style>
    body {
      background: url('color_order_click_bg.png') no-repeat center center fixed;
      background-size: cover;
      margin: 0;
      font-family: 'Segoe UI', 'Yu Gothic', 'Meiryo', sans-serif;
      overflow-x: hidden;
    }
    .center-box {
      width: 1000px;
      margin: 36px auto;
      background: rgba(255,255,255,0.93);
      border-radius: 20px;
      box-shadow: 0 4px 24px rgba(0,0,0,0.13);
      padding: 32px 24px 30px 24px;
      text-align: center;
      position: relative;
      min-height: 440px;
    }
    .title-img {
      display: block;
      margin: 0 auto 18px auto;
      max-width: 420px;
      height: auto;
    }
    h1 {
      font-size: 2.2rem;
      margin: 0 0 16px 0;
      text-align: center;
      letter-spacing: 2px;
    }
    h2 {
      font-size: 1.3rem;
      margin: 18px 0 6px 0;
      text-align: center;
      color: #1e3a5a;
    }
    .desc {
      text-align: left;
      margin: 0 auto 12px auto;
      max-width: 600px;
      color: #222;
      line-height: 1.7;
      background: rgba(240,240,240,0.82);
      padding: 10px 18px;
      border-radius: 10px;
    }
    .start-btn, .return-btn {
      margin: 26px auto 0 auto;
      display: block;
      font-size: 1.22rem;
      padding: 12px 40px;
      background: linear-gradient(90deg, #32cd32 50%, #5dade2 100%);
      color: #fff;
      border: none;
      border-radius: 32px;
      box-shadow: 0 2px 6px rgba(44,44,44,0.13);
      cursor: pointer;
      font-weight: bold;
      transition: background 0.2s, transform 0.1s;
    }
    .start-btn:hover, .return-btn:hover {
      background: linear-gradient(90deg, #5dade2 40%, #32cd32 100%);
      transform: scale(1.05);
    }
    .color-area {
      margin: 40px 0 20px 0;
      display: flex;
      flex-wrap: wrap;
      justify-content: center;
      gap: 38px 38px;
      min-height: 120px;
    }
    .color-btn {
      width: 120px; height: 120px;
      border: 4px solid #fff;
      border-radius: 22px;
      font-size: 2.9rem;
      cursor: pointer;
      box-shadow: 0 3px 12px rgba(0,0,0,0.15);
      margin: 0 8px;
      transition: transform 0.08s;
      outline: none;
      user-select: none;
      display: flex;
      flex-direction: column;
      justify-content: center;
      align-items: center;
    }
    .color-btn:active {
      transform: scale(0.93);
      box-shadow: 0 0 6px #666;
    }
    .color-label {
      font-size: 1.06rem;
      line-height: 1;
      font-weight: bold;
      margin-top: 3px;
      letter-spacing: 2px;
      color: #fff;
      text-shadow: 1px 1px 3px #111, 0 0 5px #000;
    }
    .color-red { background: #ef5757; }
    .color-green { background: #31c25b; }
    .color-yellow { background: #f9d423; color: #444;}
    .color-blue { background: #357efd; }
    .color-purple { background: #9b59b6; }
    .color-orange { background: #ff9900; }
    .color-brown { background: #a0522d; }
    .color-pink { background: #ff5fa2; }
    .color-cyan { background: #29e3e3; color: #222;}
    .color-navy { background: #2242a8; }
    .color-lime { background: #b8e986; color: #333;}
    .color-gray { background: #cccccc; color: #222;}
    .info-box {
      background: rgba(50,50,50,0.85);
      color: #fff;
      font-size: 1.18rem;
      padding: 12px 22px;
      border-radius: 14px;
      margin: 0 auto 20px auto;
      display: inline-block;
      min-width: 280px;
      text-align: center;
      box-shadow: 0 2px 8px rgba(60,60,60,0.11);
    }
    .result-msg {
      font-size: 1.75rem;
      margin: 38px 0 18px 0;
      text-align: center;
      font-weight: bold;
      color: #d81e3f;
      background: #fff9;
      border-radius: 12px;
      padding: 20px 6px;
      box-shadow: 0 2px 16px rgba(0,0,0,0.12);
    }
    .ranking-box {
      margin: 24px auto 0 auto;
      background: #eaf6f3e0;
      color: #272828;
      border-radius: 12px;
      padding: 16px 20px 12px 20px;
      max-width: 360px;
      box-shadow: 0 0 9px #66c7b0b8;
    }
    .ranking-title {
      font-size: 1.16rem;
      font-weight: bold;
      margin-bottom: 4px;
      color: #19896d;
      letter-spacing: 1.5px;
    }
    .ranking-list {
      text-align: left;
      font-size: 1.08rem;
      margin: 6px 0 0 0;
      padding-left: 0;
      list-style: none;
    }
    .ranking-list li {
      padding: 2px 0;
      display: flex;
      gap: 0.7em;
      align-items: center;
    }
    @media (max-width: 1100px) {
      .center-box { width: 98vw; min-width: 0; }
    }
  </style>
</head>
<body>
  <div class="center-box" id="main">
    <!-- タイトル/ゲーム/終了画面がここに -->
  </div>
  <script>
    // ===== 色データ(最大12色まで用意。最大10色まで出題) =====
    const colorList = [
      {name: '赤', code: 'red', class: 'color-red', emoji: '🟥'},
      {name: '緑', code: 'green', class: 'color-green', emoji: '🟩'},
      {name: '黄', code: 'yellow', class: 'color-yellow', emoji: '🟨'},
      {name: '青', code: 'blue', class: 'color-blue', emoji: '🟦'},
      {name: '紫', code: 'purple', class: 'color-purple', emoji: '🟪'},
      {name: 'オレンジ', code: 'orange', class: 'color-orange', emoji: '🟧'},
      {name: '茶', code: 'brown', class: 'color-brown', emoji: '⬛'}, // 茶色の絵文字は無いので⬛
      {name: 'ピンク', code: 'pink', class: 'color-pink', emoji: '🩷'},
      {name: 'シアン', code: 'cyan', class: 'color-cyan', emoji: '🟦'}, // シアンも🟦で代用
      {name: '紺', code: 'navy', class: 'color-navy', emoji: '🟦'},
      {name: 'ライム', code: 'lime', class: 'color-lime', emoji: '🟩'},
      {name: '灰', code: 'gray', class: 'color-gray', emoji: '⬜'}
    ];

    // ==== 状態管理 ====
    let gameOrder = [];
    let clickIndex = 0;
    let playing = false;
    let colorCount = 3;
    let startTime = 0;
    let endTime = 0;
    let ranking = [];
    const CLEAR_COLOR = 10; // 10色でクリア

    // ==== ランキングをローカルストレージから取得 ====
    function loadRanking() {
      ranking = JSON.parse(localStorage.getItem('color_order_ranking_10') || '[]');
    }
    function saveRanking() {
      localStorage.setItem('color_order_ranking_10', JSON.stringify(ranking));
    }
    // ==== 時間(ms)を「秒.小数2桁」形式に ====
    function formatTime(ms) {
      return (ms/1000).toFixed(2) + ' 秒';
    }
    // ==== 配列シャッフル ====
    function shuffle(arr) {
      let a = arr.slice();
      for (let i = a.length - 1; i > 0; i--) {
        let j = Math.floor(Math.random() * (i + 1));
        [a[i], a[j]] = [a[j], a[i]];
      }
      return a;
    }

    // ==== タイトル画面表示 ====
    function showTitle() {
      playing = false;
      colorCount = 3;
      loadRanking();
      document.getElementById('main').innerHTML = `
        <img src="color_order_click_title.png" class="title-img" alt="タイトル画像">
        <h1>🟥🟩🟦 カラー順クリックゲーム 🟦🟩🟥</h1>
        <h2>🎲 ルール説明 🎲</h2>
        <div class="desc">
          ・画面に表示された色のボタンを、<br>
          <b>下の指示どおりの順番でクリック</b>してください。<br>
          ・正解すると色が1つずつ増え、<b>10色</b>までクリアすると完全制覇です!<br>
          ・<b>1回でも間違える</b>とゲームオーバーです。<br>
          ・クリアまでの<b>タイムランキング</b>が残ります。<br>
          カラフルなボタンを素早く正確に押せるか、チャレンジしてみよう!
        </div>
        <button class="start-btn" onclick="startGame()">スタート</button>
        ${showRankingHTML()}
      `;
    }

    // ==== ランキング表示用HTML生成 ====
    function showRankingHTML() {
      if (!ranking.length) return '';
      let html = `<div class="ranking-box"><div class="ranking-title">🏆 ランキング(最速タイム) 🏆</div>
        <ol class="ranking-list">`;
      ranking.slice(0, 3).forEach((r, i) => {
        html += `<li> ${['🥇','🥈','🥉'][i]||'🏅'} <span>${formatTime(r.time)}</span> <span style="font-size:0.92em; color:#4a7;">(${r.date})</span></li>`;
      });
      html += '</ol></div>';
      return html;
    }

    // ==== ゲーム開始 ====
    function startGame() {
      colorCount = 3;
      gameOrder = shuffle(colorList).slice(0, colorCount);
      clickIndex = 0;
      playing = true;
      startTime = Date.now();
      showGameScreen();
    }

    // ==== ゲーム画面表示 ====
    function showGameScreen() {
      // パネル配置:順不同
      let panelColors = shuffle(gameOrder);
      let buttons = panelColors.map(color =>
        `<button class="color-btn ${color.class}" onclick="clickColor('${color.code}')">
          <span>${color.emoji}</span>
          <span class="color-label">${color.name}</span>
        </button>`
      ).join('');
      let nextColor = gameOrder[clickIndex];
      document.getElementById('main').innerHTML = `
        <h1>🟥🟩🟦 カラー順クリックゲーム 🟦🟩🟥</h1>
        <div class="color-area">${buttons}</div>
        <div class="info-box">
          次にクリックする色:<b style="font-size:1.2em">${nextColor.emoji} ${nextColor.name}</b><br>
          (${clickIndex+1} / ${gameOrder.length})
        </div>
        <div style="margin-top:20px; color:#555;">色の数:<b>${colorCount}</b></div>
      `;
    }

    // ==== 色クリック処理 ====
    function clickColor(code) {
      if (!playing) return;
      let correct = gameOrder[clickIndex].code;
      if (code === correct) {
        clickIndex++;
        if (clickIndex >= gameOrder.length) {
          // クリア:色増やす or ゲーム全クリ
          if (colorCount < CLEAR_COLOR) {
            colorCount++;
            // 次の色セットへ
            setTimeout(() => {
              gameOrder = shuffle(colorList).slice(0, colorCount);
              clickIndex = 0;
              showGameScreen();
            }, 350); // 短いインターバル
          } else {
            // 10色クリア(完全クリア)
            endTime = Date.now();
            let clearTime = endTime - startTime;
            updateRanking(clearTime);
            showResult(true, clearTime);
          }
        } else {
          showGameScreen();
        }
      } else {
        // ミス
        playing = false;
        endTime = Date.now();
        let clearTime = endTime - startTime;
        showResult(false, clearTime);
      }
    }

    // ==== ランキング更新 ====
    function updateRanking(time) {
      let d = new Date();
      let stamp = `${d.getFullYear()}/${String(d.getMonth()+1).padStart(2,'0')}/${String(d.getDate()).padStart(2,'0')} ${String(d.getHours()).padStart(2,'0')}:${String(d.getMinutes()).padStart(2,'0')}`;
      ranking.push({time: time, date: stamp});
      // 早い順に上位3件を保存
      ranking.sort((a,b)=>a.time-b.time);
      ranking = ranking.slice(0, 3);
      saveRanking();
    }

    // ==== 結果画面 ====
    function showResult(clear, clearTime) {
      playing = false;
      let msg = clear
        ? `🎉 おめでとう!全${colorCount}色クリア! 🎉<br>タイム:<b style="color:#17c;">${formatTime(clearTime)}</b>`
        : `💥 残念!${colorCount-1}色までクリア<br>タイム:<b style="color:#c41;">${formatTime(clearTime)}</b>`;
      let rankHtml = clear ? showRankingHTML() : '';
      document.getElementById('main').innerHTML = `
        <h1>🟥🟩🟦 カラー順クリックゲーム 🟦🟩🟥</h1>
        <div class="result-msg">${msg}</div>
        ${rankHtml}
        <button class="return-btn" onclick="showTitle()">タイトル画面に戻る</button>
      `;
    }

    // ==== 初期表示 ====
    window.onload = showTitle;

    // ==== キーボード操作(Enterでスタート・戻る) ====
    document.addEventListener('keydown', function(e) {
      if (!playing && (e.key === "Enter" || e.key === " ")) {
        if (document.querySelector('.start-btn')) startGame();
        if (document.querySelector('.return-btn')) showTitle();
      }
    });
  </script>
</body>
</html>

アルゴリズムの流れ

ステップ内容
1. showTitle()ランキング読み込み→タイトル画面を描画
2. startGame()色数を3に初期化→シャッフル&選択→タイマー開始→ゲーム画面へ
3. shuffle(arr)Fisher–Yates法で配列をランダムに並び替え
4. showGameScreen()指定数の色パネルをシャッフルして描画→次にクリックすべき色を表示
5. clickColor(code)押された色を判定:正解なら次へ/全クリア or 色数増加→次ステージ、誤りならゲームオーバー
6. updateRanking(time)記録を日時付きで配列に追加→ソート→上位3位をlocalStorageに保存
7. showResult(clear, t)結果画面描画:クリア or ミスでメッセージ分岐+ランキング表示

関数の解説

関数名役割
loadRanking()localStorage から過去のランキング配列を取得
saveRanking()localStorage にランキング配列を保存
formatTime(ms)ミリ秒→「秒.小数2桁 秒」形式の文字列にフォーマット
shuffle(arr)配列をシャッフルして新しい配列を返す(Fisher–Yatesアルゴリズム)
updateRanking(time)ランキングへ新記録追加→ソート→上位3件に絞って保存
clickColor(code)押された色をチェックし、正誤に応じてステージ進行 or 終了

改造のポイント

  • 色数や種類の拡張
    colorList に新色を追加し、CLEAR_COLOR を調整すれば、より多様なパターンで遊べます。
  • タイマー制限
    制限時間を設けたい場合は setInterval で残り時間をカウントダウンし、時間切れ判定を追加。
  • レベル機能
    ステージごとに色数以外にも制限時間やミス許容回数を変化させると、さらなる難易度設定が可能です。
  • モバイル最適化
    CSSのタッチサイズやレスポンシブを強化し、スマホでも操作しやすく改良しましょう。

ぜひ上記を参考に、ご自身のオリジナル要素をプラスしてみてください!