A simple HTML5 Game tutorial – Part 3

Following on from Part 2 we have put in place the foundation of our game and have some ‘bad guys’ moving in a menacing manner.  We are close to having a game: if we could just shot the ‘bad guys’.  Reminding ourselves of the goals set out in Part 1 we need to achieve the following:

Goals

  1. Create the ‘bad guys’.
  2. Ensure the ‘bad guys’ move in a random pattern; but, stay within the bounds of the screen.
  3. Allow a player to shoot the ‘bad guys’ by moving a target controlled by the mouse.
  4. Keep a tally of how accurate the player is e.g. shots / hits ratio.

Points 1 and 2 are covered in Part 1 and Part 2, in this post we tackle point 3.

In you want to have a peek at the result of following this post click here.

Let’s Shoot

Target for shooting bad guys in game

We need a graphic for our target.  I used the image to the left.  This image needs loading as an asset and then positioning so its centre follows the mouse pointer.  The other requirement is that the target is drawn over the top of any ‘bad guys’.

To load the target graphic as an asset we have to modify the loadSprite function as follows:


function loadSprite()
{
sprite = new Image();
sprite.src = 'sprite.png';

target = new Image();
target.src = 'target.gif';
}

We also need to bind the event related to the mouse movement to a function. The function we bind the event to will be responsible for tracking the mouse movement.  The function and the bind action can be achieve by adding the following code:


var targetX = 0,
  targetY = 0;

function moveTarget(<span class="hiddenGrammarError" pre="">e) {

  e</span> = e || window.event;
  targetX = e.pageX;
  targetY = e.pageY;

}

canvas.onmousemove = moveTarget;

The above code only tracks the mouse movement.  It stores the x and y screen coordinates in the targetX and targetY variables. We need to draw the target using these variables . To do this we simply modify the start function as follows:

   function start() {

	    clearCanvas();

	    for(i = 0; i < sprites.length; i++) {
		sprites[i].draw(ctx, sprite).move();
		sprites[i].checkBoundaryCollision();
		sprites[i].correctXY();
	    }

	    //Draw target
	    ctx.drawImage(target, 0,0, 512, 512,
		targetX - 50, targetY - 50,
		100, 100);

	    requestAnimFrame(start);
   }

With this little change we are almost there. Take a look at our progress here.

The target is moving around and you can chase the ‘bad guys’! But, it’s sure frustrating you cannot shot them. So, our next step is to add the ability to shoot.  Shooting the ‘bad guys’ is as simple as detecting when the user clicks.  Again, we use the bind feature available in JavaScript.  This time we need to bind the ‘onclick’ function of the canvas as follows:

canvas.onclick = fire;

And the ‘fire’ function:

 function fire() {
 explosions.push(new Explosion(targetX, targetY, new Audio('bang.wav')));
 }

This function uses an array to store each event. We hold each event in a queue so we can draw the animation for each. Without the array we’d only be able to draw one shot at a time: it gives us some persistence. The array acts as a FIFO queue (FIFO stands for First In Fist Out). This means we can add the events to the array and delegate the drawing of the event to the main game loop – in essence we form a separation of concerns.

The fire function create a new ‘Explosion’ object every time it is called. This object is then added to the global explosions array. Before we move on to the code to draw the explosion, let’s look at the Explosion object. Like the Thing object each Explosion uses Cartesian coordinates for its position.  The Explosion object also includes an audio sample which is played when the object is created. These are passed into the constructor as follows:

 function Explosion(x, y, audio) {

 this.x = x;
 this.y = y;
 this.drawing = true;
 this.explosionFrame = 15;
 this.width = 200;
 this.height = 200;

 audio.play();

 };

In additional to the position and sound there are a couple of interesting variables. These are the variables labelled ‘drawing’ and ‘explosionFrame’. Both of these variables represent state. The state allows us to draw each frame of an explosion. Before we can do this we need a sprite:

explosion sprite

As before we need to load this sprite within the ‘loadSprite’ function:

	function loadSprite() {

	    sprite = new Image();
	    sprite.src = 'sprite.png';

	    target = new Image();
	    target.src = 'target.gif';

	    explosion = new Image();
	    explosion.src = 'explosion.png';

	}

The Explosion object controls its own state. The state changes every time the object’s ‘draw’ method is called. The ‘draw’ method contains the following code:

	Explosion.prototype.draw = function(ctx, explosion) {

	    if(this.drawing === false) {
		return this;
	    }

	    try {

		if(this.explosionFrame-- <= 0) {
		    this.drawing = false;
		}

		//Draw explosion
		ctx.drawImage(explosion, ((this.explosionFrame % 10) -1) * 65, 0,
		    65, 65,
		    this.x - 100, this.y - 90,
		    this.width, this.height);

	    }
	    catch(e) {

	    }
	    return this;

	};

The logic applied in this method is controlled by the value held in the exlosionFrame variable. Each time the method is called the variable is decremented by one. When the value is above zero a frame of the sprite is drawn. The frame chosen from the sprite is also based on the frame variable; thus, we move from frame to frame which draws an explosion effect in the x and y position of the canvas.

Drawing the animation is one requirement of shooting a ‘bad guy’. The other is to determine whether a shot hit anything. This hit logic is also handled within the explosion object:

Explosion.prototype.checkHits = function(things) {

    if(this.drawing === false) {
	return 0;
    }

    var centreX = (this.x - 100)  + (this.width / 2),
	centreY = (this.y - 90) + (this.height / 2);

    for(i = 0; i < things.length; i++) {
        if(centreX > things[i].getX() &&
	    centreX < things[i].getX() + things[i].getWidth() &&
 	    centreY > things[i].getY() &&
	    centreY < things[i].getY() + things[i].getHeight() &&
	    things[i].getHit() === false) {

	    things[i].setHit();

	}
     }
};

The method takes an array as its only parameter. This array is the array that holds the Thing objects. We simply loop around each Thing (‘bad guy’) and check whether its coordinates are within the bounds of the explosion. If a hit is detected the things’ ‘setHit’ method is called.

Putting this together requires adding the draw explosion logic and hit detection to the main start method which results in the following:

	function start() {

	    clearCanvas();

	    for(i = 0; i < sprites.length; i++) {
		sprites[i].draw(ctx, sprite).move();
		sprites[i].checkBoundaryCollision();
		sprites[i].correctXY();
	    }

	    for(i =0; i < explosions.length; i++) {
		explosions[i].draw(ctx, explosion);
		explosions[i].checkHits(sprites);
	    }

	    //Draw target
	    ctx.drawImage(target, 0,0, 512, 512,
		targetX - 50, targetY - 50,
		100, 100);

	    requestAnimFrame(start);

	}

The end product of the above is here.  Next, we’ll add a scoreboard, so please keep tuned-in.  Any feedback is welcome, especially suggestions to improve the above.  Thanks for reading.

Advertisements

One thought on “A simple HTML5 Game tutorial – Part 3

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s