Home  >  Article  >  Web Front-end  >  javascript simulated tank battle game (html5 version) with source code download_javascript skills

javascript simulated tank battle game (html5 version) with source code download_javascript skills

WBOY
WBOYOriginal
2016-05-16 16:52:561500browse

1. Summarize the key points and problems encountered

1. For inheritance in JavaScript, it is best for the parent class to only provide method sharing, and the attributes are written to the respective subclasses to avoid mixing the constructors of the parent class and the subclass. .

2. The code for prototype simulation inheritance should be written before all method definitions, otherwise the prototype object is changed and the method becomes undefined, such as:

Copy code The code is as follows:

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

3. When drawing graphics on canvas, in addition to drawing rectangles, ctx.beginPath(); and ctx.closePath(); must be added to everything else, otherwise unexpected errors will occur.

4. The concat function can merge arrays, or return elements to a new array

5. After the src attribute of Image is assigned, the image will be loaded, but if the loading is not completed, the image will be drawn. It will cause failure, so use onload event processing

6. Extend the Array function and delete the specified element
Copy code The code is as follows:

//Extended to delete the specified element
Array.prototype.deleteElement = function (obj) {
if (obj) {
for (var i = 0; i < this.length; i ) {
if (this[i] === obj) {
this.splice (i, 1);
}
}
}
}

7. Timer setting, the first parameter of the setInterval("fun",1000) method can be a string, such as "hero.say()", similar to eval to execute this string of code, so it can bring parameters to the function and also specify the running context of this function. But if the function is passed in as a handle, it cannot take parameters, and the context cannot be specified. In addition to the first way, I used closures to solve this problem
Copy code The code is as follows:

//Timer, moves on its own
this.timer = setInterval ((function (context) {
return function () {
Bullet.prototype.move.call (context)
}
}) (this), 30);

I saved the current execution environment, And call the call method to execute it manually.

8. In addition to the function, the functional design of the method should include the condition detection for executing this function. For example, move should include the circumstances under which it can be moved and where it cannot be moved. This test should not be placed externally.

9. When writing code, you should not think about design or optimization issues. Implement the function first and then talk about optimization, or design first and then implement it. The thinking should be clear, not confusing, and focus on one point.

10. There is no sleep function in JavaScript. You can create a variable as a buffer to achieve the purpose of interval execution

2. Code implementation

1. This program is divided into Bomb.js,Bullet.js,Draw.js,Tank.js,index.html,img,music,

2. Final effect





3. Code

1.index.html

Copy code The code is as follows:






















按下回车键开始游戏



按下1键增加生命,默认是1



剩余生命数 :










2.Draw.js
复制代码 代码如下:

/**
* Created by Alane on 14-3-18.
*/

function draw(){
//Check the life and death of bullets and tanks
checkDead();
//Clear the canvas
ctx.clearRect(0,0,500,400);
//Draw the player
if(!hero.isdead){
drawTank(hero);
}else{
hero.cutLife( );
}
//Draw enemy tank
for (var i = 0; i < enemies.length; i ) {
drawTank(enemys[i]);
}
//Draw enemy bullets
for(var j=0;jvar temp = enemies[j].bulletsList;
for (var i = 0; i < temp.length; i ) {
drawBullet(temp[i]);
}
}
//Draw player bullets
var temp = hero.bulletsList;
for (var i = 0; i < temp.length; i ) {
drawBullet(temp[i]);
}

//Draw a bomb
for(var i=0 ;idrawBown(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(){
//Detect the life and death of enemy bullets
for(var j=0;jvar temp = enemies[j].bulletsList;
for (var i = 0; i < temp.length; i ) {
var o = temp[i];
if(o.isdead ){
temp.deleteElement(o);
}
}
}
//Detect the life and death of player bullets
var temp = hero.bulletsList;
for (var i = 0; i < temp.length; i ) {
var o = temp[i];
if(o.isdead){
temp.deleteElement(o);
}
}

//Detect the life and death of enemy tanks
for (var i = 0; i < enemies.length; i ) {
var o = enemies[i];
if( o.isdead){
enemys.deleteElement(o);
}
}
}

Bomb.js
Copy code The code is as follows:

/**
* 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
Copy code The code is as follows:

/**
* Created by Alane on 14-3-7.
*/
/**
* direct 0 up
* 1 right
* 2 down
* 3 left
* @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;ivar temp = allTank[i];
if(temp.isdead){
continue;
}
switch (temp.direct){
case 0:
case 2:if(this.x>temp.x && this.xtemp.y&& this.yif(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.xtemp.y&& this.yif(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;
}
}

}

源码下载
Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn