A simple HTML5 Game tutorial – Part 2

Following on from Part 1 we have put in place the foundation of our game.  But, we can’t really call it a game as we have no interaction. Reminder ourselves of the goal set out in Part 1 we need to achieve the following:

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

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.

Point 1 is covered in Part 1, in this post we tackle point 2.  To make the ‘bad guys’ move we need to alter the ‘move’ method of the Thing object.  To do this we need to make use of the direction and speed properties we added to the Thing object during Part 1.  As each of the objects within the ‘bad guys’ array is its own instance we need each to act independently.  Therefore, we can add a ‘move’ method to the Thing object as follows:

	Thing.prototype.move = function() {

	    var delta = 0.2;

	    this.x += Math.cos(this.toRad(this.direction)) * delta * this.speed;
	    this.y -= Math.sin(this.toRad(this.direction)) * delta * this.speed;
	};

	Thing.prototype.toRad = function(v) {
	    return v * Math.PI / 180;
	};

Our objects are using x (this.x) and y (this.y) as coordinates. These are Cartesian coordinates. Cartesian coordinates have the advantage of being simple – in a mathematical term – to calculate the new position given a speed. The sin and cos math functions take one parameter; an angle expressed in radians which imply from the direction (this.direction). We can multiply the result of two math function calls by the speed which results in the new x and y coordinates.  Calculating this gives the objects new position. Next we need to repeat the draw and move logic. This achieves the animation of the ‘bad guys’ and provides, as all games need, a game loop.


	window.requestAnimFrame = (function() {
	    return window.requestAnimationFrame ||
		    window.webkitRequestAnimationFrame ||
		    window.mozRequestAnimationFrame ||
		    window.oRequestAnimationFrame ||
		    window.msRequestAnimationFrame ||
		    function(callback) {
			window.setTimeout(callback, 1000 / 60);
		    };
	})();

	function start() {

	    clearCanvas();

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

	    requestAnimFrame(start);

	}

The above code implements the main game loop.  The request animation frame function above is better explained by its creator – the Guru Paul Irish,  The second function labelled ‘start’ forms our main loop.  It first clears the canvas and then redraws each object within the sprite map.  It then uses the chaining pattern to call the move method on each object.  The loop is then repeated by means of the request animation form call.

Sphere shaped bad guys with line showing exit path from screen
Sprites with no boundaries

We now have animation; however, there is a major bug in our implementation.  Our ‘bad bug’ simply move off the edge of the screen into infinity and beyond.

The image adjacent shows this is action.  After a number of iterations of the main game loop each ‘bad guy’ will simply move past the edge of the screen.

To prevent the ‘bad guys’ escaping we need to set some boundaries.  When any ‘bad guy’ hits any of the edges it should simply bounce off in the opposite direction.  This logic needs adding to the ‘move’ method. We do this be adding a new method to the Thing object’s prototype:

Thing.prototype.checkBoundaryCollision = function() {

    if (this.x + this.width > this.canvas.width ||
	this.x < 0) {
	this.direction = 2 * 0 - this.direction - 180;
    } else if(this.y < 0 || this.y + this.height > this.canvas.height) {
	this.direction = 2 * 90 - this.direction - 180;
    }
};

We then call the method within the draw function:

Thing.prototype.checkBoundaryCollision = function() {

    if (this.x + this.width > this.canvas.width ||
	this.x < 0) {
	this.direction = 2 * 0 - this.direction - 180;
    } else if(this.y < 0 || this.y + this.height > this.canvas.height) {
	this.direction = 2 * 90 - this.direction - 180;
    }
};

This almost perfectly animates our ‘bad guys’, however, if the starting position of  the Thing overlaps the edge and the speed is not sufficient enough so that the object is moved back within the boundary the object get stuck on the edge!  Known in the software development business as a bug. To fix this bug we can add a simple correction function:

	Thing.prototype.correctXY = function() {

	    if(this.x + this.width >= this.canvas.width) {
		this.x = this.canvas.width - this.width;
	    } else if(this.x < 0) {
		this.x = 0;
	    } else if(this.y < 0) {
		this.y = 0;
	    } else if(this.y + this.height >= this.canvas.height) {
		this.y = this.canvas.height - this.height;
	    }
	};

We now have animated ‘bad guys’ which bounce around the screen. This is a little closer to resembling a game. Take a look here to see our progress. We are close to delivering goal two of our objectives. But, we are missing the random movement requirement. To do this we need to manipulate the direction and randomly modify both the speed and direction at random intervals. To make this happen, we first need to a some new properties to the Thing object:

	function Thing(mapX, mapY, x, y, canvas) {
	    this.x = x;
	    this.y = y;
	    this.mapX = mapX;
	    this.mapY = mapY;
	    this.height = 50;
	    this.width = 50;
	    this.direction = Math.floor((Math.random()*359));
	    this.speed = Math.floor((Math.random()*50) + 5);
	    this.canvas = canvas;
	    this.erratic = (Math.floor((Math.random()* 4) + 1) === 1);
	    this.gravitationalPull = 0;
	    this.tick = 0;
	    this.changeAt = Math.floor((Math.random()*50) + 1);
       };

Making use of the new properties we can add the following code to the move function:

	Thing.prototype.move = function() {

	    var delta = 0.2;

	    this.x += Math.cos(this.toRad(this.direction)) * delta * this.speed;
	    this.y -= Math.sin(this.toRad(this.direction)) * delta * this.speed;

	    this.direction+= this.gravitationalPull;

	    if(this.direction < 0) {
		this.direction += 360;
	    } else if(this.direction > 360) {
		this.direction -= 360;
	    }

	    this.tick++;

	    if(this.tick > this.changeAt) {
		this.tick = 0;
		this.gravitationalPull = Math.floor((Math.random()*6));

		if(this.erratic) {
		    this.direction = Math.floor((Math.random()*359));
		    this.speed = Math.floor((Math.random()*50) + 5);
		}
	    }
	};

Putting all the above together achieves our second objective which can be viewed here.  In part three we will add the ability to shoot the ‘bad guys’.  Finally, if you can improve the above I’d love to hear you idea.  Once the tutorial is complete the code will be published to github.

Advertisements

3 thoughts on “A simple HTML5 Game tutorial – Part 2

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