HTML5 and JQuery: A simple matching game

HTML5 has exploded!  Old news I know.  Finally, it is possible to match the swish effects once reserved for Flash.  Thus, my next project was to write a simple (very simple!) game using HTML5.  On its own HTML5 is not a like-for-like replacement for Flash. It only becomes super-charged when mixed with a strong JavaScript library and some cool CSS.

The game covered in this post is a simple tile based memory game.

Matching game image

Matching tiles
Players can simply click a tile to reveal the hidden image.  Followed by a second selection to find the matching tile.  If the tiles match they remain revealed.  However, if they do not match they quickly flip back.
The code behind the scenes is simple JavaScript.  I used the JQuery library which is included within the main document:


	
	
	
	
	
	
	
	
	


	<article id="game">
		<header>
			<div>Simple HTML5 Matching Game</div>
		</header>
		<section id="board">
		</section>
		<a href='#' id="startGameButton">New Game</a>
	</article>
	
	  
	Your browser does not support the audio element.
	


The above extract creates a header section, a region for the game and an audio tag. These elements are then styled using CSS which is included as follows:
	
During the initial load a small portion of JavaScript is executed. This instantiates a click handler, so that when a player clicks the ‘New Game’ hyper-link it runs the code that sets-up the game board. The code for setting up the click handler follows:
$(document).ready(function() {
	
	$('#startGameButton').click(function() {
	
		initTiles();
		
		setTimeout("revealTiles(function() { onPeekStart(); })",iInterval);

	});
});
To start a game the player needs to hit the “New Game” hyper-link. This triggers the execution of JavaScript code which is included in the following script file:
	
Specifically the function called ‘initTiles’ followed by a call to the ‘revealTiles’ function:

function initTiles() {

	var iCounter = 0, 
		curTile = null;

	initState();
	
	// Randomly create twenty tiles and render to board
	for(iCounter = 0; iCounter < 20; iCounter++) {
		
		curTile = createTile(iCounter);
		
		$('#board').append(curTile.getHTML());
		
		tiles.push(curTile);
	}	
}

The above function applies default values to various variables and creates twenty tile objects. Each object holds the necessary information to draw the tile in its alternate states during the game e.g. flipped or not flipped. Each tile object is fundamental to the game and the code for the tile is located in ’tile.js’. This file is included within the HTML. It contains the definition for a JavaScript object. The object is structured as follows:

function tile(id) {
	
	this.id = id;
	this.frontColor = '#fcfcfc';
	this.backColor = '#fff';
	this.startAt = 1000;
	this.flipped = false;
	this.backContentImage = null;
	this.flipCompleteCallbacks = new Array();
	
	this.flip = function() {

		$("#" + this.id).flip({
			direction: this.flipMethod,
			color: this.backColor,
			content: this.getBackContent(),
			onEnd: this.onFlipComplete()
		});

		$("#" + this.id + " img").show();
		
		this.flipped = true;
	};
	
	this.onFlipComplete = function() {
		
		while(this.flipCompleteCallbacks.length &gt; 0) {
			
			this.flipCompleteCallbacks[this.flipCompleteCallbacks.length - 1]();
			this.flipCompleteCallbacks.pop();
		}
	};
	
	this.revertFlip = function() {

		$("#" + this.id + " img").hide();
		
		$("#" + this.id).revertFlip();

		this.flipped = false;
	};
	
	this.setBackContentImage = function(sBackContentImage) {
		this.backContentImage = sBackContentImage;
	};
	
	this.setTileId = function(sIdOfTile) {
		this.id = sIdOfTile;
	};

	this.setStartAt = function(iStartAt) {
		this.startAt = iStartAt;
	};
	
	this.setFrontColor = function(sColor) {
		this.frontColor = sColor;
	};

	this.setBackColor = function(sColor) {
		this.backColor = sColor;
	};

	this.setFlipMethod = function(sFlipMethod) {
		this.flipMethod = sFlipMethod;
	};
	
	this.getHTML = function() {
		return '<div id="' + this.id + '" class="tile ' + this.frontColor + '">' + '</div>';
	};

	this.getStartAt = function() {
		return this.startAt;
	};

	this.getFlipped = function() {
		return this.flipped;
	};
	
	this.getBackContent = function() {
		return '<img src="' + this.backContentImage + '" />';
	};

	this.getBackContentImage = function() {
		return this.backContentImage;
	};
	
	this.addFlipCompleteCallback = function(callback) {
		this.flipCompleteCallbacks.push(callback);
	};
}

Skipping the lesson in JavaScript, the object contains a collection of methods which handles the flip and reverse flip action. It also holds several variables to store the state of the tile. As each tile is created within the initialisation function ‘initTile’, it is stored within the global array called ’tiles’. This is used later to draw the board.

Once the initialisation function is complete the game board in rendered to the page. This is managed by the ‘revealTiles’ function which is called as follows:

setTimeout("revealTiles(function() { onPeekStart(); })",iInterval);

The reveal function contains the following code:

function revealTiles(callback) {
	
	var iCounter = 0,
		bTileNotFlipped = false;

	for(iCounter = 0; iCounter  tiles[iCounter].getStartAt()) {
				tiles[iCounter].flip();
			}
			else {
				bTileNotFlipped = true;
			}
		}
	}
	
	iTimer = iTimer + iInterval;

	if(bTileNotFlipped === true) {
		setTimeout("revealTiles(" + callback + ")",iInterval);
	} else {
		callback();
	}
}
The reveal function allows the player to have a peak at the tiles hidden image. It is called via a timer e.g. every 300 milliseconds. This allows each tile to perform an initial flip at a given time. Therefore, the sequence in which the tiles flip is sequential, but, staggered. When all of the tiles are revealed a callback function ‘onPeekStart’ is executed after a 3 second wait – allowing the player to memorise the tiles – and then executes the function that reverses the flip, and therefore, hides the images again.
The code within ‘onPeekStart’ follows:

