javascript 模拟坦克大战游戏(html5版)附源码下载


Posted in Javascript onApril 08, 2014

一、总结关键点和遇到的问题

1.javascript中的继承,最好父类只提供方法共享,属性写到各自子类中,避免父类和子类的构造函数混杂。

2.prototype模拟继承的代码,应写在所有方法定义之前,否则原型对象被改变,方法就变成了未定义,如:

Hero.prototype = new Tank (0, 0, 0); 
Hero.prototype.constructor = Hero; 
Hero.prototype.addLife = function(){ 
this.lifetimes++; 
document.querySelector("#life").innerHTML = hero.lifetimes; 
}

3.canvas画图形时,除了画矩形,其他的都要加上 ctx.beginPath();、ctx.closePath();,否则会出现意想不到的错误。

4.concat函数可以合并数组,或者是元素返回一个新的数组

5.Image的src属性赋值后就会加载图片,但如果没有加载完毕就画图片,会导致失效,所以使用onload事件处理

6.扩展Array功能,删除指定元素

//扩展 删除指定元素 
Array.prototype.deleteElement = function (obj) { 
if (obj) { 
for (var i = 0; i < this.length; i++) { 
if (this[i] === obj) { 
this.splice (i, 1); 
} 
} 
} 
}

7.定时器设置,setInterval(“fun”,1000)方法的第一个参数,可以是字符串,如"hero.say()",类似eval会去执行这串代码,所以它可以给函数带上参数,并且也指定了这个函数的运行上下文。但如果传入是函数的句柄,则不能带参数,并且不能指定上下文,除了第一种方式解决外,我用了闭包来解决这个问题
//定时器,自行运动 
this.timer = setInterval ((function (context) { 
return function () { 
Bullet.prototype.move.call (context) 
} 
}) (this), 30);

我保存了当前的执行环境,并调用call方法手动执行。

8.方法的功能设计,除了功能外,应该包括执行此功能的条件检测,如move,就应该包括什么情况下可以移动,移动到什么地方就不能移动了。此检测不应该放在外部。

9.写代码时不应该去想设计或者优化的问题,先实现功能,再谈优化,或者先设计再实现。思路要清晰,别混乱,着重于一点。

10.javascript中没有sleep的功能,可以创建一个变量作为缓冲,来达到间隔执行的目的

二、代码实现

1.本程序分为Bomb.js,Bullet.js,Draw.js,Tank.js,index.html,img,music,

2.最终效果

javascript 模拟坦克大战游戏(html5版)附源码下载

javascript 模拟坦克大战游戏(html5版)附源码下载

javascript 模拟坦克大战游戏(html5版)附源码下载 

3.代码

1.index.html

