[置顶] 小强的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(这个状态标记子弹是否存在,如果不存在则在重绘子弹的时候不再重绘),修改后的代码如下:
//子弹类
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的更多相关文章
- 小强的HTML5移动开发之路(18)——HTML5地理定位
来自:http://blog.csdn.net/dawanganban/article/details/18192091 在前面的<小强的HTML5移动开发之路(2)--HTML5的新特性> ...
- 小强的HTML5移动开发之路(14)——Video标签详解
来自:http://blog.csdn.net/dawanganban/article/details/18180605 在前面的小强的HTML5移动开发之路(5)--制作一个漂亮的视频播放器中制作了 ...
- 小强的HTML5移动开发之路(13)——HTML5中的全局属性
来自:http://blog.csdn.net/dawanganban/article/details/18179483 一.accssskey 快捷键 <!DOCTYPE HTML> ...
- 小强的HTML5移动开发之路(11)——链接,图片,表格,框架
来自:http://blog.csdn.net/dawanganban/article/details/18098193 一.HTML是什么? HTML(hypertext mark-uplangua ...
- 小强的HTML5移动开发之路(42)——HTML4与HTML5文档结构比较
一般来说,人们在书写包括HTML在内的文档时,习惯上按照类似于"章--节--小节"这样的层次结构来进行. 在HTML4中的描述方式: <html> <head&g ...
- 小强的HTML5移动开发之路(37)——jqMobi快速入门
在<小强的HTML5移动开发之路(33)-- jqMobi基础>中我们了解了什么是jqMobi,并从官方下载了jqMobi开发包,下载后解压目录如下: 拷贝上面的/css目录./plugi ...
- 小强的HTML5移动开发之路(2)——HTML5的新特性
来自:http://blog.csdn.net/dawanganban/article/details/17592787 一.画布(Canvas) 画布是网页中的一块区域,可所以用JavaScript ...
- 小强的HTML5移动开发之路(7)——坦克大战游戏1
来自:http://blog.csdn.net/dawanganban/article/details/17693145 上一篇中我们介绍了关于Canvas的基础知识,用Canvas绘制各种图形和图片 ...
- 小强的HTML5移动开发之路(12)——从一个多媒体标签说起
来自:http://blog.csdn.net/dawanganban/article/details/18136813 一.视频播放 <html> <head> <ti ...
随机推荐
- 【解题报告】POJ-1106 Transmitters
原题地址:http://poj.org/problem?id=1106 题目大意: 给定一些平面的点以及一个圆心和半径,过圆心作一个半圆,求点在半圆中点最多多少个. 解题思路: 首先将给定点中和圆心的 ...
- T-SQL备忘(4):分页
set statistics io on set statistics time on --SQL Server 2012分页方式 select * from Production.Product o ...
- jquery之on()绑定事件和off()解除绑定事件
off()函数用于移除元素上绑定的一个或多个事件的事件处理函数. off()函数主要用于解除由on()函数绑定的事件处理函数. 该函数属于jQuery对象(实例). 语法 jQuery 1.7 新增该 ...
- OpenLayers调用arcgis server发布的地图服务
有两种方式可以调用arcgis server发布的地图服务,一种是rest,一种是wms. 地图的投影为900913,arcgis server为10.0版本,地图服务的空间参考为3857. 与 ...
- centos mysq table is read only
1.进入mysql数据库目录,使用命令"chown -R mysql <数据库文件夹名称>" 2. "chgrp -R mysql <数据库文件夹名称& ...
- centos ssh 乱码
vim /etc/sysconfig/i18n 然后把里面的LANG="zh_CN.UTF-8"改成LANG="zh_CN.GB18030"
- POJ 2241 Mondriaan's Dream
题意:给一块n×m的空地,用1×2的砖铺,有多少种方案. 解法:状压dp.考虑dp[i][j]表示前i - 1行都铺满时第i行的状态为j时的方案数.对于第i行,每个格子上是否有砖用0和1表示,0表示不 ...
- js事件处理相关-实现一个div的拖拽
最终代码: <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" c ...
- YII Framework学习教程-YII的日志
日志的作用(此处省略1000字) YII中的日志很好很强大,允许你把日志信息存放到数据库,发送到制定email,存放咋文件中,意见显示页面是,甚至可以用来做性能分析. YII中日志的基本配置:/yii ...
- Linux目录初识
/ 根目录 /bin 存放必要的命令 /boot 存放内核以及启动所需的文件/dev 存放设备文件 /etc 存放系统配置文件 /home 普通用户的宿主目录,用户数据存放在其主目录中 /lib 存放 ...