【ゲーム】JavaScript:62 絵文字ペア探しゲーム

 「🔎 絵文字ペア探しゲーム 🔎」は、同じ絵文字を2枚ずつランダムに並べた全18枚(ペア数9組)のカードをめくり、ペアを探す記憶力&集中力ゲームです。すべてのペアを見つけるまでのタイムを計測し、早くクリアするほど達成感を味わえます。

遊び方・操作方法

  1. タイトル画面で「スタート」ボタンをクリック。
  2. ゲーム画面に18枚のカードが裏向きで並びます。
  3. カードをクリックすると絵文字が表示され、1枚目の選択状態に移行。
  4. 続けて2枚目をクリックすると2枚合わせの判定が行われ、
    ・同じ絵文字ならカードが消え(緑色に変化)、
    ・違う絵文字なら一瞬表示後に再び裏向きに戻ります。
  5. 残りすべてのペアを見つけてカードが消えるとクリア。
  6. クリアタイム(秒)が表示され、「タイトル画面に戻る」で再挑戦できます。

ルール

  • カード枚数:18枚(9ペア)
  • クリック制限:同時に開けられるカードは2枚まで
  • クリア判定:すべてのカードがペアとして消えた瞬間
  • タイム計測:スタート直後からすべて消えるまでを秒単位で計測
  • 終了条件:全ペア消去でゲームクリア。時間制限はなし。

🎮ゲームプレイ

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

62 絵文字ペア探しゲーム

素材のダウンロード

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

emoji_pair_search_title.pngemoji_pair_search_bg.png

ゲーム画面イメージ

プログラム全文(emoji_pair_search.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('emoji_pair_search_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.95);
      border-radius: 22px;
      box-shadow: 0 4px 24px rgba(0,0,0,0.13);
      padding-bottom: 32px;
      min-height: 530px;
      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: 270px;
      padding: 16px 0 20px 0;
      user-select: none;
    }
    .pair-board {
      display: grid;
      grid-template-columns: repeat(6, 65px);
      grid-gap: 20px 25px;
      justify-content: center;
      margin-top: 20px;
      margin-bottom: 12px;
    }
    .card-btn {
      width: 65px; height: 65px;
      font-size: 2.1em;
      background: #fff;
      color: #333;
      border-radius: 15px;
      border: 2.5px solid #1976d2;
      box-shadow: 0 2px 10px #1976d255;
      cursor: pointer;
      outline: none;
      transition: background 0.12s, transform 0.14s;
      display: flex; align-items: center; justify-content: center;
      position: relative;
      z-index: 1;
    }
    .card-btn:active {
      background: #e3f2fd;
      transform: scale(0.97);
    }
    .card-btn.paired {
      background: #c8e6c9 !important;
      border-color: #388e3c;
      color: #388e3c;
      box-shadow: 0 0 7px #81c78499;
      cursor: default;
      animation: paired-pop 0.6s;
      pointer-events: none;
    }
    @keyframes paired-pop {
      0%   { transform: scale(1);}
      30%  { transform: scale(1.16);}
      60%  { transform: scale(0.94);}
      100% { transform: scale(1);}
    }
    .info {
      text-align: center;
      color: #1976d2;
      font-size: 1.8em;      /* 大きく */
      font-weight: bold;     /* 太字で強調 */
      margin: 10px 0 0 0;
      letter-spacing: 0.05em;
    }
    .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: 2.4em;   /* さらに大きく */
      color: #e53935;
      font-weight: bold;
      letter-spacing: 0.08em;
      margin-top: 12px;
      margin-bottom: 6px;
    }
    @media (max-width: 900px) {
      .container, .game-area { width: 98vw !important; min-width: 0; }
      .pair-board { grid-template-columns: repeat(4, 18vw); grid-gap: 2vw; }
      .card-btn { width: 18vw; height: 18vw; font-size: 7vw;}
      .timer-bar { font-size: 6vw; }
      .info { font-size: 5vw; }
    }
  </style>
