小强的HTML5移动开发之路(9)——坦克大战游戏3
上一篇我们创建了敌人的坦克和自己的坦克,接下来就应该让坦克发子弹了,我们下面来看一下如何让我们的坦克发出子弹。
前面我们用面向对象的思想对Tank进行了封装,又利用对象冒充实现了我们的坦克和敌人的坦克,仿照这种方式我们是不是也应该封装一个Bullet,答案是肯定的。好吧,那么我们再想想这个Bullet"类“都应该封装什么东西呢?位置应该有吧、子弹飞行的方向应该有吧、飞行的速度也应该有吧、自己飞出去的动作应该有吧。好啦,大概就这些,封装后的Bulle”t类“如下:
//子弹类 function Bullet(x,y,direct,speed){ this.x=x; this.y=y; this.speed=speed; this.direct=direct; this.timer=null; this.run=function(){ 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; } } }
我们已经创建好子弹的模型了,下面就用我们的坦克创造子弹将子弹发出去,在Hero类中添加shotEnemy方法。
//定义一个Hero类 function Hero(x,y,direct,color){ //下面两句话的作用是通过对象冒充达到继承的效果 this.tank=Tank; this.tank(x,y,direct,color); //射击敌人函数 this.shotEnemy=function(){ switch(this.direct){ case 0: heroBullet=new Bullet(this.x+10,this.y,this.direct,1); break; case 1: heroBullet=new Bullet(this.x+30-4,this.y+10+4,this.direct,1); break; case 2: heroBullet=new Bullet(this.x+10,this.y+30,this.direct,1); break; case 3: heroBullet=new Bullet(this.x-4,this.y+10+4,this.direct,1); break; } //把这个子弹放入数组中——》push函数 //调用我们子弹的run //var timer=window.setInterval("heroBullet.run()",50); //heroBullet.timer=timer; heroBullets.push(heroBullet); var timer=window.setInterval("heroBullets["+(heroBullets.length-1)+"].run()",50); heroBullets[heroBullets.length-1].timer=timer; } }
再在按键监听函数中添加一个监听发射子弹的键“J"
case 74: //J :发子弹 hero.shotEnemy(); break;
好了我们来试着发射一下子弹吧!子弹怎么只能发一颗,而且越发越快,这是怎么回事呢?再看看我们上面写的代码,原来我们的子弹一旦发出去就不能停止了,虽然跑出了我们的”战场“但是还是在朝一个方向跑,一旦发第二颗子弹第一颗子弹就会由于重新刷新界面没有重绘子弹而消失。好了既然知道原因了下面我们判断一下子弹是否出界,然后给子弹一个状态isLive(这个状态标记子弹是否存在,如果不存在则在重绘子弹的时候不再重绘),修改后的代码如下:
立即学习“前端免费学习笔记(深入)”;
//子弹类 unction Bullet(x,y,direct,speed){ this.x=x; this.y=y; this.speed=speed; this.direct=direct; this.timer=null; this.isLive=true; this.run=function(){ //判断子弹是否已经到边界了 if(this.x<=0||this.x>=400||this.y<=0||this.y>=300){ //子弹要停止 window.clearInterval(this.timer); //子弹死亡 this.isLive=false; }else{ //可以去修改坐标 switch(this.direct){ case 0: this.y-=this.speed; break; case 1: this.x+=this.speed; break; case 2: break; } } }
如果子弹超出了canvas的范围则将isLive属性该为false
然后我们在前面的刷新界面函数中添加一个刷新子弹函数
//定时刷新我们的作战区(定时重绘) //自己的坦克,敌人坦克,子弹,炸弹,障碍物 function flashTankMap(){ //把画布清理 cxt.clearRect(0,0,400,300); //我的坦克 drawTank(hero); //我的子弹 drawHeroBullet(); //敌人的坦克 for(var i=0;i<3;i++){ drawTank(enemyTanks[i]); } }
//画出自己的子弹 function drawHeroBullet(){ for(var i=0;i<heroBullets.length;i++){ var heroBullet=heroBullets[i]; if(heroBullet!=null&&heroBullet.isLive){ cxt.fillStyle="#FEF26E"; cxt.fillRect(heroBullet.x,heroBullet.y,2,2); } } }
可以看到上面的drawHeroBullet中判断了子弹的isLive属性。
看看运行结果吧
全部源代码如下:
tankGame06.js
//为了编程方便,我们定义两个颜色数组 var heroColor=new Array("#BA9658","#FEF26E"); var enemyColor=new Array("#00A2B5","#00FEFE"); //子弹类 function Bullet(x,y,direct,speed){ this.x=x; this.y=y; this.speed=speed; this.direct=direct; this.timer=null; this.isLive=true; this.run=function(){ //判断子弹是否已经到边界了 if(this.x<=0||this.x>=400||this.y<=0||this.y>=300){ //子弹要停止 window.clearInterval(this.timer); //子弹死亡 this.isLive=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; } } } } //定义一个Tank类(基类) function Tank(x,y,direct,color){ this.x=x; this.y=y; this.speed=1; 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类 function Hero(x,y,direct,color){ //下面两句话的作用是通过对象冒充达到继承的效果 this.tank=Tank; this.tank(x,y,direct,color); //设计敌人函数 this.shotEnemy=function(){ switch(this.direct){ case 0: heroBullet=new Bullet(this.x+10,this.y,this.direct,1); break; case 1: heroBullet=new Bullet(this.x+30-4,this.y+10+4,this.direct,1); break; case 2: heroBullet=new Bullet(this.x+10,this.y+30,this.direct,1); break; case 3: heroBullet=new Bullet(this.x-4,this.y+10+4,this.direct,1); break; } //把这个子弹放入数组中——》push函数 //调用我们子弹的run //var timer=window.setInterval("heroBullet.run()",50); //heroBullet.timer=timer; heroBullets.push(heroBullet); var timer=window.setInterval("heroBullets["+(heroBullets.length-1)+"].run()",50); heroBullets[heroBullets.length-1].timer=timer; } } //定义一个EnemyTank类 function EnemyTank(x,y,direct,color){ this.tank=Tank; this.tank(x,y,direct,color); } //绘制坦克 function drawTank(tank){ //考虑方向 switch(tank.direct){ case 0: //向上 case 2: //向下 //设置颜色 cxt.fillStyle=tank.color[0]; //左边的矩形 cxt.fillRect(tank.x,tank.y,5,30); //右边的矩形 cxt.fillRect(tank.x+17,tank.y,5,30); //画中间的矩形 cxt.fillRect(tank.x+6,tank.y+5,10,20); //画出坦克的盖子 cxt.fillStyle=tank.color[1]; cxt.arc(tank.x+11,tank.y+15,5,0,Math.PI*2,true); cxt.fill(); //画出炮筒 cxt.strokeStyle=tank.color[1]; cxt.lineWidth=1.5; cxt.beginPath(); cxt.moveTo(tank.x+11,tank.y+15); if(tank.direct==0){ //只是炮筒的方向不同 cxt.lineTo(tank.x+11,tank.y); }else{ cxt.lineTo(tank.x+11,tank.y+30); } cxt.closePath(); cxt.stroke(); break; case 1: case 3: //设置颜色 cxt.fillStyle="#BA9658"; //上边的矩形 cxt.fillRect(tank.x-4,tank.y+4,30,5); //下边的矩形 cxt.fillRect(tank.x-4,tank.y+17+4,30,5); //画中间的矩形 cxt.fillRect(tank.x+5-4,tank.y+6+4,20,10); //画出坦克的盖子 cxt.fillStyle="#FEF26E"; cxt.arc(tank.x+15-4,tank.y+11+4,5,0,Math.PI*2,true); cxt.fill(); //画出炮筒 cxt.strokeStyle="#FEF26E"; cxt.lineWidth=1.5; cxt.beginPath(); cxt.moveTo(tank.x+15-4,tank.y+11+4); if(tank.direct==1){ //只是炮筒的方向不同 cxt.lineTo(tank.x+30-4,tank.y+11+4); }else{ cxt.lineTo(tank.x-4,tank.y+11+4); } cxt.closePath(); cxt.stroke(); break; } }
坦克大战.html
<!DOCTYPE html> <html> <head> <meta charset="utf-8"/> </head> <body onkeydown="getCommand();"> <h1>html5-坦克大战</h1> <!--坦克大战的战场--> <canvas id="tankMap" width="400px" height="300px" style="background-color:black"></canvas> <!--将tankGame04.js引入--> <script type="text/javascript" src="tankGame06.js"></script> <script type="text/javascript"> //得到画布 var canvas1=document.getElementById("tankMap"); //得到绘图上下文 var cxt=canvas1.getContext("2d"); //我的tank //规定0向上、1向右、2向下、3向左 var hero=new Hero(40,40,0,heroColor); //定义子弹数组 var heroBullets=new Array(); //敌人的tank var enemyTanks=new Array(); for(var i=0;i<3;i++){ var enemyTank = new EnemyTank((i+1)*50,0,2,enemyColor); enemyTanks[i]=enemyTank; } //画出自己的子弹 function drawHeroBullet(){ for(var i=0;i<heroBullets.length;i++){ var heroBullet=heroBullets[i]; if(heroBullet!=null&&heroBullet.isLive){ cxt.fillStyle="#FEF26E"; cxt.fillRect(heroBullet.x,heroBullet.y,2,2); } } } //定时刷新我们的作战区(定时重绘) //自己的坦克,敌人坦克,子弹,炸弹,障碍物 function flashTankMap(){ //把画布清理 cxt.clearRect(0,0,400,300); //我的坦克 drawTank(hero); //我的子弹 drawHeroBullet(); //敌人的坦克 for(var i=0;i<3;i++){ drawTank(enemyTanks[i]); } } flashTankMap(); //接收用户按键的函数 function getCommand(){ var code = event.keyCode; //键盘上字幕的ASCII码 switch(code){ case 87: //W :上 hero.moveUp(); break; case 68: //D :右 hero.moveRight(); break; case 83: //S :下 hero.moveDown(); break; case 65: //A :左 hero.moveLeft(); break; case 74: //J :发子弹 hero.shotEnemy(); break; } flashTankMap(); } //每隔100毫秒去刷新一次作战区 window.setInterval("flashTankMap()",100); </script> </body> </html>