• 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

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

  • 相关阅读:
    Python基础之元组tuple(带了枷锁的列表)
    Python基础之元组tuple(带了枷锁的列表)
    Python基础之列表
    Python基础之列表
    穷举法解决这个问题(1,2)
    二分查找
    正則表達式
    Restful WebService简介
    杭电1285确定比赛名次
    ACdream区域赛指导赛之手速赛系列(5) 题解
  • 原文地址:https://www.cnblogs.com/pigzhu/p/3281537.html
Copyright © 2020-2023  润新知