</head>
<body>
  <div class="container" id="main-container"></div>
  <script>
    // =============================
    // 🔎 絵文字ペア探しゲーム
    // =============================

    // 絵文字の種類リスト
    const EMOJI_LIST = [
      "🍎","🍋","🍌","🍇","🍊","🍓","🥑","🍒","🥕","🌽",
      "🥐","🍔","🍕","🍩","🍰","🍫","🍤","🍣"
    ];
    const PAIR_COUNT = 9; // ペア数(難易度調整可)
    let board = [];
    let found = [];
    let lastPick = null;
    let startTime = 0;
    let timerId = null;
    let timeSec = 0;

    // タイトル画面を表示
    function showTitleScreen() {
      clearInterval(timerId);
      document.getElementById('main-container').innerHTML = `
        <h1>🔎 絵文字ペア探しゲーム 🔎</h1>
        <img src="emoji_pair_search_title.png" class="title-img" alt="絵文字ペア探しゲーム タイトル">
        <div class="rule-section">
          <div class="rule-title">🔎 遊び方・ルール 🔎</div>
          <div class="rule-text">
            ・同じ絵文字が2枚ずつ、全${PAIR_COUNT*2}枚ランダムに並びます。<br>
            ・同じ絵文字のペアをすべて探して、素早く消しましょう。<br>
            ・どちらかをクリックするとペア選択モードに。<br>
            ・2枚目のペアをクリックしたらその2枚が消えます。<br>
            ・すべて消したらクリアです。タイムも計測します!
          </div>
        </div>
        <button class="btn" id="start-btn">スタート</button>
      `;
      document.getElementById('start-btn').onclick = startGame;
    }

    // ゲーム開始
    function startGame() {
      board = [];
      found = new Array(PAIR_COUNT*2).fill(false);
      lastPick = null;
      // ペアを作ってシャッフル
      let selected = EMOJI_LIST.slice(0, PAIR_COUNT);
      let pairs = [...selected, ...selected];
      for (let i = pairs.length - 1; i > 0; i--) {
        const j = Math.floor(Math.random() * (i + 1));
        [pairs[i], pairs[j]] = [pairs[j], pairs[i]];
      }
      board = pairs;
      timeSec = 0;
      showGameScreen();
      startTime = Date.now();
      timerId = setInterval(()=>{
        timeSec = ((Date.now()-startTime)/1000).toFixed(1);
        const tb = document.getElementById('timer-bar');
        if(tb) tb.textContent = `タイム: ${timeSec} 秒`;
      }, 100);
    }

    // ゲーム画面
    function showGameScreen() {
      let cards = "";
      for (let i = 0; i < board.length; i++) {
        cards += `
          <button class="card-btn${found[i] ? ' paired' : ''}" id="card${i}" ${found[i] ? 'disabled' : ''} onclick="pickCard(${i})">
            ${found[i] ? "" : board[i]}
          </button>
        `;
      }
      document.getElementById('main-container').innerHTML = `
        <h1>🔎 絵文字ペア探しゲーム 🔎</h1>
        <div class="game-area">
          <div class="info">同じ絵文字のペアを見つけてクリック!</div>
          <div class="timer-bar" id="timer-bar">タイム: ${timeSec} 秒</div>
          <div class="pair-board">${cards}</div>
        </div>
      `;
    }

    // カード選択時
    function pickCard(idx) {
      if (found[idx]) return;
      if (lastPick === null) {
        lastPick = idx;
        document.getElementById(`card${idx}`).classList.add('selected');
      } else if (lastPick !== idx) {
        // ペア判定
        if (board[idx] === board[lastPick]) {
          found[idx] = true;
          found[lastPick] = true;
          document.getElementById(`card${idx}`).classList.add('paired');
          document.getElementById(`card${lastPick}`).classList.add('paired');
          // 残りが全部ペアか?
          if (found.filter(v=>v).length === board.length) {
            clearInterval(timerId);
            setTimeout(()=>showEndScreen(), 700);
            return;
          }
        }
        setTimeout(()=>{
          // カードを再描画してリセット
          showGameScreen();
        }, 400);
        lastPick = null;
      }
    }

    // 終了画面
    function showEndScreen() {
      document.getElementById('main-container').innerHTML = `
        <h1>🔎 絵文字ペア探しゲーム 🔎</h1>
        <img src="emoji_pair_search_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.pickCard = pickCard;

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

アルゴリズムの流れ

手順処理内容
1showTitleScreen() でタイトル画面を描画
2「スタート」押下 → startGame() でカード配列と found 配列を初期化 → 画面描画
3startGame() でタイマー開始(setInterval)→ showGameScreen()
4showGameScreen() で裏向きカードボタンをグリッドに並べる
5クリック時 pickCard(idx):  ・1枚目なら選択フラグをセット  ・2枚目ならペア判定→合致で消去
6全消去判定で showEndScreen() を呼び出し、クリアタイムを表示
7結果画面で「タイトルに戻る」を押すと、再び showTitleScreen()

関数の詳細

関数名機能概要詳細説明
showTitleScreen()タイトル画面描画ルール説明+「スタート」ボタン設置。タイマークリア。
startGame()ゲーム初期化&開始ペア用絵文字を2枚ずつ配列に追加→シャッフル→found初期化→タイマー開始→ゲーム画面描画
showGameScreen()ゲーム画面描画boardfound からカードボタンを生成してDOMに出力、タイム表示の準備
pickCard(idx)カード選択&ペア判定1枚目・2枚目のクリックを管理。2枚目クリックで絵文字比較→合致ならfound更新→再描画 or クリア判定
showEndScreen()終了画面描画クリアメッセージ+クリアタイム表示+「タイトルに戻る」ボタン設置

改造のポイント

  • ペア数調整/難易度設定PAIR_COUNT を増減して難易度を変更。ペア数12組(24枚)以上にすると高難度に。
  • カード裏デザイン:CSSで裏面に模様やアニメーションを付け、めくり演出を強化。
  • 制限時間モード:クリアタイムではなく、制限時間内に何ペア消せるかを競うモードを追加。
  • スコア保存/ランキングlocalStorage でベストタイムを保存し、ランキング画面で競争要素を導入。
  • モバイル最適化:タッチ操作時の押下フィードバックやカードサイズを動的に調整し、レスポンシブ対応を強化。

アドバイス
まずはスムーズなカードめくり&比較ロジックを安定させ、次に演出(カード反転アニメ・サウンド)やモード追加でリプレイ性を高めましょう。ランキング機能を実装すると、ユーザーの継続プレイを促進できます!