zoukankan      html  css  js  c++  java
  • 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

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

  • 相关阅读:
    STM32 F4 DAC DMA Waveform Generator
    STM32 F4 General-purpose Timers for Periodic Interrupts
    Python第十四天 序列化 pickle模块 cPickle模块 JSON模块 API的两种格式
    Python第十三天 django 1.6 导入模板 定义数据模型 访问数据库 GET和POST方法 SimpleCMDB项目 urllib模块 urllib2模块 httplib模块 django和web服务器整合 wsgi模块 gunicorn模块
    查看SQL Server服务运行帐户和SQL Server的所有注册表项
    Pycharm使用技巧(转载)
    SQL Server 2014内存优化表的使用场景
    Python第十天 print >> f,和fd.write()的区别 stdout的buffer 标准输入 标准输出 从控制台重定向到文件 标准错误 重定向 输出流和输入流 捕获sys.exit()调用 optparse argparse
    Python第七天 函数 函数参数 函数里的变量 函数返回值 多类型传值 函数递归调用 匿名函数 内置函数
    Python第六天 类型转换
  • 原文地址:https://www.cnblogs.com/pigzhu/p/3281537.html
Copyright © 2011-2022 走看看