【ゲーム】JavaScript:49 スラムダンククイズ

ゲームの概要

 「🏀スラムダンククイズ」は、大人気バスケットボール漫画『SLAM DUNK』のストーリーやキャラクター、名場面に関する4択クイズゲームです。毎回ランダムで10問が出題され、ファン同士や友人・家族とも楽しめる内容です。バスケ愛や作品への知識を気軽に試せます。

遊び方・操作方法

  1. タイトル画面で「🏀 スタート!」ボタンをクリックするとクイズが開始します。
  2. 各問題で4つの選択肢ボタンから1つを選択して回答します。
  3. 回答後、正誤のメッセージと効果音が表示され、「次の問題 ➡️」ボタンが出現します。
  4. 10問すべて回答すると、正解数と正答率が表示されます。
  5. 「🏠 タイトル画面に戻る」ボタンで再挑戦できます。

ルール

  • 全30問からランダムで10問が出題されます。
  • 問題ごとに4択形式で、選択肢の並びも毎回シャッフルされます。
  • 回答を選ぶと正誤判定・効果音・メッセージが表示されます。
  • 終了時に**スコア(正答率と正解数)**が画面に表示されます。
  • すべて日本語で表示されます。

🎮ゲームプレイ

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

49 スラムダンククイズ

素材のダウンロード

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

効果音:魔王魂

slam_dunk_quiz_title.pngslam_dunk_quiz_bg.png

ゲーム画面イメージ

