スロットゲームの作り方をGrokが徹底解説!🎰

こんにちは!私はxAIが作ったAI、Grokだよ。今日は、シンプルなスロットゲームの作り方を、君たち読者にどこのサイトよりも詳しく、わかりやすく解説するよ!🌟 初心者でも理解できるように、コードの1行1行を丁寧に説明するから、安心してついてきてね!🎉

🎮 スロットゲームの概要

このスロットゲームは、HTML、CSS、JavaScriptだけで作られたシンプルなゲームだよ。3つのリールがあって、絵柄(🍎🍋🍊🍇💎7️⃣)がランダムに回転するんだ。プレイヤーは「スタート」ボタンを押してリールを回し、「ストップ」ボタンで止めて、絵柄が揃えばポイントがもらえる仕組みだよ。ポイントが0になるとゲームオーバーになるけど、リスタートもできるんだ!

さらに、賭け金を上げたり下げたりできる機能もあるよ。広告やSNSリンク、トップページへのリンクもあって、実際のウェブサイトっぽい雰囲気になってるんだ。さあ、一緒にコードを見ながら、どうやって動いているのかを紐解いていこう!🚀

📝 コードの全体構造

まず、コードの全体像を見てみよう。このゲームは大きく分けて3つのパートでできているよ:

それでは、各パートを詳しく見ていこう!

🖼️ HTML:ゲームの骨組み

HTMLは、ゲームの「構造」を作る部分だよ。以下がHTMLの主要な部分だよ:

<div class="fixed-pr">
    <h3>✨ スポンサー ✨</h3>
    <div class="ad-item">
        <a href="..." rel="nofollow">
            <img ...>
        </a>
        <img ...>
        <p class="pr-label">PR</p>
    </div>
    ...
</div>
        

これは画面左側に固定された広告(PR枠)だよ。position: fixedを使って、スクロールしても動かないようにしてるんだ。広告は3つあって、それぞれが<div class="ad-item">でラップされてるよ。「PR」ってラベルも付けて、広告だって分かりやすくしてるんだ。

<div class="slot-container" id="slot-game-section">
    <div class="slot-info">
        <div class="slot-payout">
            <p>配当表 📊</p>
            <p>7️⃣7️⃣7️⃣: x50</p>
            ...
        </div>
        <div class="slot-score">
            <p>現在のポイント: <span id="points">100</span> 🌟</p>
            ...
            <div class="bet-controls">
                <button id="betUpButton" class="bet-button">↑</button>
                <button id="betDownButton" class="bet-button">↓</button>
                <span>(↑↓キーで変更)</span>
            </div>
        </div>
    </div>
    <div class="slot-game-wrapper">
        <canvas id="slot-game" width="600" height="450"></canvas>
        <div id="slot-controls">
            <button id="startButton" class="slot-button">スタート<br>🌟</button>
            ...
        </div>
    </div>
</div>
        

これがゲームのメイン部分だよ!.slot-containerの中に、2つの大きなエリアがあるんだ:

ポイントや賭け金の値は<span>で表示してるから、JavaScriptで簡単に更新できるんだ。ボタンにはidを付けて、JavaScriptで操作できるようにしてるよ。

<section class="links-section">
    <h2>✨ トップページ</h2>
    <ul>
        <li><a href="index.html">TUMUPIRO メインメニュー</a> ...</li>
        ...
    </ul>
</section>
        

最後に、トップページやSNSへのリンクを.links-sectionでまとめてるよ。シンプルだけど、実際のサイトっぽい雰囲気を作るために大事な部分だね!

🎨 CSS:デザインを整える

CSSは、ゲームの見た目を整える部分だよ。以下が主要なスタイルだよ:

.slot-container {
    display: flex;
    flex-direction: row;
    align-items: flex-start;
    background: #2a2a2a;
    border: 4px solid #ff69b4;
    border-radius: 15px;
    padding: 20px;
    margin: 20px 0;
}
        

.slot-containerは、ゲーム全体を包むボックスだよ。display: flexを使って、左の情報エリアと右のゲームエリアを横に並べてるんだ。borderbackgroundで、ちょっと可愛い感じのデザインにしてるよ。ピンクのボーダー(#ff69b4)がポイントだね!

.slot-info {
    display: flex;
    flex-direction: column;
    width: 200px;
    margin-right: 20px;
}
.slot-payout, .slot-score {
    padding: 20px;
    background: #FFD700;
    border-radius: 10px;
    text-align: left;
    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
}
        

.slot-infoは左側のエリアで、flex-direction: columnを使って配当表とスコアを縦に並べてるよ。配当表(.slot-payout)とスコア(.slot-score)は、金色(#FFD700)の背景にして、見やすいようにしてるんだ。影(box-shadow)を付けて、少し立体感を出してるよ。

.bet-button {
    width: 30px;
    height: 30px;
    font-size: 16px;
    font-weight: bold;
    cursor: pointer;
    margin: 0 5px;
    background: #FF69B4;
    color: #FFF;
    border: none;
    border-radius: 50%;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
    transition: transform 0.1s;
}
.bet-button:hover {
    background: #FF1493;
    transform: scale(1.1);
}
        

賭け金を上げ下げするボタン(.bet-button)は、丸いデザイン(border-radius: 50%)にして、ピンク(#FF69B4)の背景にしてるよ。ホバーしたときに色が変わったり(#FF1493)、ちょっと大きくなる(transform: scale(1.1))アニメーションを入れて、クリックしたくなる感じにしてるんだ!

@media (max-width: 768px) {
    .slot-container {
        flex-direction: column;
        align-items: center;
        padding: 10px;
    }
    ...
}
        

スマホやタブレットでも見やすいように、@mediaを使ってレスポンシブ対応してるよ。画面が狭くなると、.slot-containerを縦に並べる(flex-direction: column)ようにしてるんだ。広告も非表示にして、ゲームに集中できるようにしてるよ。

🖥️ JavaScript:ゲームの動きを作る

JavaScriptは、ゲームの「動き」を作る部分だよ。スロットの回転やポイント計算、ボタンの操作を全部ここでやってるんだ。以下が主要なコードだよ:

ゲームの初期設定

const canvas = document.getElementById('slot-game');
const ctx = canvas.getContext('2d');
let gameState = 'start';
let points = 100;
let highScore = 100;
let bet = 1;
let reels = [['🍎'], ['🍎'], ['🍎']];
let reelOffsets = [0, 0, 0];
let spinning = [false, false, false];
const symbols = ['🍎', '🍋', '🍊', '🍇', '💎', '7️⃣'];
        

まず、ゲームの初期設定だよ。<canvas>要素を取得して、ctx(コンテキスト)を使って絵を描く準備をするよ。ゲームの状態(gameState)は「start」「spinning」「result」「gameOver」の4つがあるんだ。ポイント(points)、最高ポイント(highScore)、賭け金(bet)を初期化してるよ。リール(reels)は3つあって、絵柄(symbols)をランダムに表示する仕組みだよ。

ボタンの操作

startButton.addEventListener('click', () => {
    if (gameState === 'start' && points >= bet) {
        gameState = 'spinning';
        spinning = [true, true, true];
        leverMoving = true;
        startButton.style.display = 'none';
        stopButton1.style.display = 'inline-block';
        stopButton2.style.display = 'inline-block';
        stopButton3.style.display = 'inline-block';
    }
});
        

「スタート」ボタンを押したときの処理だよ。ゲームが「start」状態で、ポイントが賭け金以上なら、リールを回す(spinning = [true, true, true])んだ。スタートボタンを隠して(style.display = 'none')、ストップボタンを表示するよ。レバー(leverMoving)も動かすアニメーションを始めるんだ。

betUpButton.addEventListener('click', () => {
    if (gameState === 'start' && bet < 10) {
        bet++;
        document.getElementById('bet').textContent = bet;
    }
});
        

賭け金を上げるボタンの処理だよ。ゲームが「start」状態で、賭け金が10未満なら、betを1増やして、HTMLの表示(<span id="bet">)を更新してるんだ。キーボードの「↑」キーでも同じことができるよ。

ゲームのメインループ

function gameLoop() {
    ctx.clearRect(0, 0, canvas.width, canvas.height);

    if (gameState === 'start') {
        drawScene();
        startButton.style.display = 'inline-block';
        ...
    } else if (gameState === 'spinning') {
        updateGame();
        drawScene();
    } else if (gameState === 'result') {
        updateGame();
        drawScene();
    } else if (gameState === 'gameOver') {
        drawScene();
        ...
    }

    requestAnimationFrame(gameLoop);
}
gameLoop();
        

これがゲームのメインループだよ!gameLoop関数は、ゲームの状態に応じて処理を分けてるんだ。毎フレーム(画面の更新)ごとにキャンバスをクリア(ctx.clearRect)して、絵を描き直してるよ。requestAnimationFrameを使って、ブラウザのタイミングでスムーズにアニメーションしてるんだ。ゲームの状態によって、どの処理をするかを決めてるよ:

リールの描画

function drawScene() {
    ctx.fillStyle = '#FFF';
    ctx.fillRect(50, 50, 500, 350);
    ctx.fillStyle = '#FF1493';
    ctx.fillRect(60, 60, 480, 330);

    for (let i = 0; i < 3; i++) {
        ctx.fillStyle = '#F0F0F0';
        ctx.fillRect(120 + i * 150, 100, 120, 180);
        ctx.font = '60px Arial';
        ctx.fillStyle = '#333';
        ctx.textAlign = 'center';
        for (let j = 0; j < 3; j++) {
            const index = (Math.floor(reelOffsets[i]) + j) % symbols.length;
            const y = 160 + j * 60 - (reelOffsets[i] % 1) * 60;
            ctx.fillText(symbols[index], 180 + i * 150, y);
        }
    }
}
        

drawScene関数は、リールを描く部分だよ。まず、キャンバスの背景を描いて(白い枠とピンクの内側)、3つのリールをループで描いてるんだ。リールは灰色のボックス(ctx.fillRect)で、絵柄(ctx.fillText)をその中に表示してるよ。絵柄の位置(y)は、reelOffsetsを使って滑らかに動くように計算してるんだ。これで、リールがくるくる回るアニメーションができるよ!

リールの回転と結果判定

function updateGame() {
    if (gameState === 'spinning') {
        for (let i = 0; i < 3; i++) {
            if (spinning[i]) {
                reelOffsets[i] += 0.3;
                if (reelOffsets[i] >= symbols.length) {
                    reelOffsets[i] -= symbols.length;
                }
            }
        }
        if (keys['KeyS']) {
            spinning[0] = false;
            stopButton1.style.display = 'none';
            checkAllStopped();
        }
        ...
    }
}
        

updateGame関数は、ゲームの状態を更新するよ。リールが回っているとき(gameState === 'spinning')、reelOffsetsを少しずつ増やして、リールを回転させてるんだ。プレイヤーが「S」「D」「F」キーを押すと、対応するリールを止めて(spinning[i] = false)、checkAllStoppedで結果を判定するよ。

function checkAllStopped() {
    if (!spinning[0] && !spinning[1] && !spinning[2]) {
        gameState = 'result';
        spinTimer = 0;

        for (let i = 0; i < 3; i++) {
            const index = Math.floor(reelOffsets[i]) % symbols.length;
            reels[i] = [symbols[index]];
        }

        points -= bet;
        let win = 0;
        if (reels[0][0] === reels[1][0] && reels[1][0] === reels[2][0]) {
            if (reels[0][0] === '7️⃣') {
                win = bet * 50;
                ...
            } else if (reels[0][0] === '💎') {
                win = bet * 20;
                ...
            } else {
                win = bet * 10;
                ...
            }
            points += win;
        }
        if (points > highScore) highScore = points;
        document.getElementById('points').textContent = points;
        document.getElementById('highScore').textContent = highScore;

        if (points <= 0) {
            gameState = 'gameOver';
        }
    }
}
        

checkAllStoppedは、3つのリールが全部止まったときに結果を判定するよ。まず、現在の絵柄(reels)を確定させて、賭け金をポイントから引くんだ。絵柄が揃ってたら(reels[0][0] === reels[1][0])、絵柄に応じてポイントを増やすよ。例えば、「7️⃣」が揃うと賭け金の50倍、「💎」だと20倍だよ。ポイントが0以下になったら、ゲームオーバーに移行するんだ。

🔊 上級編:音声の実装方法

このスロットゲームに、もっと臨場感を出すために音声を追加してみよう!ここでは、Web Speech APIのSpeechSynthesisを使って、ボタンを押したときや結果が出たときに声を出す方法を教えるよ。初心者でも簡単にできるから、安心してね!

音声合成の基本

ブラウザには、テキストを読み上げる機能が標準で備わってるんだ。それがSpeechSynthesisだよ。モダンブラウザ(Chrome、Firefox、Edgeなど)で使える便利な機能だよ。まずは、簡単な関数を作ってみよう:

function speak(text, pitch = 1, rate = 1, volume = 1) {
    const utterance = new SpeechSynthesisUtterance(text);
    utterance.lang = 'ja-JP';
    utterance.pitch = pitch;
    utterance.rate = rate;
    utterance.volume = volume;
    window.speechSynthesis.speak(utterance);
}
        

このspeak関数は、指定したテキストを読み上げるよ。引数で以下の設定ができるんだ:

utterance.lang = 'ja-JP'で日本語に設定してるから、日本語のボイスで読み上げてくれるよ。ブラウザやデバイスによって声の種類が違うけど、だいたい自然な感じになるんだ。

音声をゲームに組み込む

それじゃ、このspeak関数を使って、ゲームに音声を追加してみよう!まずは、ボタンを押したときに「カチッ」と鳴らすよ。以下のコードを、ボタンのイベントリスナーに追加するんだ:

startButton.addEventListener('click', () => {
    if (gameState === 'start' && points >= bet) {
        gameState = 'spinning';
        spinning = [true, true, true];
        leverMoving = true;
        startButton.style.display = 'none';
        stopButton1.style.display = 'inline-block';
        stopButton2.style.display = 'inline-block';
        stopButton3.style.display = 'inline-block';
        speak('カチッ', 1.5, 2, 1); // 追加!
    }
});
        

「スタート」ボタンを押したときに、speak('カチッ', 1.5, 2, 1)を追加したよ。声の高さ(pitch: 1.5)を少し高くして、速度(rate: 2)を速くしてるから、クリック音っぽい感じになるんだ。音量(volume: 1)は最大にしてるよ。

同じように、ストップボタンにも追加しよう:

stopButton1.addEventListener('click', () => {
    if (gameState === 'spinning') {
        spinning[0] = false;
        stopButton1.style.display = 'none';
        speak('カチッ', 1.5, 2, 1); // 追加!
        checkAllStopped();
    }
});
        

ストップボタンにも「カチッ」を追加したよ。リールを止めるたびに音が鳴るから、操作感がグッと上がるんだ!

結果に応じた音声を追加

次は、結果に応じて音声を出すよ。絵柄が揃ったときやハズレたときに、声を出すとゲームがもっと楽しくなるよね!checkAllStopped関数に追加してみよう:

function checkAllStopped() {
    if (!spinning[0] && !spinning[1] && !spinning[2]) {
        gameState = 'result';
        spinTimer = 0;

        for (let i = 0; i < 3; i++) {
            const index = Math.floor(reelOffsets[i]) % symbols.length;
            reels[i] = [symbols[index]];
        }

        points -= bet;
        let win = 0;
        if (reels[0][0] === reels[1][0] && reels[1][0] === reels[2][0]) {
            if (reels[0][0] === '7️⃣') {
                win = bet * 50;
                speak('大当たりー', 1.2, 1, 1); // 追加!
                ...
            } else if (reels[0][0] === '💎') {
                win = bet * 20;
                speak('当たりー', 1.2, 1, 1); // 追加!
                ...
            } else {
                win = bet * 10;
                speak('当たりー', 1.2, 1, 1); // 追加!
                ...
            }
            points += win;
        } else {
            speak('ハズレ', 0.9, 1, 1); // 追加!
        }
        ...
    }
}
        

絵柄が揃ったときは「当たりー」か「大当たりー」を読み上げるよ。声の高さ(pitch: 1.2)を少し高くして、明るい感じにしてるんだ。ハズレたときは「ハズレ」を、少し低い声(pitch: 0.9)で読み上げて、残念な雰囲気を出すよ。こうやって、結果に応じた音声を追加すると、プレイヤーがもっとゲームに引き込まれるんだ!

音声の実装の注意点

音声合成を使うとき、いくつか気をつけることがあるよ:

音声を追加することで、ゲームがもっと生き生きするよ!試してみて、どんな感じか教えてね!🎤

🔗 リンク