<!DOCTYPE html> 
<html> 
<head> 
<title></title> 
<meta charset="utf-8"> 
<style type="text/css"> 
body { 
font: 14px "sans-serif" 
} #Map { 
background-color: #000000; 
} 
.show { 
float: left 
} 
#guide { 
float: left; 
width: 200px; 
height: 390px; 
margin-left: 5px; 
background: #CCCCCC; 
padding: 5px; 
} 
</style> 
<script type="text/javascript" src="Tank.js"></script> 
<script type="text/javascript" src="Bullet.js"></script> 
<script type="text/javascript" src="Bomb.js"></script> 
<script type="text/javascript" src="Draw.js"></script> 
<script type="text/javascript"> 
window.onload = function () { 
//画布信息 
width = document.getElementById ('Map').width; 
height = document.getElementById ('Map').height; 
ctx = document.getElementById ('Map').getContext ('2d'); 
//初始页面 
var starImg = new Image (); 
starImg.src = "img/star.jpg"; 
starImg.onload = function () { 
ctx.drawImage (starImg, 0, 0, width, height); 
} 
//键盘监听 回车开始游戏 
document.body.onkeydown = function () { 
var keycode = event.keyCode; 
switch (keycode) { 
case 13: 
//初始化参数 
init () 
//刷新页面 
setInterval (draw, 30); 
document.body.onkeydown = gameControl; 
break; 
} 
} 
} 
function init () { 
//玩家和电脑 
hero = new Hero (100, 300, 0); 
enemys = []; 
for (var i = 0; i < 3; i++) { 
enemys.push (new Enemy (100 + i * 50, 0, 2)); 
} 
//合并数组 
allTank = enemys.concat (hero); 
//炸弹 
Bombs = []; 
im = new Image (); 
im2 = new Image (); 
im3 = new Image (); 
im.src = "img/bomb_3.gif"; 
im2.src = "img/bomb_2.gif"; 
im3.src = "img/bomb_1.gif"; 
} 
function gameControl () { 
var keycode = event.keyCode; 
switch (keycode) { 
case 65: 
hero.moveLeft (); 
break;//左 
case 83: 
hero.moveDown (); 
break;//下 
case 87: 
hero.moveUp (); 
break;//上 
case 68: 
hero.moveRight (); 
break;//右 
case 74: 
hero.shot (); 
break; 
case 49: 
hero.addLife () 
break; 
} 
} 
//扩展 删除指定元素 
Array.prototype.deleteElement = function (obj) { 
if (obj) { 
for (var i = 0; i < this.length; i++) { 
if (this[i] === obj) { 
this.splice (i, 1); 
} 
} 
} 
} 
</script> 
</head> 
<body> 
<div class="show"> 
<canvas id="Map" width="500px" height="400px"> 
</canvas> 
<audio id="music" autoplay="autoplay"> 
<source src="music/111.wav"> 
</audio> 
</div> 
<div id="guide"> 
<p>按下回车键开始游戏</p> 
<p>按下1键增加生命,默认是1</p> 
<p>剩余生命数 :<label id="life">1</label></p> 
<div id="data"> 
</div> 
</div> 
</body> 
</html>

2.Draw.js
/** 
* Created by Alane on 14-3-18. 
*/ function draw(){ 
//检测子弹和坦克生死 
checkDead(); 
//清空画布 
ctx.clearRect(0,0,500,400); 
//画玩家 
if(!hero.isdead){ 
drawTank(hero); 
}else{ 
hero.cutLife(); 
} 
//画敌人坦克 
for (var i = 0; i < enemys.length; i++) { 
drawTank(enemys[i]); 
} 
//画敌人子弹 
for(var j=0;j<enemys.length;j++){ 
var temp = enemys[j].bulletsList; 
for (var i = 0; i < temp.length; i++) { 
drawBullet(temp[i]); 
} 
} 
//画玩家子弹 
var temp = hero.bulletsList; 
for (var i = 0; i < temp.length; i++) { 
drawBullet(temp[i]); 
} 
//画炸弹 
for(var i=0;i<Bombs.length;i++){ 
drawBown(Bombs[i]); 
} 
} 
function drawTank(tank){ 
var x = tank.x; 
var y = tank.y; 
ctx.fillStyle = tank.color; 
if(tank.direct == 0 || tank.direct ==2){ 
ctx.fillRect(x, y, 5,30); 
ctx.fillRect(x+15, y, 5,30); 
ctx.fillRect(x+6, y+8, 8,15); 
ctx.strokeStyle = tank.color; 
ctx.lineWidth = '1.5'; 
if(tank.direct == 0){ 
ctx.beginPath(); 
ctx.moveTo(x+10,y-2); 
ctx.lineTo(x+10,y+8); 
ctx.closePath(); 
}else{ 
ctx.beginPath(); 
ctx.moveTo(x+10,y+24); 
ctx.lineTo(x+10,y+32); 
ctx.closePath(); 
} 
ctx.stroke(); 
}else{ 
ctx.fillRect(x, y, 30,5); 
ctx.fillRect(x, y+15, 30,5); 
ctx.fillRect(x+8, y+6, 15,8); 
ctx.strokeStyle = '#FF0000'; 
ctx.lineWidth = '1.5'; 
if(tank.direct == 3){ 
ctx.beginPath(); 
ctx.moveTo(x-2,y+10); 
ctx.lineTo(x+8,y+10); 
ctx.closePath(); 
}else{ 
ctx.beginPath(); 
ctx.moveTo(x+24,y+10); 
ctx.lineTo(x+32,y+10); 
ctx.closePath(); 
} 
ctx.stroke(); 
} 
} 
function drawBullet(bullet){ 
ctx.fillStyle = bullet.color; 
ctx.beginPath(); 
ctx.arc(bullet.x,bullet.y,2,360,true); 
ctx.closePath(); 
ctx.fill(); 
} 
function drawBown (obj){ 
if(obj.life>8){ 
ctx.drawImage(im,obj.x,obj.y,50,50); 
}else if(obj.life>4){ 
ctx.drawImage(im2,obj.x,obj.y,50,50); 
}else{ 
ctx.drawImage(im3,obj.x,obj.y,50,50); 
} 
obj.lifeDown(); 
if(obj.life<=0){ 
Bombs.deleteElement(obj); 
} 
} 
function checkDead(){ 
//检测敌人子弹生死 
for(var j=0;j<enemys.length;j++){ 
var temp = enemys[j].bulletsList; 
for (var i = 0; i < temp.length; i++) { 
var o = temp[i]; 
if(o.isdead){ 
temp.deleteElement(o); 
} 
} 
} 
//检测玩家子弹生死 
var temp = hero.bulletsList; 
for (var i = 0; i < temp.length; i++) { 
var o = temp[i]; 
if(o.isdead){ 
temp.deleteElement(o); 
} 
} 
//检测敌人坦克生死 
for (var i = 0; i < enemys.length; i++) { 
var o = enemys[i]; 
if(o.isdead){ 
enemys.deleteElement(o); 
} 
} 
}

