HTML5游戏开发系列教程9(译)

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

今天我们将继续使用canvas来进行HTML5游戏开发系列的文章。这次我准备了一个新游戏,是基于第4篇的游戏,但是增加了火球,敌人和碰撞检测。故,我们的龙可以发射火球来杀死敌人,并且记录分数。这样该游戏就有更多的交互性。

之前的翻译文章可以点击这里:http://www.cnblogs.com/pigzhu/p/3234255.html

第一步:HTML

首先是我们基础的html代码:

 1 <!DOCTYPE html>
 2 <html lang="en" >
 3     <head>
 4         <meta charset="utf-8" />
 5         <title>HTML5 Game Development - Lesson 9 | Script Tutorials</title>
 6         <link href="css/main.css" rel="stylesheet" type="text/css" />
 7 
 8         <!--[if lt IE 9]>
 9           <script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
10         <![endif]-->
11         <script src="js/jquery-2.0.0.min.js"></script>
12         <script src="js/script.js"></script>
13     </head>
14     <body>
15         <header tabindex="0">
16             <h2>HTML5 Game Development - Lesson 9</h2>
17             <a  href="http://www.script-tutorials.com/html5-game-development-lesson-9/" class="stuts">Back to original tutorial on <span>Script Tutorials</span></a>
18         </header>
19 
20         <div class="container">
21             <canvas id="scene" width="1000" height="600" tabindex="1"></canvas>
22         </div>
23     </body>
24 </html>
View Code

第二步:CSS

接着这里是CSS样式。

css/main.css

这次依然不打算显示出CSS文件的内容了,因为仅仅只是些页面布局样式。你可以在源代码包里找到该文件。

第三步:JS

js/script.js

  1 // 内部变量
  2 var canvas, ctx;
  3 var backgroundImage;
  4 var iBgShiftX = 100;
  5 
  6 var dragon, enemy = null; // 游戏中两个主要实体对象
  7 var balls = [];
  8 var enemies = [];
  9 
 10 var dragonW = 75; // 龙的宽度
 11 var dragonH = 70; // 龙的高度
 12 var iSprPos = 0; // 初始帧的位置
 13 var iSprDir = 0; // 初始龙的朝向
 14 var iEnemyW = 128; // 敌人的宽度
 15 var iEnemyH = 128; // 敌人的高度
 16 var iBallSpeed = 10; // 火球的速度
 17 var iEnemySpeed = 2; // 敌人的速度
 18 
 19 var dragonSound; // 龙的声音
 20 var wingsSound; // 翅膀的声音
 21 var explodeSound, explodeSound2; // 爆炸声音
 22 var laughtSound; // 敌人从左边逃出,嘲笑的声音
 23 
 24 var bMouseDown = false; // 鼠标是否按下
 25 var iLastMouseX = 0;
 26 var iLastMouseY = 0;
 27 var iScore = 0;
 28 // -------------------------------------------------------------
 29 
 30 //
 31 function Dragon(x, y, w, h, image) {
 32     this.x = x;
 33     this.y = y;
 34     this.w = w;
 35     this.h = h;
 36     this.image = image;
 37     this.bDrag = false;
 38 }
 39 //
 40 function Ball(x, y, w, h, speed, image) {
 41     this.x = x;
 42     this.y = y;
 43     this.w = w;
 44     this.h = h;
 45     this.speed = speed;
 46     this.image = image;
 47 }
 48 // 敌人
 49 function Enemy(x, y, w, h, speed, image) {
 50     this.x = x;
 51     this.y = y;
 52     this.w = w;
 53     this.h = h;
 54     this.speed = speed;
 55     this.image = image;
 56 }
 57 // -------------------------------------------------------------
 58 // 获得位于x和y之间的随机数。
 59 function getRand(x, y) {
 60     return Math.floor(Math.random() * y) + x;
 61 }
 62 
 63 // draw functions :
 64 function drawScene() { // main drawScene function
 65     ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); // 清除这个画布
 66 
 67     // 画背景
 68     iBgShiftX += 4;
 69     if (iBgShiftX >= 1045) {
 70         iBgShiftX = 0;
 71     }
 72     ctx.drawImage(backgroundImage, 0 + iBgShiftX, 0, 1000, 940, 0, 0, 1000, 600);
 73 
 74     // 更新帧的位置
 75     iSprPos++;
 76     if (iSprPos >= 9) {
 77         iSprPos = 0;
 78     }
 79 
 80     // 当鼠标被按下,龙朝着鼠标移动
 81     if (bMouseDown) {
 82         if (iLastMouseX > dragon.x) {
 83             dragon.x += 5;
 84         }
 85         if (iLastMouseY > dragon.y) {
 86             dragon.y += 5;
 87         }
 88         if (iLastMouseX < dragon.x) {
 89             dragon.x -= 5;
 90         }
 91         if (iLastMouseY < dragon.y) {
 92             dragon.y -= 5;
 93         }
 94     }
 95 
 96     // 绘制龙
 97     ctx.drawImage(dragon.image, iSprPos * dragon.w, iSprDir * dragon.h, dragon.w, dragon.h,
 98      dragon.x - dragon.w / 2, dragon.y - dragon.h / 2, dragon.w, dragon.h);
 99 
