原文地址:http://www.script-tutorials.com/html5-game-development-lesson-6/
这是我们最新一篇HTML5游戏开发系列文章。我们将继续使用canvas来进行HTML5游戏开发系列的文章。这次是个完整的游戏例子,再现一款经典的电脑游戏--坦克大战。我将教你们使用交替的数组地图(alternative array-maps),同时将说明如何检测活动对象(坦克)和周围环境之间的碰撞。
前一篇的的介绍在HTML5游戏开发系列教程5(译)。
第一步:HTML
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>HTML5 Game Development - Lesson 6 | Script Tutorials</title>
<link href="css/main.css" rel="stylesheet" type="text/css" />
<script src="js/jquery-2.0.0.min.js"></script>
<script src="js/script.js"></script>
</head>
<body>
<header>
<h2>HTML5 Game Development - Lesson 6</h2>
<a href="http://www.script-tutorials.com/html5-game-development-lesson-6/" class="stuts">Back to original tutorial on <span>Script Tutorials</span></a>
</header>
<div class="container">
<canvas id="scene" width="800" height="600"></canvas>
</div>
</body>
</html>
第二步:CSS
css/main.css
我将不会把css文件内容发布出来,css文件里面仅仅是一些页面的层叠样式,你可以在源代码包中找到该文件。
第三步:JS
js/jquery-2.0.0.min.js(原文是1.5.2版本)
我们的代码使用了JQuery。JQuery文件在源代码包中。下面的js文件是最重要的对于我们的游戏,因为它实现了我们游戏所有的逻辑。
js/script.js
//内部变量
var canvas, context; //画布和其上下文对象
var imgBrick, imgSteel, imgWater, imgForest, imgTank; //各种实体的图片
var aMap; //地图数组
var oTank; //坦克对象 var iCellSize = 24; //地图单元格的大小
var iXCnt = 26;
var iYCnt = 26; /**
* x: 坦克左上角x轴坐标
* y: 坦克左上角y轴坐标
* w: 坦克宽度
* h: 坦克高度
* image: 坦克图片
*/
function Tank(x, y, w, h, image) {
this.x = x;
this.y = y;
this.w = w;
this.h = h;
this.i = 0;
this.image = image;
} // 清除画布
function clear() {
context.clearRect(0, 0, canvas.width, canvas.height)
} //重绘画布
function drawScene() {
clear(); //填充背景
context.fillStyle = '#111';
context.fillRect(0, 0, canvas.width, canvas.height); context.save(); //画障碍物
for (var y = 0; y < iYCnt; y++) {
for (var x = 0; x < iXCnt; x++) {
switch (aMap[y][x]) {
case 0:
break;
case 1:
context.drawImage(imgBrick, 0, 0, iCellSize, iCellSize, x * iCellSize, y * iCellSize, iCellSize, iCellSize);
break;
case 2:
context.drawImage(imgSteel, 0, 0, iCellSize, iCellSize, x * iCellSize, y * iCellSize, iCellSize, iCellSize);
break;
case 3:
context.drawImage(imgForest, 0, 0, iCellSize, iCellSize, x * iCellSize, y * iCellSize, iCellSize, iCellSize);
break;
case 4:
context.drawImage(imgWater, 0, 0, iCellSize, iCellSize, x * iCellSize, y * iCellSize, iCellSize, iCellSize);
break;
}
}
} context.restore(); //画坦克 这里可以看出坦克占4个单元格
context.drawImage(oTank.image, oTank.i * oTank.w, 0, oTank.w, oTank.h, oTank.x, oTank.y, oTank.w, oTank.h);
} $(function() {
canvas = document.getElementById('scene');
canvas.width = iXCnt * iCellSize;
canvas.height = iYCnt * iCellSize;
context = canvas.getContext('2d'); aMap = ([
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0],
[0, 0, 1, 1, 4, 4, 4, 4, 0, 0, 2, 2, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 1, 1, 4, 4, 4, 4, 0, 0, 2, 2, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 4, 4, 4, 4, 1, 1, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 0, 0, 2, 2, 0, 0],
[0, 0, 0, 0, 4, 4, 4, 4, 1, 1, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 0, 0, 2, 2, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 1, 1, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 1, 1, 0, 0, 0, 0],
[0, 0, 2, 2, 0, 0, 0, 0, 4, 4, 4, 4, 0, 0, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 2, 2, 0, 0, 0, 0, 4, 4, 4, 4, 0, 0, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[3, 3, 3, 3, 1, 1, 0, 0, 4, 4, 4, 4, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0],
[3, 3, 3, 3, 1, 1, 0, 0, 4, 4, 4, 4, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0],
[3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 2, 2],
[3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 2, 2],
[0, 0, 1, 1, 4, 4, 4, 4, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 1, 1, 4, 4, 4, 4, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[2, 2, 0, 0, 4, 4, 4, 4, 3, 3, 3, 3, 4, 4, 4, 4, 3, 3, 3, 3, 0, 0, 1, 1, 0, 0],
[2, 2, 0, 0, 4, 4, 4, 4, 3, 3, 3, 3, 4, 4, 4, 4, 3, 3, 3, 3, 0, 0, 1, 1, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 0, 0, 4, 4, 4, 4, 3, 3, 3, 3, 4, 4, 4, 4, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 0, 0, 4, 4, 4, 4, 3, 3, 3, 3, 4, 4, 4, 4, 0, 0],
[0, 0, 0, 0, 0, 0, 2, 2, 3, 3, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 4, 4, 4, 4, 0, 0],
[0, 0, 0, 0, 0, 0, 2, 2, 3, 3, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 4, 4, 4, 4, 0, 0],
[0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 2, 2, 0, 0, 0, 0],
[1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 2, 2, 0, 0, 0, 0]
]); //加载各个障碍物图片
imgBrick = new Image();
imgBrick.src = 'images/brick.png';
imgSteel = new Image();
imgSteel.src = 'images/steel.png';
imgWater = new Image();
imgWater.src = 'images/water.png';
imgForest = new Image();
imgForest.src = 'images/forest.png'; //初始化坦克
imgTank = new Image();
imgTank.src = 'images/tank.png';
oTank = new Tank(iCellSize * 9, iCellSize * 24, 48, 48, imgTank); $(window).keydown(function(event) {
switch (event.keyCode) {
case 38: // up key
oTank.i = 2; //碰撞检测
var iCurCelX = (2 * oTank.x) / 48; //得出目前坦克左上角所在的单元格
var iCurCelY = (2 * oTank.y) / 48;
if (iCurCelY) {
var iTest1 = aMap[iCurCelY - 1][iCurCelX];
var iTest2 = aMap[iCurCelY - 1][iCurCelX + 1]; if ((iTest1 == 0 || iTest1 == 3) && (iTest2 == 0 || iTest2 == 3)) {
oTank.y -= 24;
if (oTank.y < 0) {
oTank.y = 0;
}
}
}
break;
case 40: //Down key
oTank.i = 3; var iCurCelX = (2 * oTank.x) / 48;
var iCurCelY = (2 * oTank.y) / 48;
if (iCurCelY + 2 < iYCnt) {
var iTest1 = aMap[iCurCelY + 2][iCurCelX];
var iTest2 = aMap[iCurCelY + 2][iCurCelX + 1]; if ((iTest1 == 0 || iTest1 == 3) && (iTest2 == 0 || iTest2 == 3)) {
oTank.y += 24;
if (oTank.y > 576) { //576 = iCellSize * (iYCnt - 2)
oTank.y = 576;
}
}
}
break;
case 37: // Left key
oTank.i = 1; var iCurCelX = (2 * oTank.x) / 48;
var iCurCelY = (2 * oTank.y) / 48;
var iTest1 = aMap[iCurCelY][iCurCelX - 1];
var iTest2 = aMap[iCurCelY + 1][iCurCelX - 1]; if ((iTest1 == 0 || iTest1 == 3) && (iTest2 == 0 || iTest2 == 3)) {
oTank.x -= 24;
if (oTank.x < 0) {
oTank.x = 0;
}
}
break;
case 39: //Right key
oTank.i = 0; var iCurCelX = (2 * oTank.x) / 48;
var iCurCelY = (2 * oTank.y) / 48;
var iTest1 = aMap[iCurCelY][iCurCelX + 2];
var iTest2 = aMap[iCurCelY + 1][iCurCelX + 2]; if ((iTest1 == 0 || iTest1 == 3) && (iTest2 == 0 || iTest2 == 3)) {
oTank.x += 24;
if (oTank.x > 576) {
oTank.x = 576;
}
}
break;
}
});
setInterval(drawScene, 40);
});
我在很多地方加上了注释,依此希望这代码是容易理解的。
结论:
这次我们开发了一个完整的HTML5的游戏--坦克大战。我非常乐意看见你的谢意和评论。好运!