Bomb.js
/** 
* Created by Alane on 14-3-18. 
*/ 
function Bomb(x,y){ 
this.life = 12; 
this.x = x; 
this.y = y; 
} 
Bomb.prototype.lifeDown = function(){ 
this.life--; 
}

Tank.js
/** 
* Created by Alane on 14-3-7. 
*/ 
/** 
* direct 0 上 
* 1 右 
* 2 下 
* 3 左 
* @param x 
* @param y 
* @param direct 
* @constructor 
*/ 
//******************************************************************************************/ 
//坦克父类 
function Tank (x, y, direct) { 
this.speed = 2; } 
Tank.prototype.moveUp = function () { 
//边界检测 
if (this.y < 0) { 
//换方向 
this.changeDirect (); 
return; 
} 
this.y -= this.speed; 
this.direct = 0; 
} 
Tank.prototype.moveDown = function () { 
if (this.y > height - 30) { 
this.changeDirect (); 
return; 
} 
this.y += this.speed; 
this.direct = 2; 
} 
Tank.prototype.moveLeft = function () { 
if (this.x < 0) { 
this.changeDirect (); 
return; 
} 
this.x -= this.speed; 
this.direct = 3; 
} 
Tank.prototype.moveRight = function () { 
if (this.x > width - 30) { 
this.changeDirect (); 
return; 
} 
this.x += this.speed; 
this.direct = 1; 
} 
//变换方向 
Tank.prototype.changeDirect = function () { 
while (true) { 
var temp = Math.round (Math.random () * 3); 
if (this.direct != temp) { 
this.direct = temp; 
break; 
} 
} 
//alert("x="+this.x+" y="+this.y+" direct="+this.direct) 
} 
//射击子弹 
Tank.prototype.shot = function () { 
if(this.isdead){ 
return; 
} 
if (this.bulletsList.length < this.maxBulletSize) { 
//新建子弹 
var bullet = null; 
switch (this.direct) { 
case 0: 
bullet = new Bullet (this.x + 10, this.y - 2, 0, this.color); 
break; 
case 1: 
bullet = new Bullet (this.x + 32, this.y + 10, 1, this.color); 
break; 
case 2: 
bullet = new Bullet (this.x + 10, this.y + 32, 2, this.color); 
break; 
case 3: 
bullet = new Bullet (this.x - 2, this.y + 10, 3, this.color); 
break; 
} 
//放入弹夹 
this.bulletsList.push (bullet); 
} 
} 
//******************************************************************************************/ 
//玩家 
function Hero (x, y, direct) { 
this.lifetimes = 5; 
this.isdead = false; 
this.color = '#FF0000'; 
this.x = x; 
this.y = y; 
this.direct = direct; 
this.bulletsList = []; 
this.maxBulletSize = 10; 
this.newlife = null; 
} 
Hero.prototype = new Tank (0, 0, 0); 
Hero.prototype.constructor = Hero; 
Hero.prototype.addLife = function(){ 
this.lifetimes++; 
document.querySelector("#life").innerHTML = hero.lifetimes; 
} 
Hero.prototype.cutLife = function(){ 
if(this.lifetimes>=1 && !this.newlife){ 
this.lifetimes--; 
this.newlife = setTimeout("hero.newLife()",2000); 
} 
} 
Hero.prototype.newLife = function(){ 
this.isdead = false; 
clearTimeout(hero.newlife); 
hero.newlife = null; 
document.querySelector("#life").innerHTML = hero.lifetimes; 
} 