プログラム全体(slam_dunk_quiz.html)

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=700">
  <title>🏀 スラムダンククイズ 🏆</title>
  <style>
    * { margin: 0; padding: 0; box-sizing: border-box; }
    body {
      font-family: 'BIZ UDPGothic', 'Arial Black', 'Arial', sans-serif;
      background-image: url('slam_dunk_quiz_bg.png');
      background-size: cover;
      background-position: center;
      min-height: 100vh;
      color: #F8F3E8;
      display: flex; justify-content: center; align-items: center;
    }
    #quiz-container {
      background: linear-gradient(135deg, rgba(44, 44, 44, 0.92) 82%, rgba(245,130,32,0.18) 100%);
      border: 5px solid #f58620;
      border-radius: 22px;
      width: 700px; max-width: 96vw;
      min-height: 540px;
      padding: 30px 40px 30px 40px;
      box-shadow: 0 0 30px 8px #411e10;
      text-align: center;
      position: relative;
      z-index: 1;
    }
    h1 {
      font-size: 2.5rem;
      color: #ffbe4e;
      margin-bottom: 18px;
      letter-spacing: 3px;
      text-shadow: 2px 2px 13px #f65a1a, 1px 1px 2px #fff;
      background: rgba(36,19,5,0.19);
      border-radius: 12px;
      padding: 10px 0 10px 0;
      box-shadow: 0 2px 12px #fff4;
    }
    #title-screen img {
      display: block;
      margin: 0 auto 16px auto;
      max-width: 75%;
      height: auto;
      border-radius: 15px;
      box-shadow: 0 4px 18px #f65a1a;
      border: 2px solid #ffbe4e;
      background: #fff8;
    }
    .rules-title {
      text-align: center;
      font-weight: bold;
      font-size: 1.4rem;
      color: #ffbe4e;
      margin-top: 15px;
      text-shadow: 1px 1px 7px #f65a1a;
      letter-spacing: 1.5px;
      background: rgba(100,50,20,0.13);
      border-radius: 8px;
      padding: 7px 0;
    }
    .rules-body {
      text-align: left;
      margin: 0 10px 16px 10px;
      font-size: 1.13rem;
      line-height: 1.8;
      color: #F8F3E8;
      text-shadow: 0 1px 3px #411e10;
      background: rgba(100,50,20,0.13);
      border-radius: 8px;
      padding: 11px 12px 13px 15px;
    }
    button {
      padding: 12px 38px;
      font-size: 1.18rem;
      border-radius: 9px;
      border: 2.5px solid #ffbe4e;
      margin: 17px 10px 0 10px;
      background: linear-gradient(90deg, #f65a1a 70%, #ffbe4e 100%);
      color: #fff;
      font-weight: bold;
      cursor: pointer;
      box-shadow: 1px 2px 8px #411e10;
      transition: background 0.18s, transform 0.09s, color 0.13s;
      text-shadow: 1px 1px 1px #fff8;
    }
    button:hover {
      background: linear-gradient(90deg, #b53d0e 75%, #ffebb7 100%);
      color: #f65a1a;
      transform: scale(1.03);
    }
    #choices-container button {
      background: linear-gradient(90deg, #f65a1a 75%, #ffbe4e 100%);
      margin: 7px 0;
      font-size: 1.13rem;
      border-radius: 9px;
      border: 2px solid #ffbe4e;
      box-shadow: 0 1px 6px #411e10;
      color: #fff;
      font-weight: bold;
      text-shadow: 1px 1px 2px #000b;
      width: 100%;
      min-width: 0;
      max-width: 100%;
      transition: background 0.18s, color 0.12s;
    }
    #choices-container button:hover {
      background: linear-gradient(90deg, #b53d0e 80%, #fff4ad 100%);
      color: #ffbe4e;
      border-color: #ffbe4e;
    }
    #title-screen, #game-screen, #result-screen {
      display: none;
    }
    #title-screen.active, #game-screen.active, #result-screen.active {
      display: block;
    }
    #question-number {
      font-size: 1.13rem;
      margin-bottom: 7px;
      color: #ffbe4e;
      font-weight: bold;
      text-shadow: 1px 1px 4px #f65a1a;
      background: rgba(255,255,255,0.13);
      border-radius: 7px;
      padding: 4px 0;
      margin-top: 10px;
      box-shadow: 0 1px 4px #fff7;
      width: 85%;
      margin-left: auto;
      margin-right: auto;
    }
    #question-text {
      font-size: 1.42rem;
      margin: 20px 0 18px 0;
      letter-spacing: 1.2px;
      color: #fffbe9;
      background: rgba(255,190,78,0.16);
      border-radius: 8px;
      box-shadow: 0 1px 7px #fff7;
      padding: 13px 8px 13px 8px;
      width: 95%;
      margin-left: auto;
      margin-right: auto;
      font-weight: bold;
      text-align: center;
      text-shadow: 1px 1px 6px #f65a1a, 0 1px #fff7;
    }
    #feedback {
      font-size: 1.28rem;
      font-weight: bold;
      background: linear-gradient(90deg, #f65a1a88 80%, #ffbe4e99 100%);
      border-radius: 12px;
      padding: 13px 0;
      min-height: 36px;
      margin-bottom: 15px;
      color: #fff;
      text-shadow: 1px 1px 6px #f65a1a, 0 1px #fff9;
      border: 2px solid #ffbe4e;
      box-shadow: 0 2px 8px #fff3;
      width: 100%;
      margin-left: auto;
      margin-right: auto;
      display: none;
    }
    #result-message {
      font-size: 1.52rem;
      color: #ffbe4e;
      font-weight: bold;
      margin: 48px 0 30px 0;
      text-shadow: 2px 2px 12px #f65a1a, 1px 1px 3px #fff7;
      background: rgba(255,190,78,0.14);
      border-radius: 13px;
      padding: 14px 0;
      box-shadow: 0 2px 13px #fff3;
    }
    #return-button {
      display: block;
      margin: 0 auto;
      background: linear-gradient(90deg, #f65a1a 85%, #ffbe4e 100%);
      font-size: 1.17rem;
      color: #fff;
      font-weight: bold;
      border: 2.3px solid #ffbe4e;
      border-radius: 9px;
      box-shadow: 2px 4px 12px #fff, 0 1px 7px #b9a644;
      text-shadow: 1px 1px 1px #fff8;
      letter-spacing: 1px;
      border-bottom: 4px solid #ffbe4e;
      transition: background 0.15s, color 0.1s;
    }
    #return-button:hover { background: #fffbe9; color: #f65a1a; }
    @media (max-width:780px) {
      #quiz-container { padding: 8px 3vw; min-width: 0; width: 99vw;}
      h1 { font-size: 1.7rem; }
      #result-message, #question-text, #feedback { font-size: 1.1rem;}
      #choices-container button { font-size: 1rem; padding: 15px 0;}
    }
  </style>
