创建一个带有定时器的HTML5 ( 和 JavaScript ) 迷宫游戏

分享于 

17分钟阅读

Web开发

  繁體

介绍

本文介绍了如何使用 HTML5 (。canvas -element和 JavaScript,不使用 Flash ) 创建一个带有数字定时器的迷宫游戏。
注意:如果你的浏览器不支持JavaScript或者 HTML5,这个迷宫不工作。 如果你下载迷宫,但如果它没有正常工作,那么请尝试在线演示:
https://programfox.github.io/HTML5-Maze/ [ ^ ]

在我测试游戏时,另外一个重要的注意:在 Firefox。Opera 和Safari上的离线和在线运行效果良好。 但是,在 Chrome 和 IE 中,如果文件未被承载,则无法移动蓝色 rectangle。 这是出于安全原因: 文件系统上的每个文件都有不同的来源,你可以从其他来源加载文件到 canvas ( 然后是一个污染的画布 [ ^ ] ),但是如果你尝试在污染的画布上使用 getImageData(),你会在 Chrome 和 IE 中得到安全错误。 对于这些浏览器,你应该去网上演示,或者在 localhost 服务器上承载下载的文件。

下载完迷宫后,不要忘记解压所有文件( HTML文件和图像),否则迷宫就不会出现。

生成迷宫

创建迷宫的第一步是得到迷宫的图像。 要创建一个迷宫图像,我使用这个在线迷宫制作器: http://www.hereand上面.com/maze/mazeorig.form.html [ ^ ]
这就是迷宫制造者产生的迷宫:
生成的迷宫

定位元素并在画布元素上绘制迷宫

定位和绘图

下一步是定位可以使用箭头键或者,移动的rectangle,并定位端点( 我迷宫上的一个圆圈)。 在我的迷宫中,rectangle的位置是 425, 3px,大小为 15px Z 15px,圆的中心点为 524px, 122px,半径为 7 px。 首先,你需要创建 canvas -element:

<canvaswidth="616"height="556"id="mazecanvas">Can't load the maze game, because your browser doesn't support HTML5.</canvas><noscript>JavaScript is not enabled. To play the game, you should enable it.</noscript>

浏览器将显示"无法载入迷宫游戏。",如果浏览器不支持 HTML5. 迷宫的大小是 556 x,但是我把宽度设置为,因为我添加了一个( 数字) 计时器。 下一步是使用JavaScript将迷宫绘制到 canvas -element。 我们在这里使用 drawImageclosePathrectfill 方法绘制 rectangle,使用 beginPathclosePatharcfill 方法绘制圆,绘制圆:

var canvas = document.getElementById("mazecanvas");var context = canvas.getContext("2d");var currRectX = 425;var currRectY = 3;var mazeWidth = 556;var mazeHeight = 556;var intervalVar;
function drawMazeAndRectangle(rectX, rectY) {
 makeWhite(0, 0, canvas.width, canvas.height);
 var mazeImg = new Image();
 mazeImg.onload = function () { // when the image is loaded, draw the image, the rectangle and the circle context.drawImage(mazeImg, 0, 0);
 drawRectangle(rectX, rectY, "#0000FF", false, true);
 context.beginPath();
 context.arc(542, 122, 7, 0, 2 * Math.PI, false);
 context.closePath();
 context.fillStyle = '#00FF00';
 context.fill();
 };
 mazeImg.src = "maze.gif";
}
function drawRectangle(x, y, style) {
 makeWhite(currRectX, currRectY, 15, 15);
 currRectX = x;
 currRectY = y;
 context.beginPath();
 context.rect(x, y, 15, 15);
 context.closePath();
 context.fillStyle = style;
 context.fill();
}

要在 canvas 上绘制迷宫,请在脚本底部添加下面的代码:

drawMazeAndRectangle(425, 3); // { 425, 3 } is the position of the blue rectangle on the canvas

currRectXcurrRectY 表示 rectangle的位置,intervalVar 是计时器的变量,我们将在后面创建。

( ),fill() 和 stroke() 方法

在开始路径( 使用 beginPath() 方法) 之后,你可以使用 rect() 方法来创建 rectangle。 但是,如果只使用 rect() 方法,则不绘制 rectangle。 要在 canvas -element上绘制创建的rectangle,你应该使用 fill() 或者 stroke() 方法在 canvas 上实际绘制 rectangle。 fill() 方法填充路径,而 stroke() 方法绘制路径。

rect() 方法 NameTypeDescription的参数
号码rectangle的左上角的x 坐标,以像素为单位。
号码rectangle的左上角的y 坐标( 以像素为单位)。
号码rectangle的宽度,以像素为单位。
号码rectangle的高度,以像素为单位。
stroke()fill() 方法没有参数。

arc() 方法

