A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© chenzeyu81 初级黑马   /  2019-1-16 22:43  /  1095 人查看  /  0 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

HTML5+JS实现坦克大战小游戏
首先是关于html5的知识了。这里我们基本上只用了画布canvas来画坦克,还有就是html5的第一行<!DOCTYPE html>来说明这是一个使用html5写的页面,html5的特性之一就包括canvas,这是html中没有的标签。

        另外一个就是js了,涉及到的语法都是最简单、最基本的用法,这在代码中进行解释。同时,韩老师在这个视频中代码有个bug就是敌人坦克在死后依然会发子弹,小弟在此进行了修正。

       接下来最重要的就是我们要来分析一下坦克大战小游戏的设计思路:

       1、要有作战区域,这有canvas 可以帮我们解决。

       2、要有坦克,包括自己的、敌人的。

       3、要能有子弹,包括自己的、敌人的。

       4、要有炸弹。

       5、我的坦克要能按键发射子弹,敌人的坦克要能连续自动发射子弹。

       6、我的子弹打到敌人时子弹要消失,同时敌人爆炸并消失,不能再发子弹。

       以上是游戏设计的简单思路,这是初步设计,接下来以代码来分析详细的设计过程:

       步骤一:

          组织代码,为了代码易读,而且我使用的是html5+js来实现,自不必多说,使用tankGame.js+tankGame.html来组织我的代码,js用于类以及方法的实现过程,html实现函数调用以及网页的显示。

       步骤二:设计作战区域:

         code 1 from tankeGame.html

<canvas id="tankMap" width="500px" height="500px" style="background-color:black"></canvas>

    <pre class="html" name="code"><script type="text/javascript">
     
        //得到画布
        var canvas1=document.getElementById("tankMap");
        //获得画图工具

    var cxt=canvas1.getContext("2d");</script>

    <script type="text/javascript">
        //得到画布
        var canvas1=document.getElementById("tankMap");
        //得到绘图上下文(你可以理解是画笔)
        var cxt=canvas1.getContext("2d");</script>


                     

     步骤三:画坦克,包括自己的和敌人的:

// 基类,里面有基本的共有属性和方法

    function Tank(x,y,direct,color){
        
            this.x=x;
            this.y=y;
            this.speed=1;
            this.isLive=true;
            this.direct=direct;
            //一个坦克,需要两个颜色.
            this.color=color;
            //上移
            this.moveUp=function(){
                this.y-=this.speed;
                this.direct=0;
            }
            //向右
            this.moveRight=function(){
                this.x+=this.speed;
                this.direct=1;
            }
     
            //下移
            this.moveDown=function(){
                this.y+=this.speed;
                this.direct=2;
            }
            //左
            this.moveLeft=function(){
                this.x-=this.speed;
                this.direct=3;
            }
    }


