HTML5 Game Development for Intel AppUp® Center - Part 2

Categories:

This is part 2 of a series on developing a game using HTML5.  In our part 1 we looked at the Canvas Element and did the basics to create our ship with rotation and thrust to move it around our game space.   In this article we will take our game further by:

• Collision detection
• Missile Array
• Enemy Array

Collision Detection - Ship Collision with Game Edge

In part 1 of this tutorial our ship is able to move around the screen but it will fly out of our game space and unfortunately can easily be lost.  To mimmick the Omega Race game that is the inspiration of our project, we want the boundaries of our game and the inner edge of our track to bounce our ship, like a billard ball hitting the sides of pool table.

For this to work I figured that hitting or exceeding the vertical edges would cause my ship to reverse is horizontal movement, while hitting or exceeding past the horizontal edges would cause the ship to reverse its vertical movement.  In other words if my ship travelled straight down and hit the bottom edge of the game space its Y movement would then need to reverse. Similarly if I travelled and hit the left wall edge of the  game space my horizontal movement would need to reverse.

To do this I just need to check the my shipx and shipy position every time we animate the ship.   If the x position of the ship meets a condition of the ship having hit one of my vertical edges then the we want x_speed =x_speed*-1.  If it meets a condition of existing at or beyond on of my horizontal borders then it y_speed = y_speed*-1.  This will create the bounce effect.

The below code added to the end of my function "on enter frame" will check the x & y position of my ship.  Variables gameh is set as the game height of 500 pixels, variable gamew is the game width of 1000 pixels and radi is radius of my ship or 10 pixels.  Thus if (shipy>gameh-radi) means if shipy position is > 490

`     if(shipx>gamew-radi){        shipx=gamew-radi;        x_speed*=-1;        }      if(shipx<radi){        shipx=radi;        x_speed*=-1;       }      if(shipy>gameh-radi){        shipy=gameh-radi;        y_speed*=-1;         }      if(shipy<radi){        shipy=radi;        y_speed*=-1;        }  `
` if(shipx>=200 && shipy>200 && shipy<300 && shipx<=210){        x_speed*=-1;      }            if((shipx<=800 && shipy<300 && shipy>200 && shipx>790)){        x_speed*=-2;              }            if((shipy<=310 && shipx>200 && shipx<800 && shipy>300)){        y_speed*=-1;             }            if((shipy>=200 && shipx>200 && shipx<800 && shipy<210)){        y_speed*=-1;              }`

Missile Array

This next section is going to discuss arrays.  Arrays are super handy and I learned alot about creating, editing and appending items to an array on this site.  It's super valuable.  I suggest a thorough review.

One thing I like about old video games is the restriction of missile fires on the  screen at any one time.  Space Invaders & Centipede allow for one missile at a time, thus if you miss hitting an enemy  you have to wait for that missle to clear the screen before you can fire again.  So I want to do that in this game but I want to have some ability to rapid fire, so I set the number of missiles I can have on the screen to 3.  Then if you miss you target you have to wait unitil at least one of those missiles clears the screen before your ship will fire.  It makes the game more strategic, and percision of your shots matter.

So if I'm going to allow for 3 missiles to exist on the screen at any time I have to track 3 different missile coordinates at any one time, and then determine if these missiles, much like my ship, has hit the edge of the game track.  But unlike my ship if they hit the edge of the track they will disapper rather than change their direction.

To track animate 3 missiles along 3 different set of x & y coordinates, I need to create an array.  The array is like a small virtual spreadsheet that I will use to store the x & y position of my missile.  I can also store other attributes for each missile like a missile color, giving each missile shot a different color.  An array is very handy.  It allows me to store all the information about an object

Creating Missile Array

To create an array is very simple in JavaScript*.  The question is when to add it.  In the case of the missile a new missile is created every time I fire.  Thus every time I hit the S key I need to create an new array.  The following  is added to my event listener for the S key

`push.lasers(shipx, shipy, spin)`

This means each time i push my fire button (the S key) I will add a missile to my missile array with 3 bits of information. When an array is built assigns information to a variable with a number starting at 0. So after hitting the S key three times I will have variables stored at lasers(0), lasers(1) & lasers(2). For each of these I will have recorded the Ship X position, the Ship Y position and the Ship angle to those missile variables.  They will be stored at lasers(x)(0), lasers(x)(1) & lasers(x)(2).

