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

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

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.最终效果

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;
}
}

}

源码下载

(0)

相关推荐

  • 原生JavaScript实现连连看游戏(附源码)

    向大家推荐一款原生JavaScript版连连看游戏,源码下载,首页如下图所示:  首先看一下html的布局方式在index.html文件中: 复制代码 代码如下: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html> <head>

  • javascript 制作坦克大战游戏初步 图片与代码

    学了一阵子的javascript,该做点东西,虽然东西还是东拼西凑,见笑.方向键控制坦克移动,回车键发射炸弹.其他的功能敌方坦克那些还没写. javascript坦克游戏初步|阿会楠练习作品 body{ background:black; } #tanke{ position:absolute; left:500px; top:200px; } var i = 0; var bombLeftArray = new Array(100);//存放炸弹信息x var bombTopArray = n

  • node.js适合游戏后台开发吗?

    网站服务器和游戏服务器是怎么样联系到一起的? 1. 游戏分很多种,咱们先来看看MMORPG. 再怎么简单的RPG服务器都免不了处理多人交互的情形,上百人在同一个场景里面,每个客户端都需要收到其他所有人的操作信息. 其次,用户的操作是非常频繁的,一般的服务器倾向于持有长连接.而且这些链接的是频繁交互的,没有明显的持久的分区策略,所以限制了服务器的横向扩展,同一个场景往往只能放在一个物理机上面运行. 再次,端游通常是不敢把逻辑运算放客户端的,用户分分钟给你破解掉,改改金币,刷两件装备再常见不过了.所

  • JS写的贪吃蛇游戏(个人练习)

    JS贪吃蛇游戏,个人练习之用,放在这备份一下,   复制代码 代码如下: <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>JS贪吃蛇-练习</t

  • JavaScript仿微信打飞机游戏

    首先实现微信打飞机游戏,首先会有自己和敌机,采用canvas绘图来生成自己和敌人. 1.生成自己,且可以通过左右键来进行左右移动. //生成自己,且可以左右移动 //控制飞机向右移动的函数 function moveRight(event){ context.clearRect(aligh,100,47,47); //防止飞机移除背景外 if(aligh < 260){ var img = new Image(); img.src = "../images/self.png";

  • JS 拼图游戏 面向对象,注释完整。

    在线演示 http://img.jb51.net/online/pintu/pintu.htm 复制代码 代码如下: <html> <head> <title>JS拼图游戏</title> <style>     body{         font-size:9pt;     } table{ border-collapse: collapse; } input{     width:20px; } </style> </he

  • js猜数字小游戏的简单实现代码

    复制代码 代码如下: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="

  • JavaScript 打地鼠游戏代码说明

    演示地址:http://demo.jb51.net/js/mouse/index.html打包下载地址 http://www.jb51.net/jiaoben/32434.html这个是我无聊的时候写的,先看看效果(UI做得比较丑):  说明:红色的点击得分100,蓝色的点击扣分100. 只是想用js来写个小游戏,顺便练练js的代码. 先看html部分: html 复制代码 代码如下: <style> #panel{height:300px;width:300px;background:#cc

  • js实现大转盘抽奖游戏实例

    本文实例讲述了js实现大转盘抽奖游戏.分享给大家供大家参考.具体实现方法如下: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <hea

  • 纯JS实现五子棋游戏兼容各浏览器(附源码)

    纯JS五子棋(各浏览器兼容) 效果图:  代码下载 HTML代码 复制代码 代码如下: <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html;"> <title>五子棋</title> <link rel="stylesheet" type="text/

随机推荐