//子类Hero和EnemyTanke继承自基类。注意继承的方法。

    //定义一个Hero类
        //x 表示坦克的 横坐标, y 表示纵坐标, direct 方向   
        function Hero(x,y,direct,color){
        
            //继承的方法和格式,tank其实就是一个对象
            this.tank=Tank;
            this.tank(x,y,direct,color);
     
            //增加一个私有函数,射击敌人坦克.
            this.shotEnemy=function(){
               
                //创建子弹, 子弹的位置应该和hero有关系,并且和hero的方向有关
                switch(this.direct){
                    case 0:
                    heroBullet=new Bullet(this.x+9,this.y,this.direct,3,"hero",this);
                    break;
                    case 1:
                    heroBullet=new Bullet(this.x+30,this.y+9,this.direct,3,"hero",this);
                    break;
                    case 2:
                    heroBullet=new Bullet(this.x+9,this.y+30,this.direct,3,"hero",this);
                    break;
                    case 3: //右
                    heroBullet=new Bullet(this.x,this.y+9,this.direct,3,"hero",this);
                    break;
                }
     
                //把这个子弹对象放入到数组中     -> push函数
                heroBullets.push(heroBullet);
                //定时器.
                var timer=window.setInterval("heroBullets["+(heroBullets.length-1)+"].run()",50);
                //把这个timer赋给这个子弹(js对象是引用传递!)
                heroBullets[heroBullets.length-1].timer=timer;
     
        }

}

     //定义一个EnemyTank类
     function EnemyTank (x,y,direct,color){
      
      //继承Tank
      this.tank=Tank;
      this.count=0;
      this.bulletIsLive=true;
      
      this.tank(x,y,direct,color);
      this.qetBullet=null;
      this.run=function run(){
      
       //判断敌人的坦克当前方向
       switch(this.direct){
        
        case 0:
         if(this.y>0){
          this.y-=this.speed;
         }
         break;
        case 1:
         if(this.x+30<400){
          this.x+=this.speed;
         }
         break;
        case 2:
         if(this.y+30<300){
          this.y+=this.speed;
         }
         break;
        case 3:
         if(this.x>0){
          this.x-=this.speed;
         }
         break;
       }
       //改变方向,走50次,再改变方向
       if(this.count>50){
        this.direct=Math.round(Math.random()*3);//随机生成 0,1,2,3
        this.count=0;
       }
       this.count++;
       //判断敌人坦克是否还活着
       //if(this.tank.isLive==true){
       //判断子弹是否已经死亡,如果死亡,则增加新的一颗子弹
       if(this.bulletIsLive==false){
        //增子弹,这是需要考虑当前这个敌人坦克的方向,在增加子弹
         switch(this.direct){
          case 0:
           qetBullet=new Bullet(this.x+9,this.y,this.direct,3,"enemy",this);
          break;
          case 1:
           qetBullet=new Bullet(this.x+30,this.y+9,this.direct,3,"enemy",this);
          break;
          case 2:
           qetBullet=new Bullet(this.x+9,this.y+30,this.direct,3,"enemy",this);
          break;
          case 3: //右
          qetBullet=new Bullet(this.x,this.y+9,this.direct,3,"enemy",this);
          break;
            }</p><p>    //把子弹添加到敌人子弹数组中
        enemyBullets.push(qetBullet);
        //启动新子弹run
        var mytimer=window.setInterval("enemyBullets["+(enemyBullets.length-1)+"].run()",50);
        enemyBullets[enemyBullets.length-1].timer=mytimer;</p><p>    this.bulletIsLive=true;
       }
      }
     

    //绘制坦克(敌人坦克和自己的坦克)
        function drawTank(tank){
        
            //说明所有的坦克都要isLive这个属性
            if(tank.isLive){
            
     
                //考虑方向
                switch(tank.direct){
     
                case 0: //上
                case 2:// 下
                    //画出自己的坦克,使用前面的绘图技术
                    //设置颜色
                    cxt.fillStyle=tank.color[0];
                    //韩老师使用 先死--->后活 (初学者最好用这个方法)
                    //先画出左面的矩形
                    cxt.fillRect(tank.x,tank.y,5,30);
                    //画出右边的矩形(这时请大家思路->一定要一个参照点)
                    cxt.fillRect(tank.x+15,tank.y,5,30);
                    //画出中间矩形
                    cxt.fillRect(tank.x+6,tank.y+5,8,20);
                    //画出坦克的盖子
                    cxt.fillStyle=tank.color[1];
                    cxt.arc(tank.x+10,tank.y+15,4,0,360,true);
                    cxt.fill();
                    //画出炮筒(直线)
                    cxt.strokeStyle=tank.color[1];
                    //设置线条的宽度
                    cxt.lineWidth=1.5;
                    cxt.beginPath();
                    cxt.moveTo(tank.x+10,tank.y+15);
                    
                    if(tank.direct==0){
                    cxt.lineTo(tank.x+10,tank.y);
                    }else if(tank.direct==2){
                    cxt.lineTo(tank.x+10,tank.y+30);
                    }
     
                    cxt.closePath();
                    cxt.stroke();
                    break;
                case 1: //右和左
                case 3:
                    //画出自己的坦克,使用前面的绘图技术
                    //设置颜色
                    cxt.fillStyle=tank.color[0];
                    //韩老师使用 先死--->后活 (初学者最好用这个方法)
                    //先画出左面的矩形
                    cxt.fillRect(tank.x,tank.y,30,5);
                    //画出右边的矩形(这时请大家思路->一定要一个参照点)
                    cxt.fillRect(tank.x,tank.y+15,30,5);
                    //画出中间矩形
                    cxt.fillRect(tank.x+5,tank.y+6,20,8);
                    //画出坦克的盖子
                    cxt.fillStyle=tank.color[1];
                    cxt.arc(tank.x+15,tank.y+10,4,0,360,true);
                    cxt.fill();
                    //画出炮筒(直线)
                    cxt.strokeStyle=tank.color[1];
                    //设置线条的宽度
                    cxt.lineWidth=1.5;
                    cxt.beginPath();
                    cxt.moveTo(tank.x+15,tank.y+10);
                    //向右
                    if(tank.direct==1){
                    cxt.lineTo(tank.x+30,tank.y+10);
                    }else if(tank.direct==3){ //向左
                    cxt.lineTo(tank.x,tank.y+10);
                    }
     
                    cxt.closePath();
                    cxt.stroke();
                    break;
     
                }
            }
        }

步骤四:画子弹:

    type表示:这颗子弹是敌人的,还是自己的
    //tank表示对象,说明这颗子弹,属于哪个坦克.
    function Bullet(x,y,direct,speed,type,tank){
        this.x=x;
        this.y=y;
        this.direct=direct;
        this.speed=speed;
        this.timer=null;
        this.isLive=true;
        this.type=type;
        this.tank=tank;
        this.run=function run(){
            
                //在该表这个子弹的坐标时,我们先判断子弹是否已经到边界
                //子弹不前进,有两个逻辑,1.碰到边界,2. 碰到敌人坦克.
                if(this.x<=0||this.x>=500||this.y<=0||this.y>=500||this.isLive==false){
                    //子弹要停止.
                    window.clearInterval(this.timer);
                    //子弹死亡
                    this.isLive=false;
     
                    if(this.type=="enemy"){
                            this.tank.bulletIsLive=false;
                    }
                }else{
                    //坐标的移动代表子弹位置变化
                    switch(this.direct){
                        case 0:
                                this.y-=this.speed;
                                break;
                        case 1:
                                this.x+=this.speed;
                                break;
                        case 2:
                                this.y+=this.speed;
                                break;
                        case 3:
                                this.x-=this.speed;
                                break;
                    }
                }
     
        }
    }

//Bullet只是一个类,并没有画坦克的方法,需要我们自己设计,draw一个

    <pre class="javascript" name="code">//画出自己的子弹
            function drawHeroBullet(){
     
                    //现在要画出所有子弹
                    for( var i=0;i<heroBullets.length;i++){
                        var heroBullet=heroBullets;
                                      if(heroBullet!=null&&heroBullet.isLive){
                           cxt.fillStyle="#FEF26E";
                           cxt.fillRect(heroBullet.x,heroBullet.y,2,2);
                        }
                    }
     
            }
     
    //这里我们还需要添加一个函数,用于画出敌人的子弹
    function drawEnemyBullet(){
    //检查坦克是否还活着
    for(var j=0;j<enemyTanks.length;j++){
                        
        var enemyTank=enemyTanks[j];
                           
        if(enemyTank.isLive==true){
           for( var i=0;i<enemyBullets.length;i++){
           var etBullet=enemyBullets;
           if(etBullet!=null&&etBullet.isLive){
           cxt.fillStyle="#00FEFE";
           cxt.fillRect(etBullet.x,etBullet.y,2,2);
        }
           }
         }   
       }
    }        

    <p>步骤五:检测判断自己的坦克是否击中敌人坦克。</p><pre class="javascript" name="code">//编写一个函数,专门用于判断我的子弹,是否击中了某个敌人坦克
    function isHitEnemyTank(){
        
         //取出子弹
        for(var i=0;i<heroBullets.length;i++){
               
          //取出一颗子弹
          var heroBullet=heroBullets;
          if(heroBullet.isLive){ //子弹是活的,才去判断
                    //让这颗子弹去和遍历每个敌人坦克判断
          for(var j=0;j<enemyTanks.length;j++){
             var enemyTank=enemyTanks[j];
             if(enemyTank.isLive){
             //(看看这颗子弹,是否进入坦克所在矩形)
             //根据当时敌人坦克的方向来决定
             switch(enemyTank.direct){
            case 0: //敌人坦克向上
            case 2://敌人坦克向下
            if(heroBullet.x>=enemyTank.x&&heroBullet.x<=enemyTank.x+20
            &&heroBullet.y>=enemyTank.y&&heroBullet.y<=enemyTank.y+30){
            //把坦克isLive 设为false ,表示死亡
            enemyTank.isLive=false;
            //该子弹也死亡
            heroBullet.isLive=false;
            //创建一颗炸弹
            var bomb=new Bomb(enemyTank.x,enemyTank.y);
            //然后把该炸弹放入到bombs数组中
            bombs.push(bomb);
                }
                break;
                case 1: //敌人坦克向右
                case 3://敌人坦克向左

                         if(heroBullet.x>=enemyTank.x&&heroBullet.x<=enemyTank.x+30
                     &&heroBullet.y>=enemyTank.y&&heroBullet.y<=enemyTank.y+20){
                     //把坦克isLive 设为false ,表示死亡
                     enemyTank.isLive=false;
                     heroBullet.isLive=false;
     
                    //创建一颗炸弹
                var bomb=new Bomb(enemyTank.x,enemyTank.y);
                    //然后把该炸弹放入到bombs数组中
                bombs.push(bomb);
        }
        break;
     
        }
     
        }

         }//for
       }
      }
    }

步骤六:设计爆炸效果

    //定义一个炸弹类
    function Bomb(x,y){
        this.x=x;
        this.y=y;
        this.isLive=true; //炸弹是否活的,默认true;
        //炸弹有一个生命值
        this.blood=9;
        //减生命值
        this.bloodDown=function(){
            if(this.blood>0){
                this.blood--;
            }else{
                //说明炸弹死亡
                this.isLive=false;
            }
        }
    }


    //画出敌人炸弹
    function drawEnemyBomb(){
        
        for(var i=0;i<bombs.length;i++){
        
            //取出一颗炸弹
            var bomb=bombs;
            if(bomb.isLive){
     
     
               
                //更据当前这个炸弹的生命值,来画出不同的炸弹图片
                if(bomb.blood>6){  //显示最大炸弹图
                    var img1=new Image();
                    img1.src="picture/bomb_1.gif";
                    var x=bomb.x;
                    var y=bomb.y;
                    img1.onload=function(){
                        cxt.drawImage(img1,x,y,30,30);
                    }
                }else if(bomb.blood>3){
                    var img2=new Image();
                    img2.src="picture/bomb_2.gif";
                    var x=bomb.x;
                    var y=bomb.y;
                    img2.onload=function(){
                        cxt.drawImage(img2,x,y,30,30);
                    }
                }else {
                    var img3=new Image();
                    img3.src="picture/bomb_3.gif";
                    var x=bomb.x;
                    var y=bomb.y;
                    img3.onload=function(){
                        cxt.drawImage(img3,x,y,30,30);
                    }
                }
     
                //减血
                bomb.bloodDown();
                if(bomb.blood<=0){
                    //怎么办?把这个炸弹从数组中去掉
                    bombs.splice(i,1);
     
                }
            }
        }
    }

步骤七:响应键盘事件

    function getCommand(){
            
            //我怎么知道,玩家按下的是什么键
            //说明当按下键后 事件--->event对象----->事件处理函数()
            var code=event.keyCode;//对应字母的ascii码->我们看码表
            
            switch(code){
                case 87://上
                    hero.moveUp();
                    
                   break;
                case 68:
               
                  hero.moveRight();
                   break;
                 case 83:
                    
                    hero.moveDown();
                    break;
                case 65:
                    hero.moveLeft();
                    break;
                case 74:
                    hero.shotEnemy();
                    break;
            }


步骤八:页面刷新:

    //专门写一个函数,用于定时刷新我们的作战区,把要在作战区出现的元素(自己坦克,敌人坦克,子弹,炸弹,
        //障碍物...)->游戏思想
        function flashTankMap(){
            
            //把画布清理
            cxt.clearRect(0,0,500,500);
     
            //我的坦克
            drawTank(hero);
     
            //画出自己的子弹
            //子弹飞效果是怎么出现的?[答 : 首先我们应该每隔一定时间(setInterval)就去刷新作战区,如果在刷新的时候,子弹坐标变换了,给人的感觉就是子弹在飞!]
            drawHeroBullet();
     
            //敌人的坦克
            //判断一下敌人坦克是否击中
            isHitEnemyTank();
            drawEnemyBomb();
            drawEnemyBullet();
            
            //画出所有敌人坦克
            for(var i=0;i<3;i++){
                drawTank(enemyTanks);
            }
               
        }


---------------------
作者:Earl_Martin
来源:CSDN
原文:https://blog.csdn.net/u011181878/article/details/40506851
版权声明:本文为博主原创文章,转载请附上博文链接!

0 个回复

您需要登录后才可以回帖 登录 | 加入黑马