使用JS和Canvas做一個html5小遊戲
這是一個很簡單的html5遊戲,通過學習原博文自己做了些改造,
這是遊戲的截圖:
1.有計算抓住的怪物的數量
2.有背景,英雄,怪物。
第一步:建立html檔案和js檔案
建立一個games資料夾,在資料夾中建立js資料夾,images資料夾,以及index.html。
game.js放在js資料夾中,圖片放在images資料夾中。
html程式碼如下:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>Simple Canvas Game</title> </head> <body> <script src="js/game.js"></script> </body> </html>
第二步:如何製作這樣一個遊戲
我們首先要明白遊戲的流程是怎樣的。這個遊戲十分簡單,只是簡單的抓怪獸,玩家通過操縱鍵盤的上下左右來讓英雄移動從而抓怪獸,然後記錄得分。
我們需要一個遊戲環境和角色來讓玩家操作
1.首先我們用canvas來建立一個畫布作為遊戲的舞臺。
通過canvas標籤建立元素,然後我們設定畫布的寬度高度,之後讓畫布新增到頁面上。
var canvas = document.createElement("canvas"); var ctx = canvas.getContext("2d"); canvas.width = 512; canvas.height = 480; document.body.appendChild(canvas);
2.然後我們新增相應的圖片(背景,英雄,怪物)
只是簡單的建立圖片物件,而beReady這個變數是用來標識圖片是否載入完成。
// Background image var bgReady = false; var bgImage = new Image(); bgImage.onload = function () { bgReady = true; }; bgImage.src = "images/background.png"; // Hero image var heroReady = false; var heroImage = new Image(); heroImage.onload = function () { heroReady = true; }; heroImage.src = "images/hero.png"; // Monster image var monsterReady = false; var monsterImage = new Image(); monsterImage.onload = function () { monsterReady = true; }; monsterImage.src = "images/monster.png";
3.新增英雄,怪物,記錄分數的變數
資源都載入完成後,我們就構造英雄怪物的物件,因為遊戲很簡單,所以怪物靜止不動只需要隨機重新整理位置,而英雄只需要一個速度屬性就好了,而分數一開始為0。
// Game objects
var hero = {
speed: 256 // movement in pixels per second
};
var monster = {};
var monstersCaught = 0;
4.獲取使用者的輸入
因為在前端開發中,一般是使用者觸發了點選事件然後才去執行動畫或發起非同步請求之類的,但這裡希望遊戲的邏輯能夠更加緊湊同時又要及時響應輸入。所以我們就把使用者的輸入先儲存下來而不是立即響應。為此,用keysDown
這個物件來儲存使用者按下的鍵值(keyCode
),如果按下的鍵值在這個物件裡,那麼就做相應處理。
預設是鍵盤輸入,所以我們監聽keysdown和keysup。
// Handle keyboard controls
var keysDown = {};
addEventListener("keydown", function (e) {
keysDown[e.keyCode] = true;
}, false);
addEventListener("keyup", function (e) {
delete keysDown[e.keyCode];
}, false);
5.開始一輪遊戲
reset方法用於開始新一輪遊戲,在這個方法裡我們將英雄放回畫布的中心同時將怪物放到一個隨機的地方。
// 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));
};
6.更新物件
用於更新畫面的update函式,會被規律的重複呼叫。首先它檢查使用者當前按住的是不是方向鍵,然後再讓英雄朝英雄相應方向移動。這個傳入的modifier
變數是基於1開始且隨時間變化的一個因子。例如1秒過去了,它的值就是1,英雄的速度將會乘以1,也就是每秒移動256畫素;如果半秒鐘則它的值為0.5,英雄的速度就乘以0.5也就是說這半秒內英雄以正常速度一半的速度移動。理論上說因為這個update
方法被呼叫的非常快且頻繁,所以modifier
的值會很小,但有了這一因子後,不管我們的程式碼跑得快慢,都能夠保證英雄的移動速度是恆定的。
// 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();
}
};
7.渲染物體
首先把背景畫出來,然後如法炮製把英雄和怪物也畫出來,順序有講究不然後面的物體會覆蓋之前的物體。
之後我們通過canvas的相關屬性改變記分牌。
// 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("抓住的怪物: " + monstersCaught, 10, 10);
};
8.主迴圈函式
主函式控制整個遊戲的流程,先是拿到當前的時間用來計算時間差(距離上次主函式被呼叫時過了多少毫秒)。得到modifier
後除以1000(也就是1秒中的毫秒數)再傳入update
函式。最後呼叫render
函式並且將本次的時間儲存下來。
// The main game loop
var main = function () {
var now = Date.now();
var delta = now - then;
update(delta / 1000);
render();
then = now;
// Request to do this again ASAP
requestAnimationFrame(main);
};
因為運用的是requestAnimationFrame,所以我們要注意瀏覽器相容性處理。
// Cross-browser support for requestAnimationFrame
var w = window;
requestAnimationFrame = w.requestAnimationFrame || w.webkitRequestAnimationFrame || w.msRequestAnimationFrame || w.mozRequestAnimationFrame;
9.我們就可以在瀏覽器啟動遊戲了
先是設定一個初始的時間變數then
用於首先執行main
函式使用。然後呼叫 reset
函式來開始新一輪遊戲
// Let's play this game!
var then = Date.now();
reset();
main();