Thus if I have no missles yet shot and my ship is at X coordinate 50, Y coordinate 120 with an angle of 45 when I hit S a missile called missile(0) is created where

`lasers[0] = 50,120,45`

Additionally each of those numbers within lasers(0) can be called as variables per the following:

`lasers[0][0]=50`
`lasers[0][1]=120`
`lasers[0][2]=45`

The above is key. We will want to draw missiles based on the above variables, and in order to animate the missiles we will want to apply some math to these so it appears the missiles are moving on the screen.  Finally we will want to call the variables to check where the missile is and then have it trigger an event should the missile hit an enemy or should it leave the game space.

In terms of creating missles, remember I only want to do this if there are less than 3 missiles already.  If there are 3 missiles the S key should not add a missile to the arrary.  This is the same is Centipede, you have to wait for the missle to leave the space or hit something before you can fire again. This is easy to code.  the arrayname.length variable or in this case  lasers.length, will return how many missiles are currently in the array.  Thus if lasers.length is < 3 I can execture push.lasers(shipx, shipy, spin).

Removing Missile From Array

And lastly, if I want to more than 3 missiles EVER, I have to remove a missle from the array when they either hit an enemy or when they leave the game space.  I use the same collision detection method for my missiles. The only difference is when those conditions are met I simply remove a missile from the array using this command

`splice.lasers(1,0)`

Code

The following code sets the variables for my missiles

var mcolor="red";
var missilespeed=20;
var missilecount=3;
var laserTotal = 2;
var lasers = [];

This code is the Canvas Element that draws the missile shape

function drawlaser(){
context.strokeStyle=mcolor;
context.beginPath();
context.moveTo(0, shipsize*.2);
context.lineTo(shipsize*-.1, 0);
context.lineTo(0, shipsize*-.2);
context.lineTo(shipsize*.1, 0);
context.lineTo(0, shipsize*.2);
context.stroke();
}

This code checks if I have more 3 or more missiles, if not then it adjust the last coordinates of the missile adding the missile speed and the trajectory of the missile, then will draw the missile shape

function moveLaserXY() {
if (lasers.length){
for (var i = 0; i < lasers.length; i++) {
context.save();
//  mcolor=mcolora[i];
lasers[i][0] = lasers[i][0] + missilespeed * Math.cos(lasers[i][2]);
lasers[i][1] = lasers[i][1] + missilespeed * Math.sin(lasers[i][2]);
context.translate(lasers[i][0], lasers[i][1]);
context.rotate(spin * Math.PI/180);
drawlaser(context);
context.restore();
}
}
}

This is the code that determines if the missile has hit an edge of the game space, if so it will remove a missle from the array

`  function killLaser() {   for (var i = 0; i < lasers.length; i++) {    if(lasers[i][0]>200 && lasers[i][1]>200 && lasers[i][1]<300 && lasers[i][0]<800){       lasers.splice(i, 1);     }    if(lasers[i][0]>gamew || lasers[i][0]<0 || lasers[i][1]>gameh ||lasers[i][1]<0){       lasers.splice(i, 1);     }       }    }    Here is the game so far to this point HTML5-Part2a `

Enemy Ships

Till this point we have a pretty friendly game, where you can fly around a space track and shoot missiles.  But it's much more fun to have some enemies.  This is probably the most complicated part of the game.  I need to move the enemies independently and with some randomness so the game isn't super predictable.

We'll start by creating a set of 6 enemies randomly placed at the bottom of the screen.  Just like the missles we need each to have an X&Y position that we move, so we will need to create an array for our enemies, and then we will have to determine if one of our missiles hits an enemy so we can remove the missile and remove the enemy.

Code

Variables for enemies

`  var enemycount = 6;     // how many enemies I wish to start with   var enemies =[];          // Empty array that I will use to store enemy info  var enemyrotatedeg=0; // rotation of enemy, initially set to 0  var enemyx=200;            // this is where I want to start creating enemies   var enemyy=320;        // same as above  var enemyspeed=2;    // how fast the enemies move.  This will get faster with every other level`

First piece of code I want to add to is to create my enemies.  This does not need to happen with an event and I don't want to repeat this each frame so I'm calling this function out of the gate.

`createenemies();`