//******************************************************************************************/ 
//敌人坦克 
function Enemy (x, y, direct) { 
this.isdead = false; 
this.color = 'blue'; 
this.x = x; 
this.y = y; 
this.direct = direct; 
this.bulletsList = []; 
this.maxBulletSize = 1; 

//定时器,自动移动 
this.timer1 = setInterval ((function (context) { 
return function () { 
//移动 
Enemy.prototype.move.call (context); 
} 
}) (this), 30); 
//定时器,射击 
this.timer2 = setInterval ((function (context) { 
return function () { 
//射击 
Tank.prototype.shot.call (context); 
} 
}) (this), 2000); 
//定时器,变换方向 
this.timer3 = setInterval ((function (context) { 
return function () { 
//射击 
Tank.prototype.changeDirect.call (context); 
} 
}) (this), 3000); 
} 
Enemy.prototype = new Tank (0, 0, 0); 
Enemy.prototype.constructor = Enemy; 
Enemy.prototype.move = function () { 
switch (this.direct) { 
case 0: 
this.moveUp (); 
break; 
case 1: 
this.moveRight (); 
break; 
case 2: 
this.moveDown (); 
break; 
case 3: 
this.moveLeft (); 
break; 
} 
}

Bullet.js
/** 
* Created by Alane on 14-3-11. 
*/ 
function Bullet (x, y, direct, color) { 
this.isdead = false; 
this.x = x; 
this.y = y; 
this.direct = direct; 
this.speed = 4; 
this.color = color; 
//定时器,自行运动 
this.timer = setInterval ((function (context) { 
return function () { 
Bullet.prototype.move.call (context) 
} 
}) (this), 30); 
} 
Bullet.prototype.move = 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; 
} //边界检测 
if (this.y < 0 || this.x > width || this.y > height || this.x < 0) { 
clearInterval (this.timer); 
this.isdead = true; 
} 
//碰撞检测 检测敌人坦克 
for(var i=0;i<allTank.length;i++){ 
var temp = allTank[i]; 
if(temp.isdead){ 
continue; 
} 
switch (temp.direct){ 
case 0: 
case 2:if(this.x>temp.x && this.x<temp.x+20 && this.y>temp.y&& this.y<temp.y+30){ 
if(this.color == temp.color){ 
break; 
} 
Bombs.push(new Bomb(temp.x-10,temp.y-10)); 
clearInterval (this.timer); 
this.isdead = true; 
temp.isdead = true; 
}break 
case 1: 
case 3:if(this.x>temp.x && this.x<temp.x+30 && this.y>temp.y&& this.y<temp.y+20){ 
if(this.color == temp.color){ 
break; 
} 
Bombs.push(new Bomb(temp.x-10,temp.y-10)); 
clearInterval (this.timer); 
this.isdead = true; 
temp.isdead = true; 
}break; 
} 
} 
}

