上一篇我们创建了敌人的坦克和自己的坦克,接下来就应该让坦克发子弹了,我们下面来看一下如何让我们的坦克发出子弹。

前面我们用面向对象的思想对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(这个状态标记子弹是否存在,如果不存在则在重绘子弹的时候不再重绘),修改后的代码如下:

		//子弹类
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:
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>

[置顶] 小强的HTML5移动开发之路(9)——坦克大战游戏3的更多相关文章

  1. 小强的HTML5移动开发之路(18)——HTML5地理定位

    来自:http://blog.csdn.net/dawanganban/article/details/18192091 在前面的<小强的HTML5移动开发之路(2)--HTML5的新特性> ...

  2. 小强的HTML5移动开发之路(14)——Video标签详解

    来自:http://blog.csdn.net/dawanganban/article/details/18180605 在前面的小强的HTML5移动开发之路(5)--制作一个漂亮的视频播放器中制作了 ...

  3. 小强的HTML5移动开发之路(13)——HTML5中的全局属性

    来自:http://blog.csdn.net/dawanganban/article/details/18179483 一.accssskey  快捷键 <!DOCTYPE HTML> ...

  4. 小强的HTML5移动开发之路(11)——链接,图片,表格,框架

    来自:http://blog.csdn.net/dawanganban/article/details/18098193 一.HTML是什么? HTML(hypertext mark-uplangua ...

  5. 小强的HTML5移动开发之路(42)——HTML4与HTML5文档结构比较

    一般来说,人们在书写包括HTML在内的文档时,习惯上按照类似于"章--节--小节"这样的层次结构来进行. 在HTML4中的描述方式: <html> <head&g ...

  6. 小强的HTML5移动开发之路(37)——jqMobi快速入门

    在<小强的HTML5移动开发之路(33)-- jqMobi基础>中我们了解了什么是jqMobi,并从官方下载了jqMobi开发包,下载后解压目录如下: 拷贝上面的/css目录./plugi ...

  7. 小强的HTML5移动开发之路(2)——HTML5的新特性

    来自:http://blog.csdn.net/dawanganban/article/details/17592787 一.画布(Canvas) 画布是网页中的一块区域,可所以用JavaScript ...

  8. 小强的HTML5移动开发之路(7)——坦克大战游戏1

    来自:http://blog.csdn.net/dawanganban/article/details/17693145 上一篇中我们介绍了关于Canvas的基础知识,用Canvas绘制各种图形和图片 ...

  9. 小强的HTML5移动开发之路(12)——从一个多媒体标签说起

    来自:http://blog.csdn.net/dawanganban/article/details/18136813 一.视频播放 <html> <head> <ti ...

随机推荐

  1. Service完全解析(转)

    今天我们来讲一下Android中Service的相关内容. Service在Android中和Activity是属于同一级别上的组件,我们可以将他们认为是两个好哥们,Activity仪表不凡,迷倒万千 ...

  2. linux VFS 内核数据结构

    <strong>简单归纳:fd只是一个整数,在open时产生.起到一个索引的作用,进程通过PCB中的文件描述符表找到该fd所指向的文件指针filp.</strong> 文件描述 ...

  3. 一天一点MySQL复习——存储过程

    一.存储过程概念 使用SQL编写访问数据库的代码时,可用两种方法存储和执行这些代码,一种是在客户端存储代码,并创建向数据库服务器发送的SQL命令(或SQL语句),比如在C#.Java等客户端编程语言中 ...

  4. 【转】IOS中定时器NSTimer的开启与关闭

    原文网址:http://blog.csdn.net/enuola/article/details/8099461 调用一次计时器方法: myTimer = [NSTimer scheduledTime ...

  5. Android无法调用JS的问题解决

    1.启用JS webView.getSettings().setJavaScriptEnabled(true); 2.需要使用WebChromeClient(如果没有这个Client,很多东西不会响应 ...

  6. HEAD

    Branches are just pointers to commits Every branch is simply a named pointer to a commit. A special ...

  7. linux中ls命令详解 (转)

    -a -- 全部(all).列举目录中的全部文件,包括隐藏文件(.filename).位于这个列表的起首处的 .. 和 . 依次是指父目录和你的当前目录.      -l -- 长(long).列举目 ...

  8. iOS学习笔记之Category

    iOS学习笔记之Category 写在前面 Category是类别(也称为类目或范畴),使用Category,程序员可以为任何已有的类添加方法.使用类别可以对框架提供的类(无法获取源码,不能直接修改) ...

  9. EIGRP汇总

    转自:http://myhat.blog.51cto.com/391263/193189/ 实验目的:1.理解EIGRP的自动汇总的缺点2.配置EIGRP手工汇总的方法A>>>还是老 ...

  10. Win7+VS2013初试Thrift

    win7环境下VS2013编译boost_1_58_0步骤: 官网下载boost_1_58_0(直接下载),解压 cmd窗口cd到boost_1_58_0,执行bootstrap.bat cmd窗口获 ...