1. 程式人生 > >怎樣用HTML5 Canvas製作一個簡單的遊戲

怎樣用HTML5 Canvas製作一個簡單的遊戲

原文連線:How To Make A Simple HTML5 Canvas Game

自從我製作了一些HTML5遊戲(例如Crypt Run)後,我收到了很多建議,要求我寫一篇關於怎樣利用HTML5 Canvas製作遊戲的入門教程。花了一點時間考慮怎麼著手寫這篇文章後,我決定先實現一個我覺得最最簡單的遊戲,然後一行程式碼一行程式碼地進行講解。

讓我們開始吧,首先看看game.js,當然你也可以先玩玩這個遊戲(譯註:附件是遊戲原始碼,用瀏覽器開啟其中的index.html就可以玩了,或者也可以到lostdecadegames官網上去玩)。

附件下載地址:simple_canvas_game



1. 建立一個Canvas物件


// Create the canvas
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
canvas.width = 512;
canvas.height = 480;
document.body.appendChild(canvas);

我們首先要做的是建立一個canvas物件。可以用JavaScript或HTML來做,都非常簡單。此處我用的是JS。當建立了canvas之後,我們就可以獲取它的上下文物件(context)、設定尺寸,並且把它加到當前文件中。

2. 載入圖片

// Background image
var bgReady = false;
var bgImage = new Image();
bgImage.onload = function () {
    bgReady = true;
};
bgImage.src = "images/background.png";

遊戲需要影象,所以讓我們載入一些圖片吧。我想盡量簡單化,所以只用了Image物件來做,當然,還可以將載入影象的功能封裝成一個類或別的任何形式。程式碼中的bgReady用來標識圖片是否已完全載入,只有當圖片載入完成後,我們才能使用它,如果在載入完成前就對其進行繪製或渲染,JS將會報一個DOM error的錯誤。

我們會用到三張圖片(背景、英雄、怪物),每張圖片都需要這樣處理。

3. 定義遊戲要使用的物件

// Game objects
var hero = {
    speed: 256, // movement in pixels per second
    x: 0,
    y: 0
};
var monster = {
    x: 0,
    y: 0
};
var monstersCaught = 0;

定義一些變數,稍後會用到。hero物件的speed屬性表示英雄的移動速度(畫素/秒);monster物件不會移動,所以僅僅具有一對座標;monstersCaught表示玩家抓住的怪物數量。

4. 處理玩家輸入

// Handle keyboard controls
var keysDown = {};
addEventListener("keydown", function (e) {
     keysDown[e.keyCode] = true;
}, false);
addEventListener("keyup", function (e) {
     delete keysDown[e.keyCode];
}, false);

現在進行輸入的處理。(對具有web開發背景的人來說,這是目前為止第一個具有挑戰性的部分)對一般的網頁來說,當用戶開始輸入時,可能需要馬上開始播放動畫或請求資料。但在這裡,我們想讓遊戲邏輯在一個單獨的地方對遊戲中發生的事情進行處理。為此我們需要將使用者輸入儲存下來以備稍後處理,而不是立即處理。
我們通過簡單地將事件對應的鍵編碼(keyCode)儲存在keysDown變數中來實現。如果該變數中具有某個鍵編碼,就表示使用者目前正按下這個鍵。簡單吧!

5. 新遊戲

// Reset the game when the player catches a monster
var reset = function () {
     hero.x = canvas.width / 2;
     hero.y = canvas.height / 2;

     // Throw the monster somewhere on the screen randomly
     monster.x = 32 + (Math.random() * (canvas.width - 64));
     monster.y = 32 + (Math.random() * (canvas.height - 64));
};

通過呼叫reset函式來開始新遊戲。該函式將英雄(即玩家角色)放到螢幕中間,然後隨機選擇一個位置來安置怪物。

6. 更新物件

