怎么用HTML5 Canvas制作一个简单的画布游戏
【译】如何制作一个简单的HTML5画布游戏 作者:Matt Hackett
翻译出处:http://www.lostdecadegames.com/how-to-make-a-simple-html5-canvas-game/
原文作者未做版权声明,视为共享知识产权进入公共领域,自动获得授权。
你期待用HTML5制作一个简单游戏的快速教程吗?让我们实实在在地逐行跟进一个简单的游戏吧!(如果你好奇我的一局,这是我做了一半的巫师的蜥蜴)。我们来直接参阅game.js。你也可以在这里玩游戏。
截图
// Create the canvas
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
canvas.width = 512;
canvas.height = 480;
document.body.appendChild(canvas);
2、嵌入图片
// Background image
var bgReady = false;
var bgImage = new Image();
bgImage.onload = function () {
bgReady = true;
};
bgImage.src = "images/background.png";
一个游戏是需要有图形的,所以让我们来载入一些图片吧!我想做的尽可能的简单毕竟它只是一个图片,而不是封装在一个完整的类或其他的什么之中。bgReady是用来告诉我们何时绘制图像是妥当的,它尝试在它载入之前绘制以抛出一个DOM错误。我们对这三个所需图形中的每一个都这样做:背景, 主人公, 和怪物。
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);
要做到这一点,我们很容易有一个keysDown变量,它将存储任何事件的keyCode。如果一个键码在对象中,就说明用户正在按下该键,如此简单!
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));
};
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功能,它在每一个间隔执行中被调用。它要做的首要事情就是检查上、下、左、右方向键,看看用户是否有按下它们。如果有,主人公就会往相应的方向移动。
似乎有些奇怪的是modifier参数传入update。你可以看到这是如何在main函数中被引用的,但我先在此说明。 modifier 是一个基于时间的数字,单位为1。如果刚好经过了一秒,这个值就是1并且主人公的速度将乘以1,意味着它该秒已经移动了256像素。如果已经过了1/2秒,该值将是0.5且主人公在那个时间量内已经移动到它速度的一半。以此类推。这个函数被调用得如此迅速以至于modifier值一般会非常低,但这种模式会确保主人公将是匀速运动,无论该脚本运行得有多快(或慢!)。
// 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("Monsterrs caught: " + monstersCaught, 32, 32);
};
接下来我们在上下文改变某些关于绘制字体的属性,我们调用fillText来显示玩家的分数。由于我们没有任何复杂的动画或运动,我们的绘制就算大功告成了。
// 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);
};
主游戏循环用来控制游戏的流程。首先我们想获得当前的时间戳之后我们就可以计算增量(自上次间隔经过了多少毫秒)。我们用将它除以1000(一秒钟的毫秒数)并发送到update。我们调用render,并记录时间戳。也可以去看 猛击! 领域案例研究 了解更多关于游戏循环。
// Cross-browser support for requestAnimationFrame
var w = window;
requestAnimationFrame = w.requestAnimationFrame || w.webkitRequestAnimationFrame || w.msRequestAnimationFrame || w.mozRequestAnimationFrame;
别担心,你不必完全理解这一部分,但我认为循环代码的解析也是有益的。为了不断调用main游戏循环函数,本教程执行的是setInterval方法。现在有一个更好的方法,通过requestAnimationFrame方法。然而,与大多数新的网络技术一样,需要一些编码来确保跨浏览器支持。我已收录的polyfill是Paul Irish's article的简化版之一。
// Let's play this game!