iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 12
0
Software Development

用Canvas打造自己的遊樂場系列 第 12

[Day12]用Canvas打造自己的遊樂場-BB 消滅磚塊

  • 分享至 

  • xImage
  •  

今天的目標是要能夠完成消磚塊的動作,明天做個收尾,第一個遊戲就結束啦~~~

好的,那麼今天我們要寫的球與磚的互動,按照我們的分類,需要寫在move中,裡面目前有球本身的移動,還有paddle與球的互動,如果我們直接把磚塊的互動加進去,會變得很複雜,不方便除錯.所以今天的第一件事情是把動作分成不同的function.
這邊是目前的code

// 負責處理動作
move = () => {
    ball_x += ball_speed_x;
    ball_y += ball_speed_y;

    // 碰觸邊界動作
    if (ball_x < (0 + ball_r)) {
        ball_speed_x *= -1;
    }
    if (ball_x > (canvas.width - ball_r)) {
        ball_speed_x *= -1;
    }
    if (ball_y < (LIFE_SIZE + ball_r)) {
        ball_speed_y *= -1;
    }
    if (ball_y > canvas.height) {
        resetBall();
        chance -= 1;

        if (chance < 0) {
            chance = 3;
        }
    }

    // 定義paddle四個角的座標
    var paddleTopEdgeY = canvas.height - PADDLE_HEIGHT - PADDLE_HIGH;
    var paddleBottomEdgeY = paddleTopEdgeY + PADDLE_HEIGHT;
    var paddleLeftEdgeX = paddle_x;
    var paddleRightEdgeX = paddleLeftEdgeX + PADDLE_WIDTH;


    // 碰到paddle反彈
    if (ball_y > (paddleTopEdgeY - ball_r) &&
        ball_y < paddleBottomEdgeY &&
        ball_x > paddleLeftEdgeX &&
        ball_x < paddleRightEdgeX) {

            // 加速
            ball_speed += 0.5;

            // paddle中心
            var centerOfPaddleX = paddle_x + PADDLE_WIDTH / 2;

            // 計算X軸球速
            ball_speed_x = ball_speed * ((ball_x - centerOfPaddleX) / (0.51 * PADDLE_WIDTH));

            // 計算Y軸球速
            ball_speed_y = -1 * countBallSpeedY(ball_speed, ball_speed_x);
    }
}

我們先改成

// 負責處理動作
move = () => {

    // 處理球的動作
    moveBall()

    // paddle互動
    actionPaddle()

}

// 球移動
moveBall = () => {
    ball_x += ball_speed_x;
    ball_y += ball_speed_y;

    // 碰觸邊界動作
    if (ball_x < (0 + ball_r)) {
        ball_speed_x *= -1;
    }
    if (ball_x > (canvas.width - ball_r)) {
        ball_speed_x *= -1;
    }
    if (ball_y < (LIFE_SIZE + ball_r)) {
        ball_speed_y *= -1;
    }
    if (ball_y > canvas.height) {
        resetBall();
        chance -= 1;

        if (chance < 0) {
            chance = 3;
        }
    }
}

// paddle互動
actionPaddle = () => {
    // 定義paddle四個角的座標
    var paddleTopEdgeY = canvas.height - PADDLE_HEIGHT - PADDLE_HIGH;
    var paddleBottomEdgeY = paddleTopEdgeY + PADDLE_HEIGHT;
    var paddleLeftEdgeX = paddle_x;
    var paddleRightEdgeX = paddleLeftEdgeX + PADDLE_WIDTH;

    // 碰到paddle反彈
    if (ball_y > (paddleTopEdgeY - ball_r) &&
        ball_y < paddleBottomEdgeY &&
        ball_x > paddleLeftEdgeX &&
        ball_x < paddleRightEdgeX) {

        // 加速
        ball_speed += 0.5;

        // paddle中心
        var centerOfPaddleX = paddle_x + PADDLE_WIDTH / 2;

        // 計算X軸球速
        ball_speed_x = ball_speed * ((ball_x - centerOfPaddleX) / (0.51 * PADDLE_WIDTH));

        // 計算Y軸球速
        ball_speed_y = -1 * countBallSpeedY(ball_speed, ball_speed_x);
    }
}