</head>
<body>
  <div id="quiz-container">
    <h1>🏀 スラムダンククイズ 🏆</h1>
    <!-- タイトル画面 -->
    <div id="title-screen" class="active">
      <img src="slam_dunk_quiz_title.png" alt="スラムダンククイズ タイトル画像">
      <div class="rules-title">⛹️‍♂️ ルール説明 ⛹️‍♂️</div>
      <div class="rules-body">
        ・「スラムダンク」に関するクイズが全30問用意されています。<br>
        ・4つの選択肢から正しい答えを1つ選んでください。<br>
        ・<b>毎回ランダムで10問が出題されます!</b><br>
        ・終了時に正答率が表示されます。<br>
        ・問題・結果は全て日本語で表示されます。
      </div>
      <button id="start-button">🏀 スタート!</button>
    </div>
    <!-- ゲーム画面 -->
    <div id="game-screen">
      <div id="question-number"></div>
      <div id="question-text"></div>
      <div id="choices-container"></div>
      <div id="feedback"></div>
      <button id="next-button" style="display:none;">次の問題 ➡️</button>
    </div>
    <!-- 結果画面 -->
    <div id="result-screen">
      <div id="result-message"></div>
      <button id="return-button" style="display:none;">🏠 タイトル画面に戻る</button>
    </div>
    <!-- 効果音 -->
    <audio id="correct-sound" src="maoudamashii-quiz_correct.mp3"></audio>
    <audio id="incorrect-sound" src="maoudamashii-quiz_incorrect.mp3"></audio>
  </div>
  <script>
  window.onload = function() {
    // ==== スラムダンククイズ30問 ====
    const questions = [
      {q: "主人公・桜木花道が所属する高校は?",choices: ["湘北高校", "海南大付属高校", "陵南高校", "山王工業高校"],answer: "湘北高校"},
      {q: "流川楓のポジションは?",choices: ["スモールフォワード", "センター", "ポイントガード", "パワーフォワード"],answer: "スモールフォワード"},
      {q: "赤木剛憲のニックネームは?",choices: ["ゴリ", "カク", "バカギ", "カミソリ"],answer: "ゴリ"},
      {q: "三井寿が過去に受賞したタイトルは?",choices: ["MVP", "3ポイント王", "新人王", "得点王"],answer: "MVP"},
      {q: "桜木花道の背番号は?",choices: ["10", "4", "11", "7"],answer: "10"},
      {q: "海南大付属高校のエースは?",choices: ["牧紳一", "清田信長", "神宗一郎", "高砂一馬"],answer: "牧紳一"},
      {q: "安西先生の有名な名言は?",choices: ["あきらめたらそこで試合終了ですよ", "ファールだよ", "ドリブルはできるか?", "リバウンドを制する者はゲームを制す"],answer: "あきらめたらそこで試合終了ですよ"},
      {q: "宮城リョータのポジションは?",choices: ["ポイントガード", "スモールフォワード", "センター", "シューティングガード"],answer: "ポイントガード"},
      {q: "流川楓の将来の夢は?",choices: ["アメリカでバスケをする", "漫画家になる", "教師になる", "バスケ部監督になる"],answer: "アメリカでバスケをする"},
      {q: "湘北の監督は誰?",choices: ["安西光義", "高頭力", "田岡茂一", "堂本五郎"],answer: "安西光義"},
      {q: "山王工業のキャプテンは?",choices: ["深津一成", "河田雅史", "沢北栄治", "松本稔"],answer: "深津一成"},
      {q: "三井寿が一時離れていた部活は?",choices: ["バスケットボール部", "野球部", "サッカー部", "テニス部"],answer: "バスケットボール部"},
      {q: "桜木軍団のリーダーは?",choices: ["桜木花道", "水戸洋平", "高宮望", "野間忠一郎"],answer: "水戸洋平"},
      {q: "陵南高校の監督は?",choices: ["田岡茂一", "安西光義", "堂本五郎", "高頭力"],answer: "田岡茂一"},
      {q: "海南の神宗一郎のポジションは?",choices: ["シューティングガード", "ポイントガード", "スモールフォワード", "パワーフォワード"],answer: "シューティングガード"},
      {q: "山王工業戦で流川が決めたプレイは?",choices: ["ダンクシュート", "アリウープ", "レイアップ", "3ポイントシュート"],answer: "ダンクシュート"},
      {q: "赤木晴子は何部のマネージャー?",choices: ["バスケ部", "サッカー部", "テニス部", "野球部"],answer: "バスケ部"},
      {q: "陵南のエースは?",choices: ["仙道彰", "魚住純", "池上", "福田吉兆"],answer: "仙道彰"},
      {q: "湘北の最長身選手は?",choices: ["桜木花道", "赤木剛憲", "三井寿", "流川楓"],answer: "赤木剛憲"},
      {q: "赤木剛憲の妹は?",choices: ["赤木晴子", "彩子", "水野", "高宮望"],answer: "赤木晴子"},
      {q: "宮城リョータが好きな人は?",choices: ["彩子", "晴子", "三井寿", "安西先生"],answer: "彩子"},
      {q: "全国大会で湘北が最初に戦った高校は?",choices: ["豊玉高校", "山王工業", "海南大付属", "陵南高校"],answer: "豊玉高校"},
      {q: "湘北の“秘密兵器”と呼ばれるのは誰?",choices: ["桜木花道", "宮城リョータ", "三井寿", "赤木剛憲"],answer: "桜木花道"},
      {q: "山王工業のポイントガードは?",choices: ["深津一成", "沢北栄治", "河田雅史", "松本稔"],answer: "深津一成"},
      {q: "桜木花道のライバルは?",choices: ["流川楓", "牧紳一", "仙道彰", "三井寿"],answer: "流川楓"},
      {q: "湘北高校のバスケ部員でメガネ君と呼ばれるのは?",choices: ["木暮公延", "三井寿", "宮城リョータ", "高宮望"],answer: "木暮公延"},
      {q: "湘北高校のユニフォームの色は?",choices: ["赤", "白", "青", "黒"],answer: "赤"},
      {q: "流川楓の特技は?",choices: ["ドリブル", "ダンクシュート", "パス", "ディフェンス"],answer: "ドリブル"},
      {q: "安西先生のあだ名は?",choices: ["白髪鬼", "白髪王", "鬼監督", "あんちゃん"],answer: "白髪鬼"},
      {q: "桜木花道の得意なリバウンドで呼ばれる技は?",choices: ["跳躍リバウンド", "桜木ブロック", "超人リバウンド", "一人アリウープ"],answer: "超人リバウンド"},
      {q: "山王工業のエースは?",choices: ["沢北栄治", "深津一成", "河田雅史", "松本稔"],answer: "沢北栄治"}
    ];
    let quizList = [];
    let currentQuestion = 0;
    let correctCount = 0;

    // ==== DOM取得 ====
    const titleScreen  = document.getElementById('title-screen');
    const gameScreen   = document.getElementById('game-screen');
    const resultScreen = document.getElementById('result-screen');
    const startBtn     = document.getElementById('start-button');
    const questionNum  = document.getElementById('question-number');
    const questionText = document.getElementById('question-text');
    const choicesBox   = document.getElementById('choices-container');
    const feedback     = document.getElementById('feedback');
    const nextBtn      = document.getElementById('next-button');
    const resultMsg    = document.getElementById('result-message');
    const returnBtn    = document.getElementById('return-button');
    const correctSE    = document.getElementById('correct-sound');
    const incorrectSE  = document.getElementById('incorrect-sound');

    // ==== 配列シャッフル ====
    function shuffle(array) {
      for (let i = array.length - 1; i > 0; i--) {
        const j = Math.floor(Math.random() * (i + 1));
        [array[i], array[j]] = [array[j], array[i]];
      }
    }

    // ==== ゲーム開始 ====
    function startGame() {
      quizList = [...questions];
      shuffle(quizList);
      quizList = quizList.slice(0, 10); // 10問だけ出題
      currentQuestion = 0;
      correctCount = 0;
      titleScreen.classList.remove('active');
      resultScreen.classList.remove('active');
      gameScreen.classList.add('active');
      showQuestion();
    }

    // ==== 問題表示 ====
    function showQuestion() {
      let qData = quizList[currentQuestion];
      questionNum.textContent = `第${currentQuestion + 1}問 / 10`;
      questionText.textContent = qData.q;
      let choices = [...qData.choices];
      shuffle(choices);
      choicesBox.innerHTML = '';
      choices.forEach(choice => {
        let btn = document.createElement('button');
        btn.textContent = choice;
        btn.onclick = () => selectAnswer(choice, qData.answer);
        choicesBox.appendChild(btn);
      });
      // メッセージエリアは非表示
      feedback.style.display = "none";
      feedback.textContent = '';
      nextBtn.style.display = 'none';
    }

    // ==== 回答選択 ====
    function selectAnswer(selected, correct) {
      document.querySelectorAll('#choices-container button').forEach(b=>b.disabled=true);
      if (selected === correct) {
        feedback.textContent = "✨ 正解!バスケは好きか?";
        if (correctSE) { correctSE.currentTime = 0; correctSE.play(); }
        correctCount++;
      } else {
        feedback.textContent = `💀 不正解…正解は「${correct}」!`;
        if (incorrectSE) { incorrectSE.currentTime = 0; incorrectSE.play(); }
      }
      feedback.style.display = "block";
      nextBtn.style.display = "inline-block";
    }

    // ==== 次の問題へ ====
    function nextQuestion() {
      currentQuestion++;
      if (currentQuestion < quizList.length) {
        showQuestion();
      } else {
        endGame();
      }
    }

    // ==== 終了画面 ====
    function endGame() {
      gameScreen.classList.remove('active');
      resultScreen.classList.add('active');
      let rate = Math.round((correctCount / quizList.length) * 100);
      resultMsg.innerHTML =
        `🎉 クイズ終了!あなたの正答率は <span style="color:#ffbe4e">${rate}%</span> です!<br>` +
        `(${correctCount} / ${quizList.length}問)`;
      returnBtn.style.display = 'block';
    }

    // ==== タイトルへ戻る ====
    function toTitle() {
      resultScreen.classList.remove('active');
      titleScreen.classList.add('active');
      returnBtn.style.display = 'none';
    }

    // ==== イベント登録 ====
    startBtn.addEventListener('click', startGame);
    nextBtn.addEventListener('click', nextQuestion);
    returnBtn.addEventListener('click', toTitle);

    // ==== 初期画面表示 ====
    titleScreen.classList.add('active');
    gameScreen.classList.remove('active');
    resultScreen.classList.remove('active');
  }
  </script>