源码下载
Javascript 相关文章推荐
强大的jquery插件jqeuryUI做网页对话框效果!简单
Apr 14 Javascript
javascript常见用法总结
May 22 Javascript
jQuery实现点击该行即可删除HTML表格行
Oct 17 Javascript
推荐25个超炫的jQuery网格插件
Nov 28 Javascript
浅谈javascript中的call、apply、bind
Mar 06 Javascript
ECHO.js 纯javascript轻量级延迟加载的实例代码
May 24 Javascript
js和C# 时间日期格式转换的简单实例
May 28 Javascript
javascript类型系统——undefined和null全面了解
Jul 13 Javascript
JS和canvas实现俄罗斯方块
Mar 14 Javascript
vue3.0 搭建项目总结(详细步骤)
May 20 Javascript
微信小程序实现滑动翻页效果(完整代码)
Dec 06 Javascript
javascript读取本地文件和目录方法详解
Aug 06 Javascript
js定时调用方法成功后并停止调用示例
Apr 08 #Javascript
jquery选择器使用详解
Apr 08 #Javascript
jquery淡化版banner异步图片文字效果切换图片特效
Apr 08 #Javascript
jQuery拖动div、移动div、弹出层实现原理及示例
Apr 08 #Javascript
javascript跨域的4种方法和原理详解
Apr 08 #Javascript
通过Javascript读取本地Excel文件内容的代码示例
Apr 08 #Javascript
javascript数组操作(创建、元素删除、数组的拷贝)
Apr 07 #Javascript
You might like
使用PHP和HTML5 FormData实现无刷新文件上传教程
2014/09/06 PHP
php+mysql结合Ajax实现点赞功能完整实例
2015/01/30 PHP
PHP中empty,isset,is_null用法和区别
2017/02/19 PHP
PHP7扩展开发之基于函数方式使用lib库的方法详解
2018/01/15 PHP
图片自动更新(说明)
2006/10/02 Javascript
Javascript创建Silverlight Plugin以及自定义nonSilverlight和lowSilverlight样式
2010/06/28 Javascript
artdialog的图片/标题以及关闭按钮不显示的解决方法
2013/06/27 Javascript
JavaScript中的数学运算介绍
2014/12/29 Javascript
jQuery中:selected选择器用法实例
2015/01/04 Javascript
JavaScript监听和禁用浏览器回车事件实例
2015/01/31 Javascript
Javascript监视变量变化的方法
2015/06/09 Javascript
如何使用AngularJs打造权限管理系统【简易型】
2016/05/09 Javascript
jQuery的ajax下载blob文件
2016/07/21 Javascript
jQuery Easyui Tabs扩展根据自定义属性打开页签
2016/08/15 Javascript
详解js的事件处理函数和动态创建html标记方法
2016/12/16 Javascript
js 去掉字符串前后空格实现代码集合
2017/03/25 Javascript
解决浏览器会自动填充密码的问题
2017/04/28 Javascript
Angularjs cookie 操作实例详解
2017/09/27 Javascript
用JavaScript做简易的购物车的代码示例
2017/10/20 Javascript
使用layer.msg 时间设置不起作用的解决方法
2019/09/12 Javascript
前端开发之便利店收银系统代码
2019/12/27 Javascript
vue中后端做Excel导出功能返回数据流前端的处理操作
2020/09/08 Javascript
vue 全局封装loading加载教程(全局监听)
2020/11/05 Javascript
JavaScript中常用的3种弹出提示框(alert、confirm、prompt)
2020/11/10 Javascript
python解析xml文件实例分析
2015/05/27 Python
python ddt实现数据驱动
2018/03/14 Python
python文件操作的简单方法总结
2019/11/07 Python
Java中实现多态的机制是什么?
2014/12/07 面试题
菜篮子工程实施方案
2014/03/08 职场文书
网络信息安全承诺书
2014/03/26 职场文书
供货协议书
2014/04/22 职场文书
经贸日语专业自荐信
2014/09/02 职场文书
医院党的群众路线教育实践活动学习心得体会
2014/10/30 职场文书
学生逃课检讨书
2015/02/17 职场文书
python必学知识之文件操作(建议收藏)
2021/05/30 Python
20180830晚上第一届KSL半决赛 雨神vs解冻(二龙 三炮解说)
2022/04/01 星际争霸