This is the code to create the enemy.  It starts with a "for" loop based on the enemycount I set, thus it will run thru this 6 times.  Next you'll see a random generation for y and x.  Y position will be the initial position (320) from my variables plus a random number from 0-180.  The X is similar but from 5 to 600.  The rest of the numbers add some random numbers and those numbers determine when the ship will turn as it comes into a corners space.

`  function createenemies(){    for (var i=0; i<enemycount; i++){      rndy = (Math.round(Math.random() * 180));      rndx = (Math.round(Math.random() * 600));   enemies.push([rndx+enemyx,enemyy+rndy,(Math.round(Math.random() * 8)),(Math.round(Math.random() * 2000)),-1,0,(Math.round(Math.random() * 190))]);    }  }`
` `

This code draws the enemy. The enemy is a combo of circle and rotated square shapes.

`  function drawenemy(){    context.save();    context.strokeStyle="green";    context.translate(0,0);    for (var b=0; b<2; b++){      context.translate (0,0);      context.rotate(150);      context.strokeRect(-13,-13,26,26);    }    context.restore();   }  `

Here is the complex part of the code which moves the ships around the track. The if statements see if the random numbers is hit as the enemy moves into the corner area of a track, and if so will have it change is movement to move along the track

`  function rotateenemy (){     for (var i=0; i<enemycount; i++){       context.save();      if (enemies[i][0]<=200 && enemies[i][1]>=320 &&enemies[i][0]<=enemies[i][6]){        enemies[i][4]=0;        enemies[i][5]=-1;      }            if (enemies[i][1]<=200 && enemies[i][0]<=200 &&enemies[i][1]<=enemies[i][6]){        enemies[i][4]=1;        enemies[i][5]=0;       }            if (enemies[i][1]<=200 && enemies[i][0]>=800 && enemies[i][0]>=1000-enemies[i][6]){        enemies[i][4]=0;        enemies[i][5]=1;      }            if (enemies[i][1]>=320 && enemies[i][0]>=800 && enemies[i][1]>=320+enemies[i][6]*.8){        enemies[i][4]=-1;        enemies[i][5]=0;      }            enemies[i][0]=enemies[i][0]+enemies[i][4]*enemyspeed;      enemies[i][1]=enemies[i][1]+enemies[i][5]*enemyspeed;`

This final code will rotate the inner squares of the enemy

`      context.strokeRect(-5,-5,10,10);      context.beginPath();      context.arc(0, 0, 17, 0, Math.PI*2, true);       context.closePath();      context.stroke();      context.rotate(enemyrotatedeg * Math.PI/180);      context.lineWidth=1;      drawenemy();            context.restore();     }  }  `

Shooting Enemies

Now we want to put things together and allow our missiles to destroy enemies.  This is basically the same process we used for determining if the missiles hit the edges.  In addition to the collision detection for missiles and enemies I am adding a Blast effect that will animate at the spot the enemy and missile collide.  Since there can be more than one blast on the screen at a time, I again need to create an array for the Blast effect

Code

Variables

`  var blast =[];     // this is the array of blast effects  var bplus=6;      //used to set the varied starburst effect of the ship and enemy blast  var rnd = (Math.round(Math.random() * 50));`

I wanted a starbust effect but to look a bit chaotic and random as an explosion is. The Blast animation starts with a for loop to go thru my blast array.  It then creates a set of 12 lines that radiate from the center of the blast.  I played with the formula until I got the effect I wanted.

`  function drawBlast() {    for (var i=0; i<blast.length; i++) {      for (var k=0; k<11; k++ ){        bplus=bplus*-1;        context.strokeStyle="white";        context.beginPath();        context.moveTo (blast[i][0] + 10 * Math.cos(k*20),blast[i][1]+10 * Math.sin(k*20));        context.lineTo (blast[i][0] + (25+bplus) * Math.cos(k*20),blast[i][1]+(25+bplus) * Math.sin(k*20));        context.closePath();        context.stroke();      }      if (blast[i][2]<2) {        blast[i][2]=0;      }      else {        blast[i][2]--;      }      if (blast[i][2]==0) {        blast.splice(i, 1);      }     }  }  `

Here's the code for what we've done to date.  HTML5-Part2b

Next we'll look at score, creating game levels, and a game menu.

<< Back to Part 1

For more complete information about compiler optimizations, see our Optimization Notice.