// Update game objects
var update = function (modifier) {
    if (38 in keysDown) { // Player holding up
        hero.y -= hero.speed * modifier;
    }
    if (40 in keysDown) { // Player holding down
        hero.y += hero.speed * modifier;
    }
    if (37 in keysDown) { // Player holding left
        hero.x -= hero.speed * modifier;
    }
    if (39 in keysDown) { // Player holding right
        hero.x += hero.speed * modifier;
    }

    // Are they touching?
    if (
        hero.x <= (monster.x + 32)
            && monster.x <= (hero.x + 32)
            && hero.y <= (monster.y + 32)
            && monster.y <= (hero.y + 32)
    ) {
         ++monstersCaught;
         reset();
    }
};

這是update函式,遊戲每隔一定時間會呼叫它一次。它所做的第一件事情是檢查使用者是否按下了上下左右四個箭頭鍵。如果是,就將我們的英雄向相應的方向移動。

update有一個modifier引數,這看起來好像有點奇怪。你會在遊戲的主函式即main函式中看到它,不過我在這兒先解釋一下。modifier引數是一個從1開始的與時間相關的數。如果間隔剛好為1秒時,它的值就會為1,英雄移動的距離即為256畫素(英雄的速度為256畫素/秒);而如果間隔是0.5秒,它的值就為0.5,即英雄移動的距離為其速度的一半,以此類推。通常update函式呼叫的間隔很短,所以modifier的值很小,但用這種方式能夠確保不管程式碼執行的速度怎麼樣,英雄的移動速度都是相同的。

我們已經實現了根據使用者的輸入來移動英雄,但我們還可以在移動英雄時對其進行檢查,以確定是否有其他事件發生。例如:英雄是否與怪物發生了碰撞——當英雄與怪物發生碰撞時,我們為玩家進行計分(monstersCaught加1)並重置遊戲(呼叫reset函式)。

7. 渲染物件

// Draw everything
var render = function () {
    if (bgReady) {
         ctx.drawImage(bgImage, 0, 0);
    }

    if (heroReady) {
         ctx.drawImage(heroImage, hero.x, hero.y);
    }

    if (monsterReady) {
         ctx.drawImage(monsterImage, monster.x, monster.y);
    }

    // Score
    ctx.fillStyle = "rgb(250, 250, 250)";
    ctx.font = "24px Helvetica";
    ctx.textAlign = "left";
    ctx.textBaseline = "top";
    ctx.fillText("Goblins caught: " + monstersCaught, 32, 32);
};

當你能夠看到你的行動時遊戲才會變得更有趣,所以讓我們在螢幕上繪製吧。首先我們將背景圖片繪製到canvas,然後是英雄和怪物。注意順序很重要,因為任何位於表層的圖片都會將其下面的畫素覆蓋掉。

接下來是文字,這有些不同,我們呼叫fillText函式顯示玩家的分數。因為不需要複雜的動畫或者對文字進行移動,所以只是繪製一下就ok了。

8. 遊戲主迴圈

// The main game loop
var main = function () {
    var now = Date.now();
    var delta = now - then;

    update(delta / 1000);
    render();

    then = now;
};

遊戲的主迴圈用來控制遊戲流程。首先我們要獲得當前的時間,這樣我們才能計算時間差(自上次迴圈以來經過的時間)。然後計算modifier的值並交給update(需要將delta除以1000以將其轉換為毫秒)。最後呼叫render並更新記錄的時間。



9. 開始遊戲吧

// Let's play this game!
reset();
var then = Date.now();
setInterval(main, 1); // Execute as fast as possible

快完成了,這是最後一段程式碼。首先呼叫reset來開始新遊戲。(還記得嗎,這會將英雄置中並隨機安放怪物)。然後將起始時間儲存到變數then中並啟動遊戲的主迴圈。

OK!(但願)你現在已經理解了在HTML5 Canvas中用JS來開發遊戲的基礎知識了。建議最好是能夠自己親自試一把!