好的,到這裡需要先測試一下是否能正常運作,以免要是等等加入新程式時會難以除錯.

正常執行的話我們要來說明一下等等如何處理球碰到磚塊的狀態,說明流程後看code就很容易了.

昨天結束時,我們用陣列畫出了方塊,那判斷球有沒有碰到磚塊的方式就是將球的座標,轉換到磚塊的矩陣中,然後確定對應的陣列位置是否有磚塊.如果對應到的位置是有磚塊的,就需要處理碰撞的動作.
好的~我們先寫出上述敘述的程式吧.
首先先寫個判斷對應位置磚塊是否存在的函式.

//確認磚塊是不是存在
isBrickExist = ( col, row ) => {
    if (col >= 0 && col < BRICK_COLS &&
        row >= 0 && row < BRICK_ROWS) {
        var brickIndexUnderCoord = rowColToArrayIndex(col, row);
        return brick_grid[brickIndexUnderCoord];
    } else {
        return false;
    }
}

接下來就是球與磚的互動了

 // 碰到磚的動作
actionBrick = () => {
    // 球的座標轉換成磚塊的陣列位置
    var ballBrickCol = Math.floor(ball_x / BRICK_WIDTH);
    var ballBrickRow = Math.floor(ball_y / BRICK_HEIGHT);
    var brickIndexUnderBall = rowColToArrayIndex(ballBrickCol, ballBrickRow);

    // 判斷球的位置是否在我們設計有磚塊的區域內
    if (ballBrickCol >= 0 && ballBrickCol < BRICK_COLS &&
        ballBrickRow >= 0 && ballBrickRow < BRICK_ROWS) {
            // 確認該位置的磚塊在不在
            if (isBrickExist(ballBrickCol, ballBrickRow)){

            }
        }
}

到這邊寫完了觸發碰撞動作的條件,在開始寫碰撞動作前來介紹一下碰撞的種類.

分為三種:側邊撞擊、上下面的撞擊還有撞在角的位置

前兩種都好判斷及處理,第三種的處理方式就是X軸速度及Y軸速度都完全相反.那判別的方式就是非前兩種情況的撞擊,都算在這一類.

可能有點說明不太清楚,我們配合程式碼看吧

// 確認該位置的磚塊在不在
if (isBrickExist(ballBrickCol, ballBrickRow)) {
    // 消除方塊
    brick_grid[brickIndexUnderBall] = false;

    // 剩餘磚塊的數量減一
    bricks_left--;

    // 方便判斷撞擊位置的參數
    var prevBallX = ball_x - ball_speed_x;
    var prevBallY = ball_y - ball_speed_y;
    var prevBrickCol = Math.floor(prevBallX / BRICK_WIDTH);
    var prevBrickRow = Math.floor(prevBallY / BRICK_HEIGHT);

    // 預設非側邊或上下面撞擊
    var bothTestFailed = true;

    // 側邊撞擊
    if (prevBrickCol != ballBrickCol) {

        if (isBrickExist(ballBrickCol, ballBrickRow) == false) {
            ball_speed_x *= -1;
            bothTestFailed = false;
        }
    }

    // 上下面撞擊
    if (prevBrickRow != ballBrickRow) {

        if (isBrickExist(ballBrickCol, ballBrickRow) == false) {
            ball_speed_y *= -1;
            bothTestFailed = false;
        }
    }

    // 撞到角的情況
    if (bothTestFailed) {
        ball_speed_x *= -1;
        ball_speed_y *= -1;
    }
}

最後在move中加入

// 負責處理動作
move = () => {

    // 處理球的動作
    moveBall()

    // paddle互動
    actionPaddle()

    // 磚互動
    actionBrick()

}

執行後應該會出現這畫面

明天稍微做一些最後的收尾,第一個遊戲就算完成了~~ 今天就不附上全部程式碼啦,明天再放出來。


上一篇
[Day11]用Canvas打造自己的遊樂場-BB 磚塊、陣列、補班日進度少一點
下一篇
[Day13]用Canvas打造自己的遊樂場-BB 收尾
系列文
用Canvas打造自己的遊樂場30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言