iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 7
0
Software Development

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

[Day07]用Canvas打造自己的遊樂場-BB 補一下我的開發環境、彈跳、分割[]

  • 分享至 

  • xImage
  •  

突然發現前面雖然有提到,這次的程式是在HTML檔案中寫JS,但我沒有提過自己的開發環境以及如何執行程式,這邊就簡單補充一下握個人的習慣.

我自己常用的程式語言大概就三種,JS、Python以及Java,那我個人的習慣是會區分使用的IDE,Python我都使用PyCharm;Java使用IntelliJ;有關前端開發的我使用VSCode,這樣的區分是按我個人習慣.

如何執行這次撰寫的遊戲檔案呢,我這邊提供一種方法,方法有很多種,但我覺得找到一種自己覺得方便的即可.我自己常用的,是在VSCode中安裝Preview on Web Server,想做畫面測試時,點選右鍵選擇Launch on browser會直接以瀏覽器開啟,我比較常使用這方法,因為我習慣會搭配瀏覽器的開發者工具來看.

以上是我補充我自己開發時使用的工具.

拉回到遊戲內容,昨天的進度是到了畫面上呈現了一個紅磚還有小白球,並且小白球會移動了,只是目前會任性地離場.今天我們就先來解決這問題,教會小白球在規定的範圍內移動.

我們先專注於球的移動,所以先把紅磚給移除,為了後面操作上好做修改,我們把球的移動速度寫為兩個維度的變數ball_speed_x以及ball_speed_y.目前的code是這樣:

<script>
    var canvas, canvasContext;

    //球的參數
    var ball_x = 300;
    var ball_y = 300;
    var ball_speed_x = 5;
    var ball_speed_y = 5;

    window.onload = () => {

        canvas = document.getElementById('playground');
        canvasContext = canvas.getContext('2d');

        //一秒更新幾次畫面
        var timesPerSec = 30;
        setInterval(drawAll, 1000/timesPerSec);
    }

    // 負責繪製畫面
    drawAll = () => {
        // background
        canvasContext.fillStyle = 'black';
        canvasContext.fillRect(0, 0, canvas.width, canvas.height);

        ball_x += ball_speed_x;
        ball_y += ball_speed_y;

        canvasContext.fillStyle = 'white';
        canvasContext.beginPath();
        canvasContext.arc(ball_x, ball_y, 10, 0, Math.PI * 2);
        canvasContext.fill();

    }
</script>

好的,那麼我們先想一下白球的移動方式,先不考慮球低於畫面底部時GG的情況,正常球的移動是若球碰壁即反彈,一次只改變一種維度的速度,什麼意思??? 比如說球往右下移動,先碰到了右側邊界,那改變的會是ball_speed_x水平方向速度要往反方向改變,垂直方向ball_speed_y則保持不變.我們就按照這邏輯來寫一下觸動四個邊界時的動作.

drawAll = () => {
    // background
    canvasContext.fillStyle = 'black';
    canvasContext.fillRect(0, 0, canvas.width, canvas.height);

    ball_x += ball_speed_x;
    ball_y += ball_speed_y;

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

    canvasContext.fillStyle = 'white';
    canvasContext.beginPath();
    canvasContext.arc(ball_x, ball_y, 10, 0, Math.PI * 2);
    canvasContext.fill();
}

執行後會看到上面畫面,球在碰觸邊界後會反彈,只是有一個問題,因為球碰觸邊界的判斷我們是以球心作為判斷依據,這樣讓球在碰壁時,看起來會先埋一半在邊界外才反彈,我不太喜歡這樣的視覺效果,來做個小修改.先把球的半徑也以參數表示ball_r,在考量碰觸邊界時的距離也把球的半徑考量在內,如下程式,就可以解決這問題.

<script>
    var canvas, canvasContext;

    //球的參數
    var ball_x = 300;
    var ball_y = 300;
    var ball_r = 10;
    var ball_speed_x = 5;
    var ball_speed_y = 5;

    window.onload = () => {

        canvas = document.getElementById('playground');
        canvasContext = canvas.getContext('2d');

        //一秒更新幾次畫面
        var timesPerSec = 30;
        setInterval(drawAll, 1000/timesPerSec);
    }

    // 負責繪製畫面
    drawAll = () => {
        // background
        canvasContext.fillStyle = 'black';
        canvasContext.fillRect(0, 0, canvas.width, canvas.height);

        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 < (0 + ball_r)) {
            ball_speed_y *= -1;
        }
        if(ball_y > (canvas.height - ball_r)) {
            ball_speed_y *= -1;
        }

        canvasContext.fillStyle = 'white';
        canvasContext.beginPath();
        canvasContext.arc(ball_x, ball_y, ball_r, 0, Math.PI * 2);
        canvasContext.fill();

    }
</script>

到了這邊,我們完成了球的移動還有反彈,目前只寫了球跟邊界的互動,drawall就已經不少行了,可以預見如果我們用這方法寫下去,加入玩家操作的橫版以及磚塊後,程式碼一定超級長,這樣會導致除錯不易.趁問題更大之前,先來拆解我們的程式吧!!

我們把drawall拆為兩部分:畫圖的都放到draw,處理移動的都放到move.

修改完成後就完成了今天的內容,處理球碰觸邊界的反彈,還有為了後續容易修改程式或除錯,進行分割.
以下附上完整程式碼:

<!DOCTYPE html>
<html lang="en">

<head>
    <title>First Game</title>
    <meta name="description" content="第一個遊戲">
    <meta content="text/html;charset=utf-8" http-equiv="Content-Type">
    <meta content="utf-8" http-equiv="encoding">
</head>

<body>
    <canvas id="playground" width="800" height="630"></canvas>
    <script>
        var canvas, canvasContext;

        //球的參數
        var ball_x = 300;
        var ball_y = 300;
        var ball_r = 10;
        var ball_speed_x = 5;
        var ball_speed_y = 5;

        window.onload = () => {

            canvas = document.getElementById('playground');
            canvasContext = canvas.getContext('2d');

            //一秒更新幾次畫面
            var timesPerSec = 30;
            setInterval(drawAll, 1000 / timesPerSec);
        }

        // 負責更新畫面
        drawAll = () => {
            move();
            draw();
        }

        // 負責畫畫
        draw = () => {
            // background
            canvasContext.fillStyle = 'black';
            canvasContext.fillRect(0, 0, canvas.width, canvas.height);
        
            // 畫球
            canvasContext.fillStyle = 'white';
            canvasContext.beginPath();
            canvasContext.arc(ball_x, ball_y, ball_r, 0, Math.PI * 2);
            canvasContext.fill();
        }

        // 負責處理動作
        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 < (0 + ball_r)) {
                ball_speed_y *= -1;
            }
            if (ball_y > (canvas.height - ball_r)) {
                ball_speed_y *= -1;
            }
        }

    </script>
</body>

</html>

上一篇
[Day06]用Canvas打造自己的遊樂場-BB 開工
下一篇
[Day08]用Canvas打造自己的遊樂場-BB 彈跳版、元件化、重置
系列文
用Canvas打造自己的遊樂場30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言