怎么用HTML5 Canvas制作一个简单的画布游戏

发表于2016-02-21
评论2 2.2k浏览

【译】如何制作一个简单的HTML5画布游戏 作者:Matt Hackett

翻译出处:http://www.lostdecadegames.com/how-to-make-a-simple-html5-canvas-game/

原文作者未做版权声明,视为共享知识产权进入公共领域,自动获得授权。


  你期待用HTML5制作一个简单游戏的快速教程吗?让我们实实在在地逐行跟进一个简单的游戏吧!(如果你好奇我的一局,这是我做了一半的巫师的蜥蜴)。我们来直接参阅game.js。你也可以在这里玩游戏

  截图

 

1、创建画布

// 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,用来演示它是如何轻松做到的。一旦我们创建了元素,我们就得到了它的上下文,是我们用来发出绘图命令的参考。然后,我们设置它的尺寸,并将其添加到正文,它就会出现在页面了。

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);

  现在对于输入处理。(这可能是最初都会困扰每个来自web开发背景的开发者的部分。)在网络堆栈中,也许适合让用户发起输入随即开始一个动画或请求数据。但在这个流程中,我们希望我们的游戏逻辑是动态的单独在一个地方,如果发生了事件能保持严格的控制。出于这个原因,我们所想的是存储用户的输入过后使用而不是即输即用。
要做到这一点,我们很容易有一个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));

};

  这个 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功能,它在每一个间隔执行中被调用。它要做的首要事情就是检查上、下、左、右方向键,看看用户是否有按下它们。如果有,主人公就会往相应的方向移动。

  似乎有些奇怪的是modifier参数传入update。你可以看到这是如何在main函数中被引用的,但我先在此说明。 modifier 是一个基于时间的数字,单位为1。如果刚好经过了一秒,这个值就是1并且主人公的速度将乘以1,意味着它该秒已经移动了256像素。如果已经过了1/2秒,该值将是0.5且主人公在那个时间量内已经移动到它速度的一半。以此类推。这个函数被调用得如此迅速以至于modifier值一般会非常低,但这种模式会确保主人公将是匀速运动,无论该脚本运行得有多快(或慢!)。

  现在我们已经根据玩家输入来移动主人公,我们可以检查看看它会导致什么发生。如果有主人公与怪物的撞击,就对了!这几乎就是这个游戏的精髓。我们就统计分数(+1到monstersCaught)并且重置游戏。

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("Monsterrs caught: " + monstersCaught, 32, 32);

};

  当你能看到操作产生功效,游戏将更有趣,所以我们都画到屏幕上去吧。首先我们拿到背景图像并把它画到canvas。重复的操作,画上主人公和怪物。N注意顺序很重要,因为任何画到canvas 的图像都画在它下面的像素之上ote that the order is important, as any image drawn to the canvas will draw over the pixels under it。

  接下来我们在上下文改变某些关于绘制字体的属性,我们调用fillText来显示玩家的分数。由于我们没有任何复杂的动画或运动,我们的绘制就算大功告成了。


8、主游戏循环

// 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,并记录时间戳。也可以去看 猛击! 领域案例研究 了解更多关于游戏循环。


9、有关循环的注意事项

// Cross-browser support for requestAnimationFrame

var w = window;

requestAnimationFrame = w.requestAnimationFrame || w.webkitRequestAnimationFrame || w.msRequestAnimationFrame || w.mozRequestAnimationFrame;

  别担心,你不必完全理解这一部分,但我认为循环代码的解析也是有益的。为了不断调用main游戏循环函数,本教程执行的是setInterval方法。现在有一个更好的方法,通过requestAnimationFrame方法。然而,与大多数新的网络技术一样,需要一些编码来确保跨浏览器支持。我已收录的polyfillPaul Irish's article的简化版之一。


10、开始游戏!

// Let's play this game!

var then = Date.now();

reset();

main();

  大概都在这里了,这是最后的代码片段!首先我们设定时间戳(用变量then)来预备。然后我们调用reset开始新的游戏/标准。(请记住把主人公放中间,把怪物随机放置,让玩家去找怪物。)

  恭喜你!你现在了解了在JavaScript中使用canvas元素进行游戏开发的基本原理(我希望如此!)。请你自己尝试一下: 玩一下这个游戏或 fork GitHub 上的代码并且开始探索吧。

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引

0个评论