function onPeekStart() {
	setTimeout("hideTiles( function() { onPeekComplete(); })",iPeekTime);
}

As you can see the code calls the ‘hideTiles’ function after waiting a defined number of milliseconds. Again this function makes use of a callback function. In this case the callback function is ‘onPeekComplete’. The ‘hideTiles’ function follows:

function hideTiles(callback) {
	
	var iCounter = 0;

	for(iCounter = 0; iCounter < tiles.length; iCounter++) {
		
		tiles[iCounter].revertFlip();

	}
	
	callback();
}

The above function uses the global array ’tiles’ and calls the reverse action of each tile. This instructs the tile to perform the reverse flip animation. Once each tile has been instructed to flip the callback function is executed which we know to be the following:
function onPeekComplete() {

	$('div.tile').click(function() {
	
		iTileBeingFlippedId = this.id.substring("tile".length);
	
		if(tiles[iTileBeingFlippedId].getFlipped() === false) {
			tiles[iTileBeingFlippedId].addFlipCompleteCallback(function() { checkMatch(); });
			tiles[iTileBeingFlippedId].flip();
		}
	  
	});
}
The above code binds the click event of each of the tiles to the in-line JavaScript function above. This contains the code which actions the click e.g. flip the tile to reveal the image. A third use of JavaScript callback pattern is used. This time the ‘checkMatch’ function is called when the flip action is complete. This contains the following:
function checkMatch() {
	
	if(iFlippedTile === null) {
		  
		iFlippedTile = iTileBeingFlippedId;

	} else {
		
		if( tiles[iFlippedTile].getBackContentImage() !== tiles[iTileBeingFlippedId].getBackContentImage()) {
			
			setTimeout("tiles[" + iFlippedTile + "].revertFlip()", 2000);
			setTimeout("tiles[" + iTileBeingFlippedId + "].revertFlip()", 2000);
			
			playAudio("mp3/no.mp3");

		} else {
			playAudio("mp3/applause.mp3");
		}

		iFlippedTile = null;
		iTileBeingFlippedId = null;
	}
}
This function is responsible for applying the rules of the game. When the first tile is flipped the function stores the id of the flipped tile within a global variable called ‘iFlippedTile ‘. When the second tile is flipped the two are compared. If they match the tiles remain image up and a favourable sound is played to celebrate the match. Alternatively, if the tiles do not match they are flipped. This action repeats until the player has matched all of the tiles.
That concludes this post. A working version can be viewed here. The source code is available in Github.
Advertisements

38 thoughts on “HTML5 and JQuery: A simple matching game

  1. Hi. Please, how i add a sound when the card is flipped? Is it possible in canvas and html5? I want to add sound to one card and another sound to second card.thanks for your help

    1. The cards are represented by the tile object. You could add a variable to it and set it using a setter e.g. tile.setFlipSound(‘flip.mp3’); Then when flipping a card add a call to the playAudio function e.g. playAudio(this.flipSound);

  2. Can I make a match pair game using your this game? I want to make a game for matching similar but different objects rather than matching same objects.

  3. Hi Geeksretreat,
    Thanking you for providing such a nice game. Its really awesome.
    I would like to use your code partially to re-create this game and use it in my game library for kids. I may use it for commercial purpose.
    i am, therefore, seeking your permission for the same.
    If you have any objection, please call it out so that i may look for some other source.
    Thanking you in advance.

  4. is there a way to use more than 10 images and randomly use them? i already managed to use another image, but than ther are mistakes in the game. eg one picture is used three times and an other just once.

  5. Hi,
    is it possible to add and define time for the games (with a timer) and a number of lives…

    If it is possible, thank you for telling me how to make 😉

    1. I’ve been thinking about that for one of my future post. In strikes me that the game state need wrapping around the current code. This would hold and keep track of lives, score, high-score, level and difficulty which would be factored into the main engine.

  6. Hi Ray
    This has got me close to what I’m looking for. I’m trying to create a game where one image is hidden by a grid of say 12 tiles. When one tile is clicked that part of the image is revealed. When another is clicked, the first is concealed again and the new tile is revealed (only one tile revealed at any one time). I can’t seem to find any code anywhere to help me with this. Do you know of any or are you able to advise on how your code could be manipulated to acheive this? Really appreciate any help you can offer.
    Thanks
    Marc

  7. I want to reuse your script. I didnt see any license included in github so I am wondering what license do you choose foe your scripts like the html match card game script?

  8. hello.i want to tell me if i can match two images with diffrent “name of image”. i am trying to find the code but i can’t…:-(

  9. hello, I am trying to implement a timer and a click counter but i can’t seem to succeed. Can anyone help please? much obliged.

  10. Hi Ray, thank you for posting the script. I would like to use your script partially or fully for commercial purpose. I saw you gave your approval for others on previous comments, and may I please have your permission directly? Thank you again!

  11. Very good script! I’m using it on a public touch display when no information is displayed.
    I have only one problem: If somebody is clicking/taping very fast the flip function isn’t starting and you can’t see the picture after a match. How and where can I fix the problem? I’m not very good at Java and HTML…

      1. thanks for the link, I am thinking how to re-use such content, but i am having difficultly using it offline i am running windows xp. could there be an issue?

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