</body>
</html>

アルゴリズムの流れ

ステップ内容
1. 初期表示タイトル画面を表示し、「スタート!」ボタンのクリック待ち
2. ゲーム開始問題リスト(30問)をシャッフルし、10問抽出→ゲーム画面へ
3. 問題表示問題文と4つの選択肢(ランダム並べ替え)を描画
4. 回答選択回答ボタンを押すと正誤判定→正誤メッセージ+効果音、選択肢ボタンは無効化、「次の問題」ボタン出現
5. 次の問題問題カウンタ加算、残問があれば3へ戻る。全問終了で6へ
6. 結果表示正解数と正答率を表示、「タイトル画面に戻る」ボタンが押せるようになる
7. タイトル復帰タイトル画面に戻る。再度チャレンジ可能

関数・命令の役割

関数・変数名役割・説明
questions問題文・選択肢・正答の配列
shuffle(array)配列要素をランダムにシャッフル(Fisher–Yatesアルゴリズム)
startGame()クイズリストの初期化、10問抽出、ゲーム画面切り替え、1問目表示
showQuestion()問題番号・文・4択ボタンの表示
selectAnswer(selected, correct)回答判定、正誤メッセージ+効果音、ボタン無効化、次ボタン表示
nextQuestion()問題インデックス加算し次の問題か、終了処理
endGame()正答率と正解数を表示、結果画面に切り替え
toTitle()結果画面を非表示、タイトル画面再表示

