HTML5游戏开发系列教程7

原文地址:http://www.script-tutorials.com/html5-game-development-lesson-7/

 今天我们将完成我们第一个完整的游戏--打砖块。这次教程中,将展示怎样进行基本的碰撞检测和使用HTML5的本地存储。你可以使用鼠标和键盘来操作挡板,上一次游戏的持续时间和分数将会保存。

前一篇的的介绍在HTML5游戏开发系列教程6(译)。

第一步:HTML

 1 <!DOCTYPE html>

 2 <html lang="en">

 3     <head>

 4         <meta charset="utf-8" />

 5         <title>HTML5 Game Development - Lesson 7 | 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 7</h2>

13             <a href="http://www.script-tutorials.com/html5-game-development-lesson-7/" 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样式文件

css/main.css

 1 /* page layout styles */

 2 *{

 3     margin:0;

 4     padding:0;

 5 }

 6 body {

 7     background-color:#eee;

 8     color:#fff;

 9     font:14px/1.3 Arial,sans-serif;

10 }

11 header {

12     background-color:#212121;

13     box-shadow: 0 -1px 2px #111111;

14     display:block;

15     height:70px;

16     position:relative;

17     width:100%;

18     z-index:100;

19 }

20 header h2{

21     font-size:22px;

22     font-weight:normal;

23     left:50%;

24     margin-left:-400px;

25     padding:22px 0;

26     position:absolute;

27     width:540px;

28 }

29 header a.stuts,a.stuts:visited{

30     border:none;

31     text-decoration:none;

32     color:#fcfcfc;

33     font-size:14px;

34     left:50%;

35     line-height:31px;

36     margin:23px 0 0 110px;

37     position:absolute;

38     top:0;

39 }

40 header .stuts span {

41     font-size:22px;

42     font-weight:bold;

43     margin-left:5px;

44 }

45 .container {

46     margin: 20px auto;

47     overflow: hidden;

48     position: relative;

49     width: 800px;

50 }

第三步:JS

js/jquery-2.0.0.min.js  (原文使用的是jquery-1.5.2.min.js)

js/script.js

  1 //内部变量

  2 var canvas, ctx;

  3 

  4 var iStart = 0;

  5 var bRightBut = false;

  6 var bLeftBut = false;

  7 var oBall, oPadd, oBricks;

  8 var aSounds = [];

  9 var iPoints = 0;

 10 var iGameTimer;

 11 var iElapsed = iMin = iSec = 0;

 12 var sLastTime, sLastPoints;

 13 

 14 /**

 15 * @brief    球体对象

 16 *

 17 * @param    x   横坐标

 18 * @param    y   纵坐标

 19 * @param    dx  横坐标将要移动的距离 

 20 * @param    dy  纵坐标将要移动的距离

 21 * @param    r   半径

 22 *

 23 * @return   

 24 */

 25 function Ball(x, y, dx, dy, r) {

 26     this.x = x;

 27     this.y = y;

 28     this.dx = dx;

 29     this.dy = dy;

 30     this.r = r;

 31 }

 32 

 33 /**

 34 * @brief   挡板对象 

 35 *

 36 * @param    x   横坐标--纵坐标固定的

 37 * @param    w   宽端

 38 * @param    h   高度

 39 * @param    img 图片

 40 *

 41 * @return   

 42 */

 43 function Padd(x, w, h, img) {

 44     this.x = x;

 45     this.w = w;

 46     this.h = h;

 47     this.img = img;

 48 }

 49 

 50 /**

 51 * @brief    砖块对象

 52 *

 53 * @param    w   宽度

 54 * @param    h   高度

 55 * @param    r   row 第几排 

 56 * @param    c   column  第几列

 57 * @param    p   砖块之间的间隙

 58 *

 59 * @return   

 60 */

 61 function Bricks(w, h, r, c, p) {

 62     this.w = w;

 63     this.h = h;

 64     this.r = r;

 65     this.c = c;

 66     this.p = p;

 67     this.objs;

 68     this.colors = ['#9d9d9d', '#f80207', '#feff01', '#0072ff', '#fc01fc', '#03fe03'];

 69 }

 70 

 71 function clear() {

 72     ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);

 73 

 74     ctx.fillStyle = '#111';

 75     ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);

 76 }

 77 

 78 function drawScene() {

 79     clear(); 

 80 

 81     //绘制球

 82     ctx.fillStyle = '#f66';

 83     ctx.beginPath();

 84     ctx.arc(oBall.x, oBall.y, oBall.r, 0, Math.PI * 2, true);

 85     ctx.closePath();

 86     ctx.fill();

 87 

 88     //padd左右移动

 89     if (bRightBut) {

 90         oPadd.x += 5;

 91     } else if (bLeftBut) {

 92         oPadd.x -= 5;

 93     }

 94 

 95     ctx.drawImage(oPadd.img, oPadd.x, ctx.canvas.height - oPadd.h);

 96 

 97     //绘制砖块

 98     for (i = 0; i < oBricks.r; i++) {

 99         ctx.fillStyle = oBricks.colors[i];

100         for (j = 0; j < oBricks.c; j++) {

101             if (oBricks.objs[i][j] == 1) {

102                 ctx.beginPath();

103                 ctx.rect((j * (oBricks.w + oBricks.p)) + oBricks.p, (i * (oBricks.h + oBricks.p)) + oBricks.p, oBricks.w, oBricks.h);

104                 ctx.closePath();

105                 ctx.fill();

106             }

107         }

108     }

109 

110     //处理碰撞检测

111     iRowH = oBricks.h + oBricks.p;

112     iRow = Math.floor(oBall.y / iRowH);

113     iCol = Math.floor(oBall.x / (oBricks.w + oBricks.p));

114 

115     if (oBall.y < oBricks.r * iRowH && iRow >= 0 && iCol >= 0 && oBricks.objs[iRow][iCol] == 1) {  //处理球碰到砖块

116         oBricks.objs[iRow][iCol] = 0;

117         oBall.dy = -oBall.dy;

118         iPoints++;

119 

120         aSounds[0].play();

121     }

122 

123     if (oBall.x + oBall.dx + oBall.r > ctx.canvas.width || oBall.x + oBall.dx - oBall.r < 0) { //处理左右边界

124         oBall.dx = -oBall.dx;

125     }

126 

127     if (oBall.y + oBall.dy - oBall.r < 0) {   //处理上边界

128         oBall.dy = -oBall.dy;

129     } else if (oBall.y + oBall.dy + oBall.r > ctx.canvas.height - oPadd.h) {   //处理下边界

130         if (oBall.x > oPadd.x && oBall.x < oPadd.x + oPadd.w) {  //球碰到挡板反弹

131             oBall.dx = 10 * ((oBall.x - (oPadd.x + oPadd.w / 2)) / oPadd.w);

132             oBall.dy = -oBall.dy;

133 

134             aSounds[2].play();

135         } else if (oBall.y + oBall.dy + oBall.r > ctx.canvas.height) { //失败

136             clearInterval(iStart);

137             clearInterval(iGameTimer);

138 

139             //在Local Storage中存持续时间和分数

140             localStorage.setItem('last-time', iMin + ':' + iSec);

141             localStorage.setItem('last-points', iPoints);

142 

143             aSounds[1].play();

144         }

145     }

146 

147     oBall.x += oBall.dx;

148     oBall.y += oBall.dy;

149 

150     //显示分数和时间

151     ctx.font = '16px Verdana';

152     ctx.fillStyle = '#fff';

153     iMin = Math.floor(iElapsed / 60);

154     iSec = iElapsed % 60;

155     if (iMin < 10) {

156         iMin = "0" + iMin;

157     }

158     if (iSec < 10) {

159         iSec = "0" + iSec;

160     }

161     ctx.fillText('Time: ' + iMin + ':' + iSec, 600, 520);

162     ctx.fillText('Points: ' + iPoints, 600, 550);

163 

164     if (sLastTime != null && sLastPoints != null) {

165         ctx.fillText('Last Time: ' + sLastTime, 600, 400);

166         ctx.fillText('Last Points: ' + sLastPoints, 600, 490);

167     }

168 }

