First, summarize the key points and problems encountered
Inheritance in 1.javascript, the best parent class provides only method sharing, attributes are written to their subclasses, and the constructors of the parent class and subclass are not promiscuous.
2.prototype simulate inherited code that should be written before all method definitions, otherwise the prototype object is changed and the method becomes undefined, such as:
Copy Code code 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.canvas drawing Graphics, in addition to drawing a rectangle, the other must add Ctx.beginpath (), Ctx.closepath (), otherwise there will be unexpected errors.
The 4.concat function can merge an array, or the element returns a new array
5.Image the SRC attribute will load the picture, but if the picture is not finished loading, it will cause invalidation, so use the onload event handling
6. Extend Array function, delete specified element
Copy Code code as follows:
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);
}
}
}
}
7. Timer settings, setinterval ("Fun", 1000) method of the first parameter, can be a string, such as "Hero.say ()", similar to the eval will execute the code, so it can give the function with parameters, and also specify the function of the running context. But if you pass in a handle to a function, you cannot take arguments, and you cannot specify a context, except for the first solution, I used a closure to solve the problem.
Copy Code code as follows:
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 to execute manually.
8. The functional design of the method, in addition to the function, should include the implementation of this function of the condition detection, such as move, it should include what circumstances can be moved, move to where it can not be moved. This detection should not be placed externally.
9. Write code should not think about the design or optimization of the problem, first realize the function, then talk about optimization, or design before implementation. Be clear, don't be confused, focus on a little.
There is no sleep in the 10.javascript function, you can create a variable as a buffer to achieve the purpose of interval execution
Second, code implementation
1. This procedure 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 code as follows:
<! DOCTYPE html>
<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 () {
Canvas information
width = document.getElementById (' Map '). Width;
Height = document.getElementById (' Map '). Height;
CTX = document.getElementById (' Map '). GetContext (' 2d ');
Initial page
var starimg = new Image ();
STARIMG.SRC = "Img/star.jpg";
Starimg.onload = function () {
Ctx.drawimage (starimg, 0, 0, width, height);
}
Keyboard Monitor Enter start game
Document.body.onkeydown = function () {
var keycode = Event.keycode;
Switch (keycode) {
Case 13:
Initialization parameters
Init ()
Refresh 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 (+ I * 50, 0, 2));
}
Merging arrays
Alltank = Enemys.concat (Hero);
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;//Left
Case 83:
Hero.movedown ();
break;//under
Case 87:
Hero.moveup ();
On break;//
Case 68:
Hero.moveright ();
break;//Right
Case 74:
Hero.shot ();
Break
Case 49:
Hero.addlife ()
Break
}
}
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>
<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 1 keys to increase life, the default is 1</p>
<p> remaining number: <label id= "Life" >1</label></p>
<div id= "Data" >
</div>
</div>
</body>
2.draw.js
Copy Code code as follows:
/**
* Created by Alane on 14-3-18.
*/
function Draw () {
Test bullets and Tank life
Checkdead ();
Empty canvas
Ctx.clearrect (0,0,500,400);
Draw a 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 Bullets
var temp = hero.bulletslist;
for (var i = 0; i < temp.length; i++) {
Drawbullet (Temp[i]);
}
Draw bombs
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 () {
Detect enemy bullets and die
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);
}
}
}
Test player Bullet Life
var temp = hero.bulletslist;
for (var i = 0; i < temp.length; i++) {
var o = temp[i];
if (o.isdead) {
Temp.deleteelement (o);
}
}
Test 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
Copy Code code 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 code as follows:
/**
* Created by Alane on 14-3-7.
*/
/**
* on Direct 0
* 1 Right
* 2 Down
* 3 Left
* @param x
* @param y
* @param Direct
* @constructor
*/
//******************************************************************************************/
Tank Parent Class
function Tank (x, y, direct) {
This.speed = 2;
}
Tank.prototype.moveUp = function () {
Boundary detection
if (This.y < 0) {
Change 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 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) {
New Bullets
var bullet = null;
Switch (this.direct) {
Case 0:
Bullet = new Bullet (this.x +, this.y-2, 0, This.color);
Break
Case 1:
Bullet = new Bullet (this.x +, This.y + 1, this.color);
Break
Case 2:
Bullet = new Bullet (this.x +, This.y + 2, this.color);
Break
Case 3:
Bullet = new Bullet (this.x-2, This.y + 3, this.color);
Break
}
Put the cartridge in.
This.bulletsList.push (bullet);
}
}
//******************************************************************************************/
Players
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;
}
//******************************************************************************************/
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, automatic movement
This.timer1 = SetInterval ((function (context) {
return function () {
Move
Enemy.prototype.move.call (context);
}
}) (this), 30;
Timer, shooting
This.timer2 = SetInterval ((function (context) {
return function () {
Shooting
Tank.prototype.shot.call (context);
}
}) (this), 2000;
Timer, change 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
Copy Code code as follows:
/**
* 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;
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;
}
}
}
SOURCE download