How to Build a Matching Game in Your Free Time with Easel.js
Are you a beginning to intermediate JavaScript developer looking for a fun project to practice your skills? Building games is an engaging way to solidify your coding abilities while creating something entertaining you can share with others.
In this tutorial, I‘ll walk you through building a matching game using Easel.js, a powerful library for 2D graphics and game development in JavaScript. We‘ll cover the basics of setting up the game board, randomizing tiles, handling click events, checking for matches, and more.
By the end, you‘ll have a fully functional matching game you can extend and customize. Let‘s jump in!
What is Easel.js?
Easel.js is a JavaScript library that makes it easy to work with HTML5 canvas and create interactive 2D graphics. It provides a display list and tools for drawing shapes, images, text, and more.
Some advantages of Easel.js include:
- Straightforward API for drawing on HTML canvas
- Hierarchical display list for nesting and organizing objects
- Built-in event system for handling mouse interactions
- Optimized rendering to handle frequent screen updates in games
These features make Easel.js a great choice for building a tile-based matching game without needing to directly manipulate the canvas or implement complex logic from scratch.
Game Overview
Before diving into the code, let‘s outline the basic structure and mechanics of the matching game:
- The game board consists of a grid of square tiles, initially hidden
- Clicking a tile flips it over, revealing its color
- When two tiles are flipped:
— If their colors match, the tiles disappear
— If the colors don‘t match, the tiles flip back over - The game is won when all tiles have been matched
With that in mind, we can break the implementation into a few key components:
- Game Board: a container for the tiles
- Tiles: the individual tiles that can be flipped and matched
- Color Randomizing: generating and assigning random colors to the tiles
- Click Handling: detecting clicks on tiles and performing the appropriate action
- Match Checking: determining if two flipped tiles have matching colors
- Game End: tracking the number of matches to determine when all tiles have been cleared
Let‘s go through each component and build up the game step-by-step.
Setting Up the Easel Stage
First, we need to create an HTML canvas element where the game will be rendered. Add this to your HTML file:
<canvas id="gameCanvas" width="720" height="540"></canvas>
We‘ll use a 720×540 pixel canvas, but you can adjust the dimensions to fit your desired game size.
Next, set up the Easel Stage, which serves as the root container for all our game elements:
const stage = new createjs.Stage("gameCanvas");
Pass in the ID of the canvas element, and Easel will handle the rest. We‘ll add child elements to this stage to build up the game board.
Creating the Game Board and Tiles
Now, let‘s create a container for the tiles and set up some variables to configure the game board:
const tileContainer = new createjs.Container();
stage.addChild(tileContainer);
const tileCount = 32;
const tileSize = 70;
const tileSpacing = 10;
const columns = 8;
Here, we‘re creating a 4×8 grid of 32 tiles, each 70×70 pixels with 10 pixels of spacing between them. Adjust these values based on your desired game board size and layout.
To create the tiles, we‘ll write a createTile
function that draws a single tile and returns an Easel Shape object:
function createTile(color) {
const tile = new createjs.Shape();
tile.graphics.beginFill(color).drawRect(0, 0, tileSize, tileSize);
tile.graphics.endFill().beginStroke("black").drawRect(0, 0, tileSize, tileSize);
return tile;
}
Each tile is a colored square with a black border. We‘ll generate the color dynamically in the next step.
Randomizing Tile Colors
To create a matching game, we need pairs of tiles with the same color. We can generate random colors and ensure there are two of each color by creating an array of colors, doubling it, and shuffling the result:
function generateColors(count) {
const colors = [];
for (let i = 0; i < count / 2; i++) {
const color = generateRandomColor();
colors.push(color, color);
}
shuffleArray(colors);
return colors;
}
function generateRandomColor() {
const r = Math.floor(Math.random() * 256);
const g = Math.floor(Math.random() * 256);
const b = Math.floor(Math.random() * 256);
return `rgb(${r}, ${g}, ${b})`;
}
function shuffleArray(array) {
for (let i = array.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[array[i], array[j]] = [array[j], array[i]];
}
}
The generateColors
function takes the total number of tiles and returns an array of random colors, with each color appearing twice. generateRandomColor
creates a random RGB color string, and shuffleArray
randomizes the order of the colors using the Fisher-Yates shuffle algorithm.
Now we can create the tiles and add them to the game board:
const colors = generateColors(tileCount);
for (let i = 0; i < tileCount; i++) {
const tile = createTile(colors[i]);
tile.x = (i % columns) * (tileSize + tileSpacing);
tile.y = Math.floor(i / columns) * (tileSize + tileSpacing);
tileContainer.addChild(tile);
}
This loops through the colors array, creates a tile for each color, positions it in a grid layout based on the column and row index, and adds it to the tile container.
Handling Tile Clicks
To flip tiles when they are clicked, we need to add an event listener to each tile that listens for the "click" event:
function handleClick(event) {
const tile = event.currentTarget;
// TODO: Implement tile flipping and matching logic
}
for (let i = 0; i < tileCount; i++) {
const tile = createTile(colors[i]);
// ... positioning code ...
tile.addEventListener("click", handleClick);
tileContainer.addChild(tile);
}
Inside the handleClick
function, we‘ll add the logic for flipping tiles and checking for matches in the next steps.
Flipping Tiles
To flip a tile, we‘ll toggle its visibility by changing its opacity. We also need to keep track of the first and second tiles that are flipped to check if they match.
let firstFlippedTile = null;
let secondFlippedTile = null;
function handleClick(event) {
const tile = event.currentTarget;
if (tile === firstFlippedTile || tile.opacity === 1) {
return;
}
tile.opacity = 1;
if (!firstFlippedTile) {
firstFlippedTile = tile;
} else {
secondFlippedTile = tile;
checkForMatch();
}
}
If the clicked tile is already flipped (opacity 1) or is the same as the first flipped tile, we ignore the click. Otherwise, we set the tile‘s opacity to 1 to reveal its color.
If firstFlippedTile
is null, we assign the clicked tile to it. If firstFlippedTile
is already set, we assign the clicked tile to secondFlippedTile
and call checkForMatch
to determine if the tiles match.
Checking for Matches
In the checkForMatch
function, we compare the colors of the two flipped tiles. If they match, we remove them from the game board. If they don‘t match, we flip them back over after a short delay.
function checkForMatch() {
if (firstFlippedTile.graphics._fill.style === secondFlippedTile.graphics._fill.style) {
// Tiles match, remove them from the board
createjs.Tween.get(firstFlippedTile).to({ opacity: 0 }, 500).call(removeFromStage, null, firstFlippedTile);
createjs.Tween.get(secondFlippedTile).to({ opacity: 0 }, 500).call(removeFromStage, null, secondFlippedTile);
} else {
// Tiles don‘t match, flip them back over
setTimeout(() => {
firstFlippedTile.opacity = 0;
secondFlippedTile.opacity = 0;
firstFlippedTile = null;
secondFlippedTile = null;
}, 500);
}
}
function removeFromStage(tile) {
tileContainer.removeChild(tile);
}
We use the Easel Tween class to animate the opacity of matching tiles to 0 over 500 milliseconds, then call removeFromStage
to remove them from the tile container.
If the tiles don‘t match, we use setTimeout
to flip them back over after a 500-millisecond delay by setting their opacity to 0.
Checking for Game End
Finally, we need to track the number of matches and determine when all tiles have been cleared to signal the end of the game.
let matchCount = 0;
function checkForMatch() {
if (firstFlippedTile.graphics._fill.style === secondFlippedTile.graphics._fill.style) {
// ... remove tiles ...
matchCount++;
if (matchCount === tileCount / 2) {
// All tiles have been matched
alert("Congratulations, you won!");
}
} else {
// ... flip tiles back over ...
}
}
We increment the matchCount
variable each time a match is found. When matchCount
equals half of the total number of tiles (since each color appears twice), we know all tiles have been matched and the game is won.
Enhancing the Game
Congratulations, you now have a basic matching game up and running! There are many ways you can extend and enhance it:
- Use images instead of solid colors for the tiles
- Add a scoring system based on the number of moves or time taken to complete the game
- Implement different difficulty levels by increasing the number of tiles or colors
- Create an appealing UI around the game board with a title screen, instructions, and restart button
Feel free to customize the game and make it your own!
Conclusion
In this tutorial, we walked through building a matching game using Easel.js. We covered:
- Setting up the Easel Stage and canvas
- Creating the game board and tiles
- Randomizing tile colors and positions
- Handling tile click events
- Flipping tiles and checking for matches
- Determining when the game is won
I hope this has been a helpful introduction to building games with Easel.js. With the core mechanics in place, you have a solid foundation to build upon and create increasingly complex and engaging games.
Remember, the key to becoming a better developer is practice and experimentation. Don‘t be afraid to try new things, break stuff, and learn from your mistakes. Happy coding!