【ゲーム】JavaScript:64 タイル記憶チャレンジ

 「🧠 タイル記憶チャレンジ 🧠」は、6×5 のマス上にランダムに光るタイル(初期ヒントタイル)を一瞬だけ記憶し、その位置を正確に当てるメモリーゲームです。光ったタイルをすべてクリックで当てるまでのタイムを競います。

遊び方・操作方法

  1. スタートボタンをクリックするとゲーム開始。
  2. 盤面(6列×5行)のうち、ランダムで7枚のタイルが一瞬だけ「光る(黄色)」ので、位置を覚える。
  3. 光が消えたら、覚えたタイルを順番・順不同にクリックして当てる。
  4. すべて正解すればクリア。間違えると即リトライ(同じタイル配置で再挑戦)となる。

ルール

  • 盤面サイズ:6列×5行(計30マス)
  • ヒントタイル数:7枚(HINT_CNT = 7
  • ヒント表示:開始後0.4秒後に1.35秒間光る
  • 制限時間:なし(クリアタイムを計測)
  • 間違い:不正解タイルをクリックするとすぐリトライ
  • クリア:7枚すべてを当てた瞬間

🎮ゲームプレイ

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

64 タイル記憶チャレンジ

素材のダウンロード

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

tile_memory_challenge_title.pngtile_memory_challenge_bg.png

ゲーム画面イメージ

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

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>🧠 タイル記憶チャレンジ 🧠</title>
  <style>
    html, body {
      margin: 0; padding: 0;
      width: 100vw; height: 100vh;
      font-family: 'Yu Gothic', 'Meiryo', sans-serif;
      background: url('tile_memory_challenge_bg.png') no-repeat center center fixed;
      background-size: cover;
    }
    body {
      width: 100vw;
      height: 100vh;
      overflow: auto;
    }
    .container {
      width: 800px;
      margin: 40px auto;
      background: rgba(255,255,255,0.96);
      border-radius: 22px;
      box-shadow: 0 4px 24px rgba(0,0,0,0.13);
      padding-bottom: 32px;
      min-height: 520px;
      position: relative;
    }
    .title-img {
      display: block;
      margin: 20px auto 18px auto;
      width: 340px;
      max-width: 80%;
      height: auto;
    }
    h1 {
      text-align: center;
      font-size: 2.1em;
      margin: 0.6em 0 0.15em 0;
      color: #1976d2;
      text-shadow: 1px 1px 7px #fff;
      letter-spacing: 0.04em;
    }
    .rule-section {
      background: rgba(235,245,255,0.98);
      border-radius: 14px;
      margin: 28px 32px 14px 32px;
      padding: 16px 24px;
      box-shadow: 0 2px 8px #4d90fe22;
    }
    .rule-title {
      text-align: center;
      font-weight: bold;
      font-size: 1.3em;
      margin-bottom: 10px;
      color: #1976d2;
    }
    .rule-text {
      text-align: left;
      font-size: 1.09em;
      line-height: 1.65;
      color: #174078;
      letter-spacing: 0.01em;
    }
    .btn {
      display: block;
      margin: 28px auto 0 auto;
      padding: 14px 50px;
      font-size: 1.2em;
      border: none;
      border-radius: 28px;
      background: linear-gradient(90deg, #87c9fa, #1565c0);
      color: #fff;
      font-weight: bold;
      box-shadow: 0 2px 8px #1976d266;
      cursor: pointer;
      transition: background 0.2s;
    }
    .btn:hover { background: linear-gradient(90deg, #b7e4fe, #1976d2); }
    .game-area {
      width: 740px;
      margin: 36px auto 0 auto;
      background: rgba(240,248,255,0.96);
      border-radius: 16px;
      box-shadow: 0 1px 10px #1565c055;
      display: flex;
      flex-direction: column;
      align-items: center;
      min-height: 310px;
      padding: 16px 0 20px 0;
      user-select: none;
    }
    .info {
      text-align: center;
      color: #1976d2;
      font-size: 1.19em;
      margin: 5px 0 0 0;
    }
    .memory-board {
      display: grid;
      grid-template-columns: repeat(6, 54px);
      grid-gap: 15px 18px;
      justify-content: center;
      margin-top: 26px;
      margin-bottom: 10px;
    }
    .memory-tile {
      width: 54px; height: 54px;
      background: #fff;
      border: 2.5px solid #1976d2;
      border-radius: 14px;
      box-shadow: 0 2px 8px #1976d266;
      cursor: pointer;
      font-size: 2.1em;
      display: flex; align-items: center; justify-content: center;
      transition: background 0.14s, border-color 0.14s;
      user-select: none;
      position: relative;
      outline: none;
    }
    .memory-tile.selected {
      background: #b2ebf2;
      border-color: #00bcd4;
      color: #006064;
    }
    .memory-tile.found {
      background: #c8e6c9 !important;
      border-color: #388e3c;
      color: #388e3c;
      box-shadow: 0 0 7px #81c78499;
      cursor: default;
      pointer-events: none;
      animation: found-pop 0.45s;
    }
    .memory-tile.hint {
      background: #ffd54f !important;
      border-color: #ff9800;
      color: #bf360c;
    }
    .memory-tile:active:not(.found):not(.hint) {
      background: #e3f2fd;
      transform: scale(0.96);
    }
    @keyframes found-pop {
      0%   { transform: scale(1);}
      50%  { transform: scale(1.13);}
      100% { transform: scale(1);}
    }
    .message-box {
      text-align: center;
      background: rgba(235,245,255,0.98);
      font-size: 1.7em;
      color: #1976d2;
      font-weight: bold;
      border-radius: 16px;
      box-shadow: 0 4px 24px #1976d233;
      width: 80%;
      max-width: 480px;
      margin: 34px auto 0 auto;
      padding: 32px 18px;
      position: relative;
      z-index: 2;
    }
    .center-btn { margin: 22px auto 0 auto; }
    .timer-bar {
      text-align: center;
      font-size: 1.09em;
      margin-top: 6px;
      color: #e53935;
      font-weight: bold;
      letter-spacing: 0.08em;
    }
    @media (max-width: 900px) {
      .container, .game-area { width: 98vw !important; min-width: 0; }
      .memory-board { grid-template-columns: repeat(4, 17vw); grid-gap: 2vw; }
      .memory-tile { width: 17vw; height: 17vw; font-size: 6vw;}
    }
  </style>
</head>
<body>
  <div class="container" id="main-container"></div>
  <script>
    // =============================
    // 🧠 タイル記憶チャレンジ
    // =============================

    const BOARD_W = 6, BOARD_H = 5; // 6x5の盤面
    const TILE_CNT = BOARD_W * BOARD_H;
    const HINT_CNT = 7; // 一度に記憶するタイルの数(レベルで増減可)
    let hintTiles = [];
    let foundTiles = [];
    let selectedTiles = [];
    let phase = "wait";
    let startTime = 0;
    let timerId = null;
    let timeSec = 0;

    // タイトル画面
    function showTitleScreen() {
      clearInterval(timerId);
      document.getElementById('main-container').innerHTML = `
        <h1>🧠 タイル記憶チャレンジ 🧠</h1>
        <img src="tile_memory_challenge_title.png" class="title-img" alt="タイル記憶チャレンジ タイトル">
        <div class="rule-section">
          <div class="rule-title">🧠 遊び方・ルール 🧠</div>
          <div class="rule-text">
            ・一瞬だけ光るタイルの位置を覚えよう!<br>
            ・すべて当てるまでクリック!<br>
            ・間違えたらやり直しです。<br>
            ・タイムも計測されます。
          </div>
        </div>
        <button class="btn" id="start-btn">スタート</button>
      `;
      document.getElementById('start-btn').onclick = startGame;
    }

    // ゲーム開始
    function startGame() {
      // ヒントタイルランダム選出
      let arr = Array.from({length: TILE_CNT}, (_,i)=>i);
      for (let i = arr.length - 1; i > 0; i--) {
        const j = Math.floor(Math.random() * (i + 1));
        [arr[i], arr[j]] = [arr[j], arr[i]];
      }
      hintTiles = arr.slice(0, HINT_CNT).sort((a,b)=>a-b); // 並びは小さい順
      foundTiles = new Array(TILE_CNT).fill(false);
      selectedTiles = [];
      phase = "show";
      timeSec = 0;
      showGameScreen();
      setTimeout(showHint, 400);
    }

    // ヒントを一瞬表示
    function showHint() {
      renderBoard(true);
      setTimeout(()=>{
        phase = "play";
        startTime = Date.now();
        timerId = setInterval(()=>{
          timeSec = ((Date.now()-startTime)/1000).toFixed(1);
          const tb = document.getElementById('timer-bar');
          if(tb) tb.textContent = `タイム: ${timeSec} 秒`;
        }, 100);
        renderBoard(false);
      }, 1350);
    }

    // ゲーム画面
    function showGameScreen() {
      document.getElementById('main-container').innerHTML = `
        <h1>🧠 タイル記憶チャレンジ 🧠</h1>
        <div class="game-area">
          <div class="info">${phase==="play" ? "光っていたタイルの位置をすべて当てて!" : "これから光るタイルを覚えてください。"}</div>
          <div class="timer-bar" id="timer-bar">タイム: ${timeSec} 秒</div>
          <div class="memory-board" id="memory-board"></div>
        </div>
      `;
      renderBoard(phase==="show");
    }

    // ボード描画
    function renderBoard(hint=false) {
      let html = "";
      for(let i=0; i<TILE_CNT; i++) {
        let cls = "memory-tile";
        let disp = "";
        if(hint && hintTiles.includes(i)) cls += " hint";
        if(foundTiles[i]) cls += " found";
        if(selectedTiles.includes(i) && !foundTiles[i]) cls += " selected";
        html += `<div class="${cls}" id="tile${i}" onclick="pickTile(${i})">${disp}</div>`;
      }
      document.getElementById('memory-board').innerHTML = html;
    }

    // タイルクリック
    function pickTile(idx) {
      if(phase !== "play" || foundTiles[idx] || selectedTiles.includes(idx)) return;
      selectedTiles.push(idx);
      // 正解判定
      if(hintTiles.includes(idx)) {
        foundTiles[idx] = true;
        renderBoard();
        // 全て見つけたらクリア
        if(foundTiles.filter(v=>v).length === HINT_CNT) {
          clearInterval(timerId);
          setTimeout(showEndScreen, 700);
          return;
        }
      } else {
        // 間違い→やり直し
        phase = "fail";
        renderBoard();
        setTimeout(()=>{
          showGameScreen();
          setTimeout(showHint, 500);
        }, 1100);
        return;
      }
      renderBoard();
    }

    // 終了画面
    function showEndScreen() {
      document.getElementById('main-container').innerHTML = `
        <h1>🧠 タイル記憶チャレンジ 🧠</h1>
        <img src="tile_memory_challenge_title.png" class="title-img" alt="タイル記憶チャレンジ タイトル">
        <div class="message-box">
          🎉 すべてのタイルを当てました!<br>あなたのタイム:<b>${timeSec}</b> 秒
        </div>
        <button class="btn center-btn" id="back-title-btn">タイトル画面に戻る</button>
      `;
      document.getElementById('back-title-btn').onclick = showTitleScreen;
    }

    // グローバル
    window.pickTile = pickTile;

    // 初期表示
    showTitleScreen();
  </script>
</body>
</html>

アルゴリズムの流れ

ステップ関数内容
1showTitleScreenタイトル画面の描画。ルールとスタートボタン設置。
2startGameヒントタイルをランダム選出して初期化→showGameScreenshowHintへ移行
3showHintヒント表示フェーズ。盤面に hint クラスを付与し1.35秒後に非表示フェーズへ
4renderBoardhintplayfound フェーズに応じたタイル描画
5pickTileクリックイベント。正解なら foundTiles 更新、すべて当てれば showEndScreen。不正解ならリトライ
6showEndScreenクリアタイム表示&タイトル戻りボタン設置

関数の詳細

関数名役割詳細
showTitleScreenタイトル画面の生成ルール説明・スタートボタンを表示。タイマー停止
startGameゲーム初期化&開始ヒントタイルをランダム抽出・配列初期化→画面構築→ヒント表示
showHintヒントフェーズrenderBoard(true) で黄色背景にして一瞬表示→クリックフェーズ開始
renderBoardボード描画hintselectedfound 各クラスを付与し、DOMで再構築
pickTileタイル選択処理正誤判定 → 正解:foundTiles 更新 ➝ 全消去でクリア画面不正解:phase="fail" ➝ リトライ
showEndScreen終了画面表示クリアタイム表示+タイトルへ戻るボタン設置

改造のポイント

  • 難易度設定HINT_CNT を増減してタイル枚数を調整。初級者は5枚、中級は7枚、上級は10枚など。
  • 段階モード:ステージクリアごとに HINT_CNT を段階的に増やす「レベルアップ制」を実装。
  • 演出強化:タイルが光る際のアニメーション(CSSトランジション強化)やサウンドエフェクトを追加すると没入感UP。
  • タイムアタックランキングlocalStorage に最速タイムを保存し、ベストスコアを表示するランキング画面を実装。
  • レスポンシブ調整:スマホでの見やすさ・操作しやすさを考慮し、タイルサイズや間隔を動的に調整。

アドバイス
まずはコアロジック(タイルの選出→表示→クリック判定→クリア判定)の安定を優先。そのあと見た目・音・モード追加を進めると、段階的にクオリティを高めやすくなります!