169 

170 //初始化

171 $(function() {

172     canvas = document.getElementById('scene');

173     ctx = canvas.getContext('2d');

174 

175     var width = canvas.width;

176     var height = canvas.height;

177 

178     var padImg = new Image();

179     padImg.src = 'images/padd.png';

180     padImg.onload = function() {};

181 

182     oBall = new Ball(width / 2, 550, 0.5, -5, 10);

183     oPadd = new Padd(width / 2, 120, 20, padImg);

184     oBricks = new Bricks((width / 8) - 1, 20, 6, 8, 2); 

185 

186     oBricks.objs = new Array(oBricks.r);   //oBricks.objs  是个二维数组

187     for (i = 0; i <oBricks.r; i++) {

188         oBricks.objs[i] = new Array(oBricks.c);

189         for (j = 0; j < oBricks.c; j++) {

190             oBricks.objs[i][j] = 1;

191         }

192     }

193 

194     //声音

195     aSounds[0] = new Audio('media/snd1.wav');

196     aSounds[0].volume = 0.9;

197     aSounds[1] = new Audio('media/snd2.wav');

198     aSounds[1].volume = 0.9;

199     aSounds[2] = new Audio('media/snd3.wav');

200     aSounds[2].volume = 0.9;

201 

202     iStart = setInterval(drawScene, 10);  //重绘

203     iGameTimer = setInterval(countTimer, 1000);  //计数器

204 

205     sLastTime = localStorage.getItem('last-time');

206     sLastPoints = localStorage.getItem('last-points');

207 

208     $(window).keydown(function(event) {

209         switch (event.keyCode) {

210             case 37:

211                 bLeftBut = true;

212                 break;

213             case 39:

214                 bRightBut = true;

215                 break;

216         }

217     });

218     $(window).keyup(function(event) {

219         switch (event.keyCode) {

220             case 37:

221                 bLeftBut = false;

222                 break;

223             case 39:

224                 bRightBut = false;

225                 break;

226         }

227     });

228 

229     //处理挡板跟随鼠标移动

230     var iCanvX1 = $(canvas).offset().left;

231     var iCanvX2 = iCanvX1 + width;

232     $('#scene').mousemove(function(e) {

233         if (e.pageX > iCanvX1 && e.pageX < iCanvX2) {

234             oPadd.x = Math.max(e.pageX - iCanvX1 - (oPadd.w / 2), 0);

235             oPadd.x = Math.min(ctx.canvas.width - oPadd.w, oPadd.x);

236         }

237     });

238 });

239 

240 function countTimer() {

241     iElapsed++;

242 }

我在很多地方添加了注释,希望这些代码很容易理解。注意localStorage对象,并理解它在HTML5本地存储中是如果使用的(使用setItem方法来存储数据,使用getItem来取出数据)。同样,理解怎样处理球和砖块之间的碰撞检测将会很有趣。

结论:

这次我们编写了我们的第一个打砖块游戏。最重要的功能已经呈现了,并且学习了碰撞检测和HTML5的本地存储。我非常乐意看见你的谢意和评论。好运!

你可能感兴趣的:(html5)