zoukankan      html  css  js  c++  java
  • 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的本地存储。我非常乐意看见你的谢意和评论。好运!

  • 相关阅读:
    vue-cli3和element做一个简单的登陆页面
    用vue和layui简单写一个响应式数据展示表
    js中的AJAX
    js个人笔记简记
    解决sublime快捷键回车换行问题
    Sublime设置格式化代码快捷键ctrl+shift+r
    2020前端最新面试知识点汇总
    cookie,sessionstorage,localstorage区别
    linux/centos7安装mysql
    linux基本命令的操作
  • 原文地址:https://www.cnblogs.com/pigzhu/p/3214077.html
Copyright © 2011-2022 走看看