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

前面我们用面向对象的思想对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. django - 修改 自增长id,起始值

    常常你会遇到这样的情况,需要自增长的起始值是 0,再次从 0开始. 两个选择: 1. drop table_name; django重新建表. 2. ALTER TABLE table_name AU ...

  2. 2015-10-13 晴 tcp/ip卷1

    今年看tcp/ip卷1的内容.苦和甜来自外界,坚强则来自内心,来自一个人的自我努力. 只有勤奋和积极进取的人 才会赢得成功的人生.加油

  3. oracle 导入数据时提示只有 DBA 才能导入由其他 DBA 导出的文件

    提示: IMP-00013: 只有 DBA 才能导入由其他 DBA 导出的文件 IMP-00000: 未成功终止导入 解决方法: 用户system用户登录然后授权 grant dba to hszx

  4. 嵌入式 arm平台ping域名指定ip小结

    在fs的目录/etc/下添加文件hosts,然后内容修改如下: 192.168.11.12 qycam.com ping qycam.com 解析为192.168.11.12

  5. JVM内存结构之三--持久代

    本文会介绍一些JVM内存结构的基本概念,然后很快会讲到持久代,来看下Java SE 8发布后它究竟到哪去了. 基础知识 JVM只不过是运行在你系统上的另一个进程而已,这一切的魔法始于一个java命令. ...

  6. JVM 性能调优实战之:一次系统性能瓶颈的寻找过程

    玩过性能优化的朋友都清楚,性能优化的关键并不在于怎么进行优化,而在于怎么找到当前系统的性能瓶颈.性能优化分为好几个层次,比如系统层次.算法层次.代码层次…JVM 的性能优化被认为是底层优化,门槛较高, ...

  7. Delphi中实现MDI子窗体(转)

        Delphi中实现MDI子窗体 用MDI实现浏览子窗口,具有窗口管理功能,同屏观看多个网页的内容  ① 多文档窗体(MDI) MDI窗体是一种具有主子结构的窗体体系,微软的Word便是其中的一 ...

  8. 网络编程 --- URLConnection --- 读取服务器的数据 --- java

    使用URLConnection类获取服务器的数据 抽象类URLConnection表示一个指向指定URL资源的活动连接,它是java协议处理器机制的一部分. URL对象的openConnection( ...

  9. 数往知来 SQL SERVER 基本语法<七>

    sqlserver学习_01 启动数据库 开始->cmd->进入控制台    sqlcmd->-S .\sqlexpress    1> 如果出现表示数据库"sqle ...

  10. django 搭建自己的博客

    原文链接:http://www.errdev.com/post/4/ 每一个爱折腾的程序员都有自己的博客,好吧,虽然我不太喜欢写博客,但是这样骚包的想法却不断涌现.博客园虽好,可以没有完全的掌控感,搭 ...