100     // 如果有火球则绘制
101     if (balls.length > 0) {
102         for (var key in balls) {
103             if (balls[key] != undefined) {
104                 ctx.drawImage(balls[key].image, balls[key].x, balls[key].y);
105                 balls[key].x += balls[key].speed;
106 
107                 if (balls[key].x > canvas.width) {  //超出屏幕,移除
108                     delete balls[key];
109                 }
110             }
111         }
112     }
113 
114     // 如果有敌人则绘制
115     if (enemies.length > 0) {
116         for (var ekey in enemies) {
117             if (enemies[ekey] != undefined) {
118                 ctx.drawImage(enemies[ekey].image, enemies[ekey].x, enemies[ekey].y);
119                 enemies[ekey].x += enemies[ekey].speed;
120 
121                 if (enemies[ekey].x < - iEnemyW) {  //敌人没有被击中,从左边消失,并发出嘲笑声音
122                     delete enemies[ekey];
123 
124                     laughtSound.currentTime = 0;
125                     laughtSound.play();
126                 }
127             }
128         }
129     }
130 
131     // 检测是否击中敌人
132     if (balls.length > 0) {
133         for (var key in balls) {
134             if (balls[key] != undefined) {
135 
136                 if (enemies.length > 0) {
137                     for (var ekey in enemies) {
138                         if (enemies[ekey] != undefined && balls[key] != undefined) {
139                             if (balls[key].x + balls[key].w > enemies[ekey].x && balls[key].y + balls[key].h > enemies[ekey].y 
140                                 && balls[key].y < enemies[ekey].y + enemies[ekey].h) {
141                                 delete enemies[ekey];
142                                 delete balls[key];
143                                 iScore++;
144 
145                                 explodeSound2.currentTime = 0;
146                                 explodeSound2.play();
147                             }
148                         }
149                     }
150                 }
151             }
152         }
153     }
154 
155     // 绘制分数
156     ctx.font = '16px Verdana';
157     ctx.fillStyle = '#fff';
158     ctx.fillText('Score: ' + iScore * 10, 900, 580);
159     ctx.fillText('Plese click "1" to cast fireball', 100, 580);
160 
161 }
162 
163 // -------------------------------------------------------------
164 
165 // 初始化
166 $(function(){
167     canvas = document.getElementById('scene');
168     ctx = canvas.getContext('2d');
169 
170     var width = canvas.width;
171     var height = canvas.height;
172 
173     // 加载背景图片
174     backgroundImage = new Image();
175     backgroundImage.src = 'images/hell.jpg';
176     backgroundImage.onload = function() {
177     }
178     backgroundImage.onerror = function() {
179         console.log('Error loading the background image.');
180     }
181 
182     //初始化各种声音
183     dragonSound = new Audio('media/dragon.wav');
184     dragonSound.volume = 0.9;
185 
186     laughtSound = new Audio('media/laught.wav');
187     laughtSound.volume = 0.9;
188 
189     explodeSound = new Audio('media/explode1.wav');
190     explodeSound.volume = 0.9;
191     explodeSound2 = new Audio('media/explosion.wav');
192     explodeSound2.volume = 0.9;
193 
194     wingsSound = new Audio('media/wings.wav');
195     wingsSound.volume = 0.9;
196     wingsSound.addEventListener('ended', function() { // loop wings sound
197         this.currentTime = 0;
198         this.play();
199     }, false);
200     wingsSound.play();
201 
202     // 加载各种图片
203     var oBallImage = new Image();
204     oBallImage.src = 'images/fireball.png';
205     oBallImage.onload = function() { }
206 
207     var oEnemyImage = new Image();
208     oEnemyImage.src = 'images/enemy.png';
209     oEnemyImage.onload = function() { }
210 
211     var oDragonImage = new Image();
212     oDragonImage.src = 'images/dragon.gif';
213     oDragonImage.onload = function() {
214         dragon = new Dragon(400, 300, dragonW, dragonH, oDragonImage);
215     }
216 
217     $('#scene').mousedown(function(e) { // 处理鼠标按下
218         var mouseX = e.layerX || 0;
219         var mouseY = e.layerY || 0;
220         if(e.originalEvent.layerX) { // jquery 1.7之后用下面这种方式
221             mouseX = e.originalEvent.layerX;
222             mouseY = e.originalEvent.layerY;
223         }
224 
225         bMouseDown = true;
226 
227         if (mouseX > dragon.x- dragon.w/2 && mouseX < dragon.x- dragon.w/2 +dragon.w &&
228             mouseY > dragon.y- dragon.h/2 && mouseY < dragon.y-dragon.h/2 +dragon.h) {
229 
230             dragon.bDrag = true;
231             dragon.x = mouseX;
232             dragon.y = mouseY;
233         }
234     });
235 
236     $('#scene').mousemove(function(e) { // 处理鼠标移动
237         var mouseX = e.layerX || 0;
238         var mouseY = e.layerY || 0;
239         if(e.originalEvent.layerX) {
240             mouseX = e.originalEvent.layerX;
241             mouseY = e.originalEvent.layerY;
242         }
243 
244         // 保存上次鼠标的位置
245         iLastMouseX = mouseX;
246         iLastMouseY = mouseY;
247 
248         // 执行龙的拖动
249         if (dragon.bDrag) {
250             dragon.x = mouseX;
251             dragon.y = mouseY;
252         }
253 
254         // 根据鼠标的位置,改变龙的方向
255         if (mouseX > dragon.x && Math.abs(mouseY-dragon.y) < dragon.w/2) {
256             iSprDir = 0;
257         } else if (mouseX < dragon.x && Math.abs(mouseY-dragon.y) < dragon.w/2) {
258             iSprDir = 4;
259         } else if (mouseY > dragon.y && Math.abs(mouseX-dragon.x) < dragon.h/2) {
260             iSprDir = 2;
261         } else if (mouseY < dragon.y && Math.abs(mouseX-dragon.x) < dragon.h/2) {
262             iSprDir = 6;
263         } else if (mouseY < dragon.y && mouseX < dragon.x) {
264             iSprDir = 5;
265         } else if (mouseY < dragon.y && mouseX > dragon.x) {
266             iSprDir = 7;
267         } else if (mouseY > dragon.y && mouseX < dragon.x) {
268             iSprDir = 3;
269         } else if (mouseY > dragon.y && mouseX > dragon.x) {
270             iSprDir = 1;
271         }
272     });
273 
274     $('#scene').mouseup(function(e) { // 处理鼠标释放事件
275         dragon.bDrag = false;
276         bMouseDown = false;
277 
278         // play dragon sound
279         dragonSound.currentTime = 0;
280         dragonSound.play();
281     });
282 
283     $(window).keydown(function(event){ // 按键1,开火
284         switch (event.keyCode) {
285             case 49: // '1' key
286                 balls.push(new Ball(dragon.x, dragon.y, 32, 32, iBallSpeed, oBallImage));
287 
288                 // play explode sound #1
289                 explodeSound.currentTime = 0;
290                 explodeSound.play();
291                 break;
292         }
293     });
294 
295     setInterval(drawScene, 30); // loop drawScene
296 
297     // 随机生产出敌人
298     var enTimer = null;
299     function addEnemy() {
300         clearInterval(enTimer);
301 
302         var randY = getRand(0, canvas.height - iEnemyH);
303         enemies.push(new Enemy(canvas.width, randY, iEnemyW, iEnemyH, - iEnemySpeed, oEnemyImage));
304 
305         var interval = getRand(5000, 10000);
306         enTimer = setInterval(addEnemy, interval); // loop drawScene
307     }
308     addEnemy();
309 });

