【ゲーム】JavaScript:26 記憶チャレンジ

 「記憶チャレンジ」は、シンプルな「シモン・セイモア」タイプの記憶力ゲームです。4色のパッドがランダムに光るシーケンスを見て、その順番どおりに自分でタップします。レベルが上がるごとにシーケンス長が1つずつ増え、どこまで記憶できるかを競います。

遊び方と操作方法

  1. タイトル画面の「スタート 🚀」ボタンをクリック
  2. カラーパッドが順番に光る(シーケンス再生)
  3. 再生終了後に「順番にタップしてください」のメッセージが表示されたら、表示されたとおりにパッドをタップ
  4. 正しくタップできればレベルアップして次の長いシーケンスへ
  5. いずれかでミスするとゲームオーバー

ルール

  • レベル1からスタートし、最初は1色光るシーケンス
  • 毎ラウンド、前のシーケンスに「1色を追加」して再生
  • 光った順序どおりにすべてタップできればクリア
  • どこかで間違えると即ゲームオーバー
  • クリアした最高レベルがスコア

🎮ゲームプレイ

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

26 記憶チャレンジ

素材のダウンロード

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

memory_challenge_title.pngmemory_challenge_bg.png

ゲーム画面イメージ

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

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>🧠 記憶チャレンジ 🧠</title>
  <style>
    /* ===== 全体背景設定 ===== */
    body {
      margin: 0;
      padding: 0;
      font-family: 'Arial', sans-serif;
      background: url('memory_challenge_bg.png') no-repeat center center fixed;
      background-size: cover;
    }
    /* ===== 中央オーバーレイ共通スタイル ===== */
    .overlay {
      position: absolute;
      top: 50%; left: 50%;
      transform: translate(-50%, -50%);
      background-color: rgba(255, 255, 255, 0.9);
      padding: 20px;
      border-radius: 10px;
      text-align: center;
      width: 90%; max-width: 500px;
    }
    /* ===== 非表示クラス ===== */
    .hidden { display: none; }
    /* ===== タイトル画像 ===== */
    .title-image {
      display: block;
      margin: 0 auto 10px;
      max-width: 80%; height: auto;
    }
    /* ===== 汎用ボタン ===== */
    .btn {
      display: inline-block;
      padding: 12px 24px;
      font-size: 18px;
      font-weight: bold;
      margin: 15px 5px 0;
      cursor: pointer;
      border: 2px solid #e0a800;
      border-radius: 8px;
      background-color: #ffc107;
      color: #000;
      box-shadow: 0 4px 6px rgba(0,0,0,0.2);
      transition: background-color 0.2s, transform 0.1s;
    }
    .btn:hover { background-color: #e0a800; transform: translateY(-2px); }
    .btn:active { transform: translateY(0); box-shadow: 0 2px 4px rgba(0,0,0,0.2); }
    /* ===== ゲームパッド ===== */
    #pad-container {
      display: grid;
      grid-template-columns: repeat(2, 1fr);
      gap: 10px;
      margin: 20px auto;
      width: 300px;
      height: 300px;
    }
    .pad {
      width: 100%; height: 100%;
      border-radius: 10px;
      cursor: pointer;
      opacity: 0.4; /* 非アクティブ時を暗く */
      transition: opacity 0.1s, transform 0.1s, filter 0.1s, box-shadow 0.1s;
    }
    .pad.red    { background-color: #e74c3c; }
    .pad.green  { background-color: #2ecc71; }
    .pad.blue   { background-color: #3498db; }
    .pad.yellow { background-color: #f1c40f; }
    /* はっきり光る状態 */
    .pad.active {
      opacity: 1; /* 明暗差を強調 */
      transform: scale(1.15);
      filter: brightness(250%);
      box-shadow: 0 0 30px rgba(255,255,255,0.9), 0 0 60px rgba(255,255,255,0.7);
    }
    /* ===== メッセージ ===== */
    .message {
      margin-top: 15px;
      padding: 10px;
      background-color: rgba(0,0,0,0.7);
      color: #fff;
      border-radius: 5px;
      min-height: 1.5em;
    }
  </style>
</head>
<body>
  <!-- タイトル画面 -->
  <div id="title-screen" class="overlay">
    <img src="memory_challenge_title.png" alt="記憶チャレンジタイトル" class="title-image">
    <h1>🧠 記憶チャレンジ 🧠</h1>
    <p>光るパッドの順番を記憶して、同じ順序でタップしてください。</p>
    <p>レベルが上がるごとにパターンが長くなります。</p>
    <button id="start-btn" class="btn">スタート 🚀</button>
  </div>

  <!-- ゲーム画面 -->
  <div id="game-screen" class="overlay hidden">
    <h2>レベル: <span id="level-display">1</span></h2>
    <!-- ゲームパッド4色 -->
    <div id="pad-container">
      <div class="pad red"    data-color="red"></div>
      <div class="pad green"  data-color="green"></div>
      <div class="pad blue"   data-color="blue"></div>
      <div class="pad yellow" data-color="yellow"></div>
    </div>
    <!-- プレイヤー案内メッセージ -->
    <div id="message" class="message">準備中…</div>
  </div>

  <!-- 終了画面 -->
  <div id="end-screen" class="overlay hidden">
    <h2>ゲームオーバー 💥</h2>
    <p id="final-message">レベル <span id="final-level">1</span> で終了しました。</p>
    <button id="restart-btn" class="btn">タイトルに戻る 🔄</button>
  </div>

  <script>
    // パッドの色リスト
    const COLORS = ['red','green','blue','yellow'];
    // ゲーム状態変数
    let sequence = [];    // システム生成シーケンス
    let playerIdx = 0;    // プレイヤー入力位置
    let level = 1;        // 現在のレベル
    let playing = false;  // 入力受付中フラグ

    // DOM要素取得
    const titleScreen = document.getElementById('title-screen');
    const gameScreen  = document.getElementById('game-screen');
    const endScreen   = document.getElementById('end-screen');
    const startBtn    = document.getElementById('start-btn');
    const restartBtn  = document.getElementById('restart-btn');
    const pads        = document.querySelectorAll('.pad');
    const msgDiv      = document.getElementById('message');
    const levelDisp   = document.getElementById('level-display');
    const finalLevel  = document.getElementById('final-level');

    /** タイトル画面表示 */
    function showTitle() {
      titleScreen.classList.remove('hidden');
      gameScreen.classList.add('hidden');
      endScreen.classList.add('hidden');
    }
    /** ゲーム開始 */
    function startGame() {
      sequence = [];
      level = 1;
      levelDisp.textContent = level;
      titleScreen.classList.add('hidden');
      endScreen.classList.add('hidden');
      gameScreen.classList.remove('hidden');
      nextRound();
    }
    /** 次のラウンド:シーケンスに色追加&再生 */
    function nextRound() {
      msgDiv.textContent = 'シーケンス再生中…';
      playing = false;
      sequence.push(COLORS[Math.floor(Math.random()*COLORS.length)]);
      let idx = 0;
      const interval = setInterval(() => {
        lightPad(sequence[idx]);
        idx++;
        if(idx >= sequence.length) {
          clearInterval(interval);
          setTimeout(() => { playerIdx = 0; playing = true; msgDiv.textContent = '順番にタップしてください'; }, 600);
        }
      }, 1200);
    }
    /** パッドを一瞬光らせる */
    function lightPad(color) {
      const pad = document.querySelector(`.pad.${color}`);
      pad.classList.add('active');
      setTimeout(() => pad.classList.remove('active'), 800);
    }
    /** プレイヤー入力処理 */
    pads.forEach(pad => pad.addEventListener('click', () => {
      if(!playing) return;
      const color = pad.dataset.color;
      lightPad(color);
      if(color === sequence[playerIdx]) {
        playerIdx++;
        if(playerIdx === sequence.length) {
          playing = false;
          level++;
          levelDisp.textContent = level;
          msgDiv.textContent = '正解!次のレベル';
          setTimeout(nextRound, 1000);
        }
      } else endGame();
    }));
    /** ゲームオーバー処理 */
    function endGame() {
      gameScreen.classList.add('hidden');
      finalLevel.textContent = level;
      endScreen.classList.remove('hidden');
    }
    document.addEventListener('DOMContentLoaded', () => {
      startBtn.addEventListener('click', startGame);
      restartBtn.addEventListener('click', showTitle);
      showTitle();
    });
  </script>
</body>
</html>

アルゴリズムの流れ

1. タイトル表示タイトル画面のみ表示し、他画面を隠すshowTitle()
2. ゲーム開始シーケンス配列を空に、レベル1にリセット、画面切替startGame()
3. シーケンス生成COLORS からランダムに1色を追加sequence.push(...)
4. シーケンス再生setInterval で順に lightPad() を呼び出し、点灯→保持→消灯を繰り返すlightPad()
5. プレイヤー入力クリック時に現在の期待色と比較し、成功なら次へ、失敗ならゲームオーバーpads.forEach(... click)
6. レベルアップ成功時にレベル更新、数値表示更新、次ラウンド呼び出しlevel++, nextRound()
7. 終了判定失敗時にゲーム画面を隠し、終了画面を表示endGame()

関数の詳しい解説

関数名説明
showTitle()タイトル画面を表示し、ゲーム画面・終了画面を非表示に
startGame()ゲーム状態(sequence, level)を初期化し、レベル表示をリセット、nextRound() を実行
nextRound()シーケンスに新色を追加し、再生後に入力受付状態へ切り替え
lightPad(color)指定した色の .pad 要素を一時的に .active クラスで強調表示し、その後クラスを削除
endGame()ゲーム画面を隠して終了画面を表示し、最終レベルをメッセージに反映

改造のポイント

  • 再生スピード調整
    setInterval の間隔(1200ms)や lightPad の保持時間(800ms)を変えると難易度を調整できます。
  • 色の追加/変更
    COLORS 配列に色を増やせばパッドを増やして記憶がさらに難しく可能。CSS .pad デザインを追加してください。
  • サウンド効果・アニメ
    光るときに効果音を鳴らしたり、レベルアップ・ゲームオーバー時にアニメーションを追加すると盛り上がります。
  • スコアボード機能
    localStorage にクリアした最高レベルを保存し、タイトル画面に「ハイスコア」表示を追加。
  • 視覚エフェクト
    .active クラスにカスタムアニメーション(CSS keyframes)を加えて、より派手に演出できます。

アドバイス:レベルに応じて背景色やパッドの形状を変えるなど、視覚的変化を盛り込むとプレイヤーのモチベーションが上がります。出題パターンを「逆再生」「同時光り」などバリエーションを増やして遊びごたえを工夫しましょう!