Javascript simulation of the tank of html5 version of the game with the source download

  • 2020-03-30 02:33:06
  • OfStack

1. Summarize key points and problems encountered

1. Inheritance in javascript, it is better to share the methods with the parent class, and write the properties to the subclass to avoid mixing the constructor of the parent class and the subclass.

2. Prototype simulates inherited code, which should be written before all method definitions, otherwise the prototype object will be changed and the method will become undefined, such as:
 
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 a picture on canvas, ctx.beginpath () should be added to everything except the rectangle. And CTX. ClosePath (); Otherwise, unexpected errors may occur.

Concat functions can merge arrays, or elements can return a new array

5. The Image will be loaded after the value of the SRC attribute of the Image is assigned. However, if the Image is not loaded completely, it will be invalid

6. Extends the Array function to delete specified elements
 
//The extension deletes 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); 
} 
} 
} 
} 

The timer setting, the first argument to the setInterval (" fun ", 1000) method, can be a string, such as "hero.say()". Similar to eval, it executes this string of code, so it can take arguments to the function and specify the context in which the function will be run. But if I pass in a handle to a function, I can't take an argument, and I can't specify a context, so instead of the first solution, I use closures to solve this problem
 
//Timer, self-motion
this.timer = setInterval ((function (context) { 
return function () { 
Bullet.prototype.move.call (context) 
} 
}) (this), 30); 

I saved the current execution environment and called the call method for manual execution.

8. The functional design of the method, in addition to the function, should include the implementation of the function of the condition detection, such as move, should include what can be moved, moved to where can not be moved. This detection should not be placed externally.

9. When writing code, you should not think about design or optimization. You should implement the function first, then talk about optimization, or design first and then implement. Be clear, don't get confused, 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

Two, code implementation

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

2. End result

< img Alt = "" border = 0 SRC =" / / files.jb51.net/file_images/article/201404/2014040815493242.jpg ">

< img Alt = "" border = 0 SRC =" / / files.jb51.net/file_images/article/201404/2014040815493343.jpg ">

< img Alt = "" border = 0 SRC =" / / files.jb51.net/file_images/article/201404/2014040815493344.jpg ">  

3. Code

1. The 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 () { 
//The canvas information
width = document.getElementById ('Map').width; 
height = document.getElementById ('Map').height; 
ctx = document.getElementById ('Map').getContext ('2d'); 
//The initial page
var starImg = new Image (); 
starImg.src = "img/star.jpg"; 
starImg.onload = function () { 
ctx.drawImage (starImg, 0, 0, width, height); 
} 

//Keyboard monitor return to start the game
document.body.onkeydown = function () { 
var keycode = event.keyCode; 
switch (keycode) { 
case 13: 
//Initialization parameter
init () 
//Refresh the page
setInterval (draw, 30); 
document.body.onkeydown = gameControl; 
break; 
} 
} 
} 

function init () { 
//Players and computers
hero = new Hero (100, 300, 0); 
enemys = []; 
for (var i = 0; i < 3; i++) { 
enemys.push (new Enemy (100 + i * 50, 0, 2)); 
} 
//Merge array
allTank = enemys.concat (hero); 

// The bomb  
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;// On the left  
case 83: 
hero.moveDown (); 
break;// Under the  
case 87: 
hero.moveUp (); 
break;// on  
case 68: 
hero.moveRight (); 
break;// right  
case 74: 
hero.shot (); 
break; 
case 49: 
hero.addLife () 
break; 
} 
} 

//The extension deletes 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); 
} 
} 
} 
} 

</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> Press enter to start the game </p> 

<p> Press the 1 Bond adds life , The default is 1</p> 

<p> Remaining life  :<label id="life">1</label></p> 

<div id="data"> 

</div> 
</div> 
</body> 
</html> 

2. The Draw. Js
 
 

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

//Draw a bomb
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(){ 
//Check enemy bullets for life and death
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); 
} 
} 
} 
//Check player's bullet for life or death
var temp = hero.bulletsList; 
for (var i = 0; i < temp.length; i++) { 
var o = temp[i]; 
if(o.isdead){ 
temp.deleteElement(o); 
} 
} 

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

Bomb. Js
 
 
function Bomb(x,y){ 
this.life = 12; 
this.x = x; 
this.y = y; 
} 
Bomb.prototype.lifeDown = function(){ 
this.life--; 
} 

Tank. Js
 
 
 
/ 
//Tanks to the parent class
function Tank (x, y, direct) { 
this.speed = 2; 

} 
Tank.prototype.moveUp = function () { 
//Boundary detection
if (this.y < 0) { 
//In the direction
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; 

} 

// change In the direction
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) 
} 

//Shooting bullets
Tank.prototype.shot = function () { 
if(this.isdead){ 
return; 
} 
if (this.bulletsList.length < this.maxBulletSize) { 
//The new bullet
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; 
} 
//Into the cartridge
this.bulletsList.push (bullet); 
} 
} 
/ 
// The player  
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; 
} 


/ 
//The enemy tanks
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; 


//Timer, move automatically
this.timer1 = setInterval ((function (context) { 
return function () { 
// mobile  
Enemy.prototype.move.call (context); 
} 
}) (this), 30); 

//Timer, shooting
this.timer2 = setInterval ((function (context) { 
return function () { 
// shooting  
Tank.prototype.shot.call (context); 
} 
}) (this), 2000); 

// The timer , change In the direction
this.timer3 = setInterval ((function (context) { 
return function () { 
// shooting  
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
 
 
function Bullet (x, y, direct, color) { 
this.isdead = false; 
this.x = x; 
this.y = y; 
this.direct = direct; 
this.speed = 4; 
this.color = color; 
//Timer, self-motion
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; 
} 

//Boundary detection
if (this.y < 0 || this.x > width || this.y > height || this.x < 0) { 
clearInterval (this.timer); 
this.isdead = true; 
} 

//Collision detection detects enemy tanks
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; 
} 
} 

} 

Download the source code


Related articles: