BLOG

【簡単ゲームプログラミング】ブロック崩しゲームをつくってみよう!-#2 ボールとパドルを動かそう編-【HTML・CSS・JavaScript】

2024-02-07

■過去回はこちら!
#1:ベースデザインの作成編

どうもロックシステムのみなみです!
ブロック崩しゲームづくり2回目です!

前回の動画ではブロック崩しの見た目を作成しました。
第2回目の今回はボールが跳ね返るようにしたりパドルを動かせるようにしていきます!

今回のポイント

<ボールにアニメーションを実装>

ボールにアニメーションを実装するためにrequestAnimationFrame()を使います!
一般的なブラウザは毎秒約60回再描画を行っており、そのタイミングに被らないよう引数に指定した関数を自動で繰り返し実行してくれます。これによってアニメーション化することが可能になります。
requestAnimationFrame()はJavaScriptでアニメーションを効率的に実装するための関数なのです!


    function start() {
        ballX += ballSpeedX;
        ballY += ballSpeedY;

        ball.style.left = ballX + "px";
        ball.style.top = ballY + "px";
     
        }
        requestAnimationFrame(start);
    }

まずstart関数を用意、requestAnimationFrame()の引数にstart関数を入れます。⇒requestAnimationFrame(start)
そうすることでstart関数が繰り返され、ballspeedX、ballspeedYの値が永遠にCSSに追加されていきます。
これによりボールが動いているように見えます!



<ボールの跳ね返り処理>


        // 衝突検出(左右)
        if (ballX < 0 || ballX + 20 > 600) {
            ballSpeedX = -ballSpeedX;
        }
左右の衝突検出、左はボールの左端が基準となるためボール幅は含めません。
右は右端を検出するためにボール幅20pxを含めます。


        // 衝突検出(上)
        if (ballY < 0) {
            ballSpeedY = -ballSpeedY;
        }
        // 衝突検出(下)
        if (ballY + 20 > 400) {
            return;
        }
上下の衝突検出、上はボールの上端が基準となるためボール幅は含めません。
下は左右の時と同様にボール幅20pxを含めます。
また下に付いた場合はゲームオーバーにするために跳ね返りではなくreturnとします。
return:関数の実行が停止。値を指定している場合、元の位置に返されます。


      // 衝突検出(パドル)
        if (
            // ボールX軸 + ボール幅(20px)でボールの右端がパドルの左端よりも右に位置しているかどうか
            ballX + 20 > paddle.offsetLeft &&

            // ボールX軸 - ボール幅(20px)でボールの左端がパドルの右端よりも左に位置しているかどうか
            ballX - 20 < paddle.offsetLeft + paddle.offsetWidth &&

            // ボールY軸 + ボール幅(20px)でボールの下端がパドルの上端よりも下に位置しているかどうか
            ballY + 20 > paddle.offsetTop &&

            // ボールY軸 - ボール幅(20px)でボールの上端がパドルの下端よりも上に位置しているかどうか
            ballY - 20 < paddle.offsetTop + paddle.offsetHeight
        ) {
            ballSpeedY = -ballSpeedY;
        }
        requestAnimationFrame(start);
    }
ボールがパドルに当たった時に跳ね返る処理。 パドルに当たっているかどうかを検知して、当たったらボールを反転して逆方向に移動するようにしています!


<パドルの操作処理>


    document.addEventListener("mousemove", function(event) {
        const mouseX = event.clientX - gameContainer.getBoundingClientRect().left;
        const paddleX = mouseX - paddle.offsetWidth / 2;
        if (paddleX < 0) {
            paddle.style.left = "0px";
        } else if(paddleX + paddle.offsetWidth > gameContainer.offsetWidth) {
            paddle.style.left = gameContainer.offsetWidth - paddle.offsetWidth + "px";
        } else {
            paddle.style.left = paddleX + "px";
        }
    })
})
addEventListenerの第一引数をmousemoveとして、マウスが動いたときに発生するイベントを書けるようにします!
gameContainerクラスを基準として相対的にパドルの可動範囲、マウスの反応する範囲を制御しました。

今回使用したコードはこちら

・00:32~
JavaScript
今回は、前回作成したJavaScriptファイルにボールの跳ね返りアニメーションとパドルの動作を追加していきました。

document.addEventListener("DOMContentLoaded", function() {
    const gameContainer = document.querySelector(".gameContainer");
    const ball = document.querySelector(".ball");
    const paddle = document.querySelector(".paddle");
    // ブロックの行数
    const blockLine = 4;
    // 1行あたりのブロック数
    const numBlocks = 8;
    // 1行ごとのブロックカラー
    const blockColor = ["yellow", "pink", "red", "blue"];
    for (let i = 0; i < blockLine * numBlocks; i++) {
        const block = document.createElement("div");
        block.classList.add("block");
        gameContainer.appendChild(block);
        const row = Math.floor(i / numBlocks);
        const col = i % numBlocks;
        const colorIndex = row % blockColor.length;
        block.style.top = row * 30 + "px";
        block.style.left = col * 75 + "px";
        block.style.backgroundColor = blockColor[colorIndex];
    }
    let ballX = 500;
    let ballY = 200;
    let ballSpeedX = 2;
    let ballSpeedY = 2;
    start();
    function start() {
        ballX += ballSpeedX;
        ballY += ballSpeedY;
        ball.style.left = ballX + "px";
        ball.style.top = ballY + "px";
        // 衝突検出(左右)
        if (ballX < 0 || ballX + 20 > 600) {
            ballSpeedX = -ballSpeedX;
        }
        // 衝突検出(上)
        if (ballY < 0) {
            ballSpeedY = -ballSpeedY;
        }
        // 衝突検出(下)
        if (ballY + 20 > 400) {
            return;
        }
        // 衝突検出(パドル)
        if (
            ballX + 20 > paddle.offsetLeft &&
            ballX - 20 < paddle.offsetLeft + paddle.offsetWidth &&
            ballY + 20 > paddle.offsetTop &&
            ballY - 20 < paddle.offsetTop + paddle.offsetHeight
        ) {
            ballSpeedY = -ballSpeedY;
        }
        requestAnimationFrame(start);
    }
    document.addEventListener("mousemove", function(event) {
        const mouseX = event.clientX - gameContainer.getBoundingClientRect().left;
        const paddleX = mouseX - paddle.offsetWidth / 2;
        if (paddleX < 0) {
            paddle.style.left = "0px";
        } else if(paddleX + paddle.offsetWidth > gameContainer.offsetWidth) {
            paddle.style.left = gameContainer.offsetWidth - paddle.offsetWidth + "px";
        } else {
            paddle.style.left = paddleX + "px";
        }
    })
})

▼2回目までの完成コードは以下のGoogleドライブからダウンロードできます!https://drive.google.com/file/d/1TZEoLwYdvOeCxQ6_Q60oRot9typMzc7G/view?usp=sharing

株式会社ロックシステム

「ブラック企業をやっつけろ!!」を企業理念にエンジニアが働きやすい環境をつきつめる大阪のシステム開発会社。2014年会社設立以来、残業時間ほぼゼロを達成し、高い従業員還元率でエンジニアファーストな会社としてIT業界に蔓延るブラックなイメージをホワイトに変えられる起爆剤となるべく日々活動中!絶賛エンジニア募集中。