Creating the Memory Game

The Face object

We'll use a Face class to keep track of each image on the grid. When we create a new Face, it'll be given the x, y position of the Face on the grid, and a spriteX, spriteY which is the column and row of the sprite to use for this entry:

function Face(x, y, spriteX, spriteY)
{

The spritePos is an array storing the calculated x, y pixel coordinates of the sprite for this face on the sprite image, calculated from spriteX x spriteSheet.tileW, and the spriteY x spriteSheet.tileH.

	this.spritePos = [(spriteX * spriteSheet.spriteW),
			(spriteY * spriteSheet.spriteH)];

We'll also store the calculated position of the Face relative to the grid top-left drawing position in pixels, using the x, y arguments multiplied by the spriteSheet.tileW and spriteSheet.tileH respectively:

	this.pos = [(x * spriteSheet.spriteW),
			(y * spriteSheet.spriteH)];

The typeID (index) of the sprite being used is calculated from the spriteY x spriteSheet.cols plus spriteX. This is used for comparing Faces to see if they match.

	this.typeID = (spriteY * spriteSheet.cols) + spriteX;

We'll also store the currentState of the Face, to begin with they'll all be hidden. The stateChanged will store the gameTime when the Face begins animating, but is set as 0 by default, and active is a boolean flag that states whether or not the Face is currently in the activeFaces list.

	this.currentState	= 'hidden';
	this.stateChanged	= 0;
	this.active		= false;
}

We can also close this function with our curly brace.

Face methods

Faces in the activeFaces list will have their update method called every time the game logic is processed:

Face.prototype.update = function()
{

If this Face has the state incorrect (the Player tried to match it to the wrong partner), we check if 700 milliseconds has elapsed since the stateChanged time was set...

	if(this.currentState=='incorrect' &&
		(gameTime - this.stateChanged) > 700)
	{

If it has, we hide this Face (change the currentState to hidden), change the stateChanged property to the current gameTime, and set the active flag to false (so we know to remove it from the activeFaces array):

		this.currentState	= 'hidden';
		this.stateChanged	= gameTime;
		this.active		= false;

We can close this if block and method.

	}
};

Handling input

When a Face is clicked on, we want to allow it to do some processing:

Face.prototype.click = function()
{

If the Face has already been matched to its partner, we do nothing; this entry no longer handles user input.

	if(this.currentState=='correct') { return; }

If the Face is the current visibleFace we'll just hide it - this is done by setting the currentState to hidden, the stateChanged time to 0, and the global visibleFace to null. We the return to exit the function:

	if(visibleFace==this)
	{
		this.currentState	= 'hidden';
		this.stateChanged	= 0;
		visibleFace		= null;
		return;
	}

If no Face is currently visible (visibleFace is null), then we want to make this the visibleFace. We change the Face currentState to visible, set the stateChanged to the current gameTime, and set the global visibleFace to this.

	if(visibleFace==null)
	{
		visibleFace		= this;
		this.currentState	= 'visible';
		this.stateChange 	= gameTime;
	}

Otherwise, if the current visibleFace matches this Face (the typeID attributes match), we set the currentState to correct and update the stateChanged time...

	else if(visibleFace.typeID==this.typeID)
	{
		this.currentState	= 'correct';
		this.stateChanged	= gameTime;

...as well as updating the visibleFace currentState to correct and updating its stateChanged time, and after reset the visibleFace global to null:

		visibleFace.currentState	= 'correct';
		visibleFace.stateChanged	= gameTime;
		visibleFace			= null;

We'll close this else if statement, but before doing so call our method for checking if the grid is completely revealed (checkState).

		checkState();
	}

If the other if/else cases are not true, then we can assume the currently revealed faces do not match. In this case, we'll set the currentState of both this face and the visibleFace to incorrect, update their stateChanged time to the current gameTime, and set both of their active flags to true.

		this.currentState	= 'incorrect';
		this.stateChanged	= gameTime;
		this.active		= true;
		
		visibleFace.currentState	= 'incorrect';
		visibleFace.stateChanged	= gameTime;
		visibleFace.active		= true;

A reference to both this face and the visibleFace will be added to the visibleFaces array so we know we're updating them, and the global visibleFace reference will be reset to null:

		activeFaces.push(this);
		activeFaces.push(visibleFace);
		
		visibleFace = null;

We're then OK to close this if block and end the method:

	}
};
Page loaded in 0.012 second(s).