在上面代码的开始处,我增加了两个新对象,球和敌人。每个对象都有他们自己的属性集(比如位置,大小,图片,速度),然后通过‘drawScene’方法来绘制他们,在该方法底部,你可以看到处理球和敌人的碰撞检测代码:

 1 // 检测是否击中敌人
 2     if (balls.length > 0) {
 3         for (var key in balls) {
 4             if (balls[key] != undefined) {
 5 
 6                 if (enemies.length > 0) {
 7                     for (var ekey in enemies) {
 8                         if (enemies[ekey] != undefined && balls[key] != undefined) {
 9                             if (balls[key].x + balls[key].w > enemies[ekey].x && balls[key].y + balls[key].h > enemies[ekey].y 
10                                 && balls[key].y < enemies[ekey].y + enemies[ekey].h) {
11                                 delete enemies[ekey];
12                                 delete balls[key];
13                                 iScore++;
14 
15                                 explodeSound2.currentTime = 0;
16                                 explodeSound2.play();
17                             }
18                         }
19                     }
20                 }
21             }
22         }
23     }
View Code

最后,我们通过下面的代码不定时间的增加敌人:

 1 // 随机生产出敌人
 2     var enTimer = null;
 3     function addEnemy() {
 4         clearInterval(enTimer);
 5 
 6         var randY = getRand(0, canvas.height - iEnemyH);
 7         enemies.push(new Enemy(canvas.width, randY, iEnemyW, iEnemyH, - iEnemySpeed, oEnemyImage));
 8 
 9         var interval = getRand(5000, 10000);
10         enTimer = setInterval(addEnemy, interval); // loop drawScene
11     }
12     addEnemy();

 

 第四步:Custom files

  • images/dragon.gif, images/enemy.png, images/fireball.png, images/hell.jpg

  • media/dragon.wav, media/explode1.wav, media/explosion.wav, media/laught.wav, media/wings.wav

上面所有的文件都在源码包里。

posted @ 2013-08-25 22:28  bells  阅读(859)  评论(0编辑  收藏  举报