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:

  1. Game Board: a container for the tiles
  2. Tiles: the individual tiles that can be flipped and matched
  3. Color Randomizing: generating and assigning random colors to the tiles
  4. Click Handling: detecting clicks on tiles and performing the appropriate action
  5. Match Checking: determining if two flipped tiles have matching colors
  6. 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!

Similar Posts