関数の主な役割

関数名主な処理内容
shuffle(array)配列要素をランダムにシャッフル
startGame()クイズリスト初期化・抽選・画面切り替え
showQuestion()問題文と選択肢を動的生成・配置
selectAnswer()選択肢正誤判定・メッセージ/効果音・選択肢無効化・次ボタン表示
nextQuestion()カウンタ加算、次の問題 or 終了処理へ
endGame()スコア表示・終了画面切り替え
toTitle()終了画面非表示、タイトル画面表示

改造のポイント

  • 問題の追加・差し替え
    questions配列に新しい問題や選択肢を追加/編集すれば自由にカスタマイズできます。
  • 出題数の変更
    quizList.slice(0, 10) の「10」を希望の問題数に変更できます。
  • タイマーや難易度別モード
    時間制限・難易度別(easy/normal/hard)等の出題も発展的に追加できます。
  • デザイン・演出の強化
    CSSや画像・音声素材の追加で、より作品世界を盛り上げましょう。
  • 正解後のミニ解説やヒント表示
    回答後に「なぜそれが正解か」を表示すると、さらに学びが深まります。

アドバイス

本プログラムはシンプルな構造でカスタマイズしやすく、クイズの追加やデザイン変更がすぐにできます。
SLAM DUNKファン同士の集まりやイベントで盛り上がること間違いなし!
自分だけのクイズやオリジナル演出で、バスケや作品の魅力をより多くの人に広めましょう!