原文地址:http://www.script-tutorials.com/html5-game-development-lesson-6/
这是我们最新一篇HTML5游戏开发系列文章。我们将继续使用canvas来进行HTML5游戏开发系列的文章。这次是个完整的游戏例子,再现一款经典的电脑游戏--坦克大战。我将教你们使用交替的数组地图(alternative array-maps),同时将说明如何检测活动对象(坦克)和周围环境之间的碰撞。
前一篇的的介绍在HTML5游戏开发系列教程5(译)。
第一步:HTML
index.html
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="utf-8" /> 5 <title>HTML5 Game Development - Lesson 6 | Script Tutorials</title> 6 <link href="css/main.css" rel="stylesheet" type="text/css" /> 7 <script src="js/jquery-2.0.0.min.js"></script> 8 <script src="js/script.js"></script> 9 </head> 10 <body> 11 <header> 12 <h2>HTML5 Game Development - Lesson 6</h2> 13 <a href="http://www.script-tutorials.com/html5-game-development-lesson-6/" class="stuts">Back to original tutorial on <span>Script Tutorials</span></a> 14 </header> 15 <div class="container"> 16 <canvas id="scene" width="800" height="600"></canvas> 17 </div> 18 </body> 19 </html>
第二步:CSS
css/main.css
我将不会把css文件内容发布出来,css文件里面仅仅是一些页面的层叠样式,你可以在源代码包中找到该文件。
第三步:JS
js/jquery-2.0.0.min.js(原文是1.5.2版本)
我们的代码使用了JQuery。JQuery文件在源代码包中。下面的js文件是最重要的对于我们的游戏,因为它实现了我们游戏所有的逻辑。
js/script.js
1 //内部变量 2 var canvas, context; //画布和其上下文对象 3 var imgBrick, imgSteel, imgWater, imgForest, imgTank; //各种实体的图片 4 var aMap; //地图数组 5 var oTank; //坦克对象 6 7 var iCellSize = 24; //地图单元格的大小 8 var iXCnt = 26; 9 var iYCnt = 26; 10 11 /** 12 * x: 坦克左上角x轴坐标 13 * y: 坦克左上角y轴坐标 14 * w: 坦克宽度 15 * h: 坦克高度 16 * image: 坦克图片 17 */ 18 function Tank(x, y, w, h, image) { 19 this.x = x; 20 this.y = y; 21 this.w = w; 22 this.h = h; 23 this.i = 0; 24 this.image = image; 25 } 26 27 // 清除画布 28 function clear() { 29 context.clearRect(0, 0, canvas.width, canvas.height) 30 } 31 32 //重绘画布 33 function drawScene() { 34 clear(); 35 36 //填充背景 37 context.fillStyle = '#111'; 38 context.fillRect(0, 0, canvas.width, canvas.height); 39 40 context.save(); 41 42 //画障碍物 43 for (var y = 0; y < iYCnt; y++) { 44 for (var x = 0; x < iXCnt; x++) { 45 switch (aMap[y][x]) { 46 case 0: 47 break; 48 case 1: 49 context.drawImage(imgBrick, 0, 0, iCellSize, iCellSize, x * iCellSize, y * iCellSize, iCellSize, iCellSize); 50 break; 51 case 2: 52 context.drawImage(imgSteel, 0, 0, iCellSize, iCellSize, x * iCellSize, y * iCellSize, iCellSize, iCellSize); 53 break; 54 case 3: 55 context.drawImage(imgForest, 0, 0, iCellSize, iCellSize, x * iCellSize, y * iCellSize, iCellSize, iCellSize); 56 break; 57 case 4: 58 context.drawImage(imgWater, 0, 0, iCellSize, iCellSize, x * iCellSize, y * iCellSize, iCellSize, iCellSize); 59 break; 60 } 61 } 62 } 63 64 context.restore(); 65 66 //画坦克 这里可以看出坦克占4个单元格 67 context.drawImage(oTank.image, oTank.i * oTank.w, 0, oTank.w, oTank.h, oTank.x, oTank.y, oTank.w, oTank.h); 68 } 69 70 $(function() { 71 canvas = document.getElementById('scene'); 72 canvas.width = iXCnt * iCellSize; 73 canvas.height = iYCnt * iCellSize; 74 context = canvas.getContext('2d'); 75 76 aMap = ([ 77 [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], 78 [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], 79 [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], 80 [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], 81 [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], 82 [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], 83 [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], 84 [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], 85 [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], 86 [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], 87 [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], 88 [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], 89 [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], 90 [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], 91 [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], 92 [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], 93 [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], 94 [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], 95 [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], 96 [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], 97 [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], 98 [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], 99 [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], 100 [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], 101 [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], 102 [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] 103 ]); 104 105 //加载各个障碍物图片 106 imgBrick = new Image(); 107 imgBrick.src = 'images/brick.png'; 108 imgSteel = new Image(); 109 imgSteel.src = 'images/steel.png'; 110 imgWater = new Image(); 111 imgWater.src = 'images/water.png'; 112 imgForest = new Image(); 113 imgForest.src = 'images/forest.png'; 114 115 //初始化坦克 116 imgTank = new Image(); 117 imgTank.src = 'images/tank.png'; 118 oTank = new Tank(iCellSize * 9, iCellSize * 24, 48, 48, imgTank); 119 120 $(window).keydown(function(event) { 121 switch (event.keyCode) { 122 case 38: // up key 123 oTank.i = 2; 124 125 //碰撞检测 126 var iCurCelX = (2 * oTank.x) / 48; //得出目前坦克左上角所在的单元格 127 var iCurCelY = (2 * oTank.y) / 48; 128 if (iCurCelY) { 129 var iTest1 = aMap[iCurCelY - 1][iCurCelX]; 130 var iTest2 = aMap[iCurCelY - 1][iCurCelX + 1]; 131 132 if ((iTest1 == 0 || iTest1 == 3) && (iTest2 == 0 || iTest2 == 3)) { 133 oTank.y -= 24; 134 if (oTank.y < 0) { 135 oTank.y = 0; 136 } 137 } 138 } 139 break; 140 case 40: //Down key 141 oTank.i = 3; 142 143 var iCurCelX = (2 * oTank.x) / 48; 144 var iCurCelY = (2 * oTank.y) / 48; 145 if (iCurCelY + 2 < iYCnt) { 146 var iTest1 = aMap[iCurCelY + 2][iCurCelX]; 147 var iTest2 = aMap[iCurCelY + 2][iCurCelX + 1]; 148 149 if ((iTest1 == 0 || iTest1 == 3) && (iTest2 == 0 || iTest2 == 3)) { 150 oTank.y += 24; 151 if (oTank.y > 576) { //576 = iCellSize * (iYCnt - 2) 152 oTank.y = 576; 153 } 154 } 155 } 156 break; 157 case 37: // Left key 158 oTank.i = 1; 159 160 var iCurCelX = (2 * oTank.x) / 48; 161 var iCurCelY = (2 * oTank.y) / 48; 162 var iTest1 = aMap[iCurCelY][iCurCelX - 1]; 163 var iTest2 = aMap[iCurCelY + 1][iCurCelX - 1]; 164 165 if ((iTest1 == 0 || iTest1 == 3) && (iTest2 == 0 || iTest2 == 3)) { 166 oTank.x -= 24; 167 if (oTank.x < 0) { 168 oTank.x = 0; 169 } 170 } 171 break; 172 case 39: //Right key 173 oTank.i = 0; 174 175 var iCurCelX = (2 * oTank.x) / 48; 176 var iCurCelY = (2 * oTank.y) / 48; 177 var iTest1 = aMap[iCurCelY][iCurCelX + 2]; 178 var iTest2 = aMap[iCurCelY + 1][iCurCelX + 2]; 179 180 if ((iTest1 == 0 || iTest1 == 3) && (iTest2 == 0 || iTest2 == 3)) { 181 oTank.x += 24; 182 if (oTank.x > 576) { 183 oTank.x = 576; 184 } 185 } 186 break; 187 } 188 }); 189 setInterval(drawScene, 40); 190 });
我在很多地方加上了注释,依此希望这代码是容易理解的。
结论:
这次我们开发了一个完整的HTML5的游戏--坦克大战。我非常乐意看见你的谢意和评论。好运!