arc() 方法在 canvas 上绘制一个 arc。 绘制 arc 后,应调用 stroke() 或者 fill() 方法。 你可以使用这里方法绘制圆或者圆的一部分。

arc() 方法 NameTypeDescription的参数
号码arc的中心点的x 坐标,以像素为单位。
号码arc 中心点的y 坐标,以像素为单位。
半径号码arc的半径,以像素为单位。
startAngle号码起始角度,以弧度为单位。 0位于 arc的circle的3 clock ( 参见图)
endAngle号码结束角度,以弧度为单位。
逆时针方向的。布尔型如果 arc 应以逆时针 direction ( 从开始到结束) 绘制,则为 true
如果 arc 应以顺时针 direction ( 从开始到结束) 绘制,则为 false

图像:
弧度

makeWhite() 函数

在前面的代码Fragment中,你看到我使用了 makeWhite() 函数。 我自己创造了这个功能。 它在 canvas white上生成一个 rectangle。 那么,我为什么不使用 clear 方法? 因为 clear() 方法使得给定 rectangle 中所有像素都透明,所以我们在迷宫中不需要。 这是 makeWhite() 函数的代码:

function makeWhite(x, y, w, h) {
 context.beginPath();
 context.rect(x, y, w, h);
 context.closePath();
 context.fillStyle = "white";
 context.fill();
}

使用箭头键或者WASD键移动 rectangle。

接下来要实现的是使用箭头键或者WASD来移动蓝色的rectangle。 第一步是计算蓝色 rectangle的新的X 和y 坐标。 第二步是移动 rectangle,如果可以移动,如果蓝色 rectangle 达到最终点( 绿色圆圈),则显示"祝贺恭喜"消息: !

function moveRect(e) {
 var newX;
 var newY;
 var canMove;
 e = e || window.event;
 switch (e.keyCode) {
 case38: // arrow up keycase87: // W key newX = currRectX;
 newY = currRectY - 3;
 break;
 case37: // arrow left keycase65: // A key newX = currRectX - 3;
 newY = currRectY;
 break;
 case40: // arrow down keycase83: // S key newX = currRectX;
 newY = currRectY + 3;
 break;
 case39: // arrow right keycase68: // D key newX = currRectX + 3;
 newY = currRectY;
 break;
 default: return;
 }
 movingAllowed = canMoveTo(newX, newY);
 if (movingAllowed === 1) { // 1 means 'the rectangle can move' drawRectangle(newX, newY, "#0000FF");
 currRectX = newX;
 currRectY = newY;
 }
 elseif (movingAllowed === 2) { // 2 means 'the rectangle reached the end point' clearInterval(intervalVar); // we'll set the timer later in this article makeWhite(0, 0, canvas.width, canvas.height);
 context.font = "40px Arial";
 context.fillStyle = "blue";
 context.textAlign = "center";
 context.textBaseline = "middle";
 context.fillText("Congratulations!", canvas.width/2, canvas.height/2);
 window.removeEventListener("keydown", moveRect, true);
 }
}

如果 rectangle 到达终点,我使用 clearInterval() 方法停止计时器( 我们将在本文后面设置)。 然后,我画了"恭喜在 canvas 上,然后删除 keydown 事件监听器,因为蓝色的rectangle 不应该再移动。

在移动蓝色 rectangle 之前,你应该添加一个 keydown 事件侦听器:

drawMazeAndRectangle(425, 3); // this line is already addedwindow.addEventListener("keydown", moveRect, true); // add this at the bottom of your script

检查蓝色 rectangle 是否可以移动: canMoveTo() 函数

在前面的代码Fragment中,你看到了 canMoveTo() 函数。 我创建了这个方法来检查蓝色 rectangle 是否可以移动。 逻辑 behind:

  • 检查蓝色 rectangle 是否将 inside 移动到 canvas的边界
  • 如果是这样,就可以获得 rectangle的图像数据 x = destinationX, y = destinationY, width = 15, height = 15 因为它是蓝色 rectangle的大小,所以我把 15当作宽度和高度。
  • 使用 for 循环查看所有像素: 如果其中任何一个有 black的颜色,蓝色的rectangle 就不能移动。 如果其中任何一个有颜色石灰,那么你就到达终点了。

这是 canMoveTo() 函数的代码:

function canMoveTo(destX, destY) {
 var imgData = context.getImageData(destX, destY, 15, 15);
 var data = imgData.data;
 var canMove = 1; // 1 means: the rectangle can moveif (destX >= 0 && destX <= mazeWidth - 15 && destY >= 0 && destY <= mazeHeight - 15) { // check whether the rectangle would move inside the bounds of the canvasfor (var i = 0; i <4 * 15 * 15; i += 4) { // look at all pixelsif (data[i] === 0 && data[i + 1] === 0 && data[i + 2] === 0) { // black canMove = 0; // 0 means: the rectangle can't movebreak;
 }
 elseif (data[i] === 0 && data[i + 1] === 255 && data[i + 2] === 0) { // lime: #00FF00 canMove = 2; // 2 means: the end point is reachedbreak;
 }
 }
 }
 else {
 canMove = 0;
 }
 return canMove;
}

getImageData() 方法

使用 getImageData() 方法,你可以获取 canvas 特定区域的图像数据。 这里方法返回 ImageData 对象,而 data 属性是包含RGBA像素数据的array。 所以:

  • data[0] 包含中第一个像素的R ( 红色) 值。
  • data[1] 包含 ImageData 中第一个像素的G ( 绿色) 值
  • data[2] 包含 ImageData 中第一个像素的B ( 蓝色) 值
  • data[3] 包含 ImageData 中第一个像素的( alpha ) 值
  • data[4] 包含中像素的R ( 红色) 值
  • data[5] 包含 ImageData 中第二个像素的G ( 绿色) 值
  • data[6] 包含 ImageData 中第二个像素的B ( 蓝色) 值
  • data[7] 包含 ImageData 中第二个像素的( alpha ) 值
  • 等等
getImageData() 方法NameTypeDescription的参数
sx号码从 rectangle的左上角获取图像数据的x 坐标( 以像素为单位)。
号码从 rectangle的左上角获取图像数据的y 坐标,以像素为单位。
号码从 rectangle 获取图像数据的宽度( 以像素为单位)。
号码从 rectangle 获取图像数据的高度( 以像素为单位)。

实现计时器

下一步是实现计时器。 为此,我们使用 setInterval() 方法以秒为单位减少时间。 如果有时间,我们将整个 canvas 输出,添加红色"时间"消息。

function createTimer(seconds) {
 intervalVar = setInterval(function () {
 makeWhite(mazeWidth, 0, canvas.width - mazeWidth, canvas.height);
 if (seconds === 0) {
 clearInterval(intervalVar);
 window.removeEventListener("keydown", moveRect, true);
 makeWhite(0, 0, canvas.width, canvas.height);
 context.font = "40px Arial";
 context.fillStyle = "red";
 context.textAlign = "center";
 context.textBaseline = "middle";
 context.fillText("Time's up!", canvas.width/2, canvas.height/2);
 return;
 }
 context.font = "20px Arial";
 if (seconds <= 10 && seconds >5) {
 context.fillStyle = "orangered";
 }
 elseif (seconds <= 5) {
 context.fillStyle = "red";
 }
 else {
 context.fillStyle = "green";
 }
 context.textAlign = "center";
 context.textBaseline = "middle";
 var minutes = Math.floor(seconds/60);
 var secondsToShow = (seconds - minutes * 60).toString();
 if (secondsToShow.length === 1) {
 secondsToShow = "0" + secondsToShow; // if the number of seconds is '5' for example, make sure that it is shown as '05' }
 context.fillText(minutes.toString() + ":" + secondsToShow, mazeWidth + 30, canvas.height/2);
 seconds--;
 }, 1000);
}

createTimer() 函数中,我创建了一个匿名函数,该函数将在。 如果你不希望在每秒钟调用匿名函数,setInterval() 方法会返回一个惟一的间隔 ID,你可以传递给 clearInterval() 方法。 在匿名函数的第一行,我清除了 canvas的特定范围: 我只清除了计时器的面积。 在这个迷宫中,canvas 被分成两个部分: 迷宫出现了,而在另一部分中,计时器出现了。

如果 seconds 等于0,我将调用 clearInterval() 方法,因为我希望在每秒停止匿名函数的执行。 然后移除 keydown 事件侦听器,因为不再需要移动蓝色 rectangle ( 因为向上) 时间。 然后,我清除整个画布,在它上面绘制"时间"。

如果 seconds 还不等于0,我将在 canvas 上绘制剩余的时间。 如果剩余时间超过 10秒,则剩余时间的颜色为绿色。 如果剩余时间小于或者等于 10,但 GREATER 于 5,则颜色为橙色,如果剩余时间小于或者等于 5秒。
首先,我们计算剩余的分钟数。 为此,我们计算 seconds/60的楼层值,并得到剩余的秒数,我们计算 seconds - minutes * 60 如果秒数为 5,则确保它将显示为 05,如果需要,将它的前面的5 按零显示。

要真正创建计时器,请在脚本末尾的底部添加这里行:

drawMazeAndRectangle(425, 3); // added alreadywindow.addEventListener("keydown", moveRect, true); // added alreadycreateTimer(120); // add this line// 120 seconds -> 2 minutes

历史记录

  • 30 2013年月: 在 Chrome 和 IE 中添加了关于安全性错误的信息
  • 6 2013年月: 第一个版本

JAVA  Javascript  GAM  时间  Html5  Timer  
相关文章