How to Make a Match 3 Game in Unity

Learn how to make a Match 3 game in this Unity tutorial! By Jeff Fisher.

Leave a rating/review
Save for later
Share
You are currently viewing page 2 of 4 of this article. Click here to view the first page.

Prevent Repeating Tiles

generatingMatches

The board generates up and then right, so to correct the “automatic” matching 3 combo you'll need to detect what sprite is to the left of your new tile, and what sprite is below your new tile.

To do this, create two Sprite variables in the CreateBoard method, right above the double for-loops:

    Sprite[] previousLeft = new Sprite[ySize];
    Sprite previousBelow = null;

These variables will be used to hold a reference to adjacent tiles so you can replace their characters.
Take a look at the image below:

The loop iterates through all tiles from the bottom left and goes up one tile at a time. Every iteration gets the character displayed left and below the current tile and removes those from a list of new possible characters.
A random character gets pulled out of that list and assigned to both the left and bottom tiles.
This makes sure there'll never be a row of 3 identical characters from the start.

To make this happen, add the following lines right above Sprite newSprite = characters[Random.Range(0, characters.Count)];:

List<Sprite> possibleCharacters = new List<Sprite>(); // 1
possibleCharacters.AddRange(characters); // 2

possibleCharacters.Remove(previousLeft[y]); // 3
possibleCharacters.Remove(previousBelow);
  1. Create a list of possible characters for this sprite.
  2. Add all characters to the list.
  3. Remove the characters that are on the left and below the current sprite from the list of possible characters.

Next, replace this line:

Sprite newSprite = characters[Random.Range(0, characters.Count)];

with

Sprite newSprite = possibleCharacters[Random.Range(0, possibleCharacters.Count)];

This will select a new sprite from the list of possible characters and store it.

Finally, add these lines underneath newTile.GetComponent().sprite = newSprite;:

previousLeft[y] = newSprite;
previousBelow = newSprite;

This assign the newSprite to both the tile left and below the current one for the next iteration of the loop to use.

Run the game, and check out your new dynamic grid with non-repeating tiles!

non-repeating

Swapping Tiles

The most important gameplay mechanic of Match 3 games is selecting and swapping adjacent tiles so you can line up 3 in a row. To achieve this you'll need to do some additional scripting. First up is selecting the tile.

Open up Tile.cs in a code editor. For convenience, this script has already been laid out with a few variables and two methods: Select and Deselect.

Select tells the game that this tile piece has been selected, changes the tile’s color, and plays a selection sound effect. Deselect returns the sprite back to its original color and tells the game no object is currently selected.

What you don't have is a way for the player to interact with the tiles. A left mouse click seems to be a reasonable option for controls.

Unity has a built-in MonoBehaviour method ready for you to use: OnMouseDown.

Add the following method to Tile.cs, right below the Deselect method:

void OnMouseDown() {
	// 1
    if (render.sprite == null || BoardManager.instance.IsShifting) {
        return;
    }

    if (isSelected) { // 2 Is it already selected?
        Deselect();
    } else {
        if (previousSelected == null) { // 3 Is it the first tile selected?
            Select();
        } else {
            previousSelected.Deselect(); // 4
        }
    }
}
  1. Make sure the game is permitting tile selections. There may be times you don't want players to be able to select tiles, such as when the game ends, or if the tile is empty.
  2. if (isSelected) determines whether to select or deselect the tile. If it's already been selected, deselect it.
  3. Check if there's already another tile selected. When previousSelected is null, it's the first one, so select it.
  4. If it wasn't the first one that was selected, deselect all tiles.

Save this script and return to the editor.
You should now be able to select and deselect tiles by left clicking them.

select

All good? Now you can add the swapping mechanism.

Swapping Tiles

Start by opening Tile.cs and adding the following method named SwapSprite underneath the OnMouseDown method:

public void SwapSprite(SpriteRenderer render2) { // 1
    if (render.sprite == render2.sprite) { // 2
        return;
    }

    Sprite tempSprite = render2.sprite; // 3
    render2.sprite = render.sprite; // 4
    render.sprite = tempSprite; // 5
    SFXManager.instance.PlaySFX(Clip.Swap); // 6
}

This method will swap the sprites of 2 tiles. Here's how it works:

  1. Accept a SpriteRenderer called render2 as a parameter which will be used together with render to swap sprites.
  2. Check render2 against the SpriteRenderer of the current tile. If they are the same, do nothing, as swapping two identical sprites wouldn't make much sense.
  3. Create a tempSprite to hold the sprite of render2.
  4. Swap out the second sprite by setting it to the first.
  5. Swap out the first sprite by setting it to the second (which has been put into tempSprite.
  6. Play a sound effect.

With the SwapSprite method implemented, you can now call it from OnMouseDown.
Add this line right above previousSelected.Deselect(); in the else statement of the OnMouseDown method:

SwapSprite(previousSelected.render);

This will do the actual swapping once you've selected the second tile.
Save this script and return to the editor.
Run the game, and try it out! You should be able to select two tiles and see them swap places:

SwappingGif

Finding Adjacent Tiles

You've probably noticed that you can swap any two tiles on the board. This makes the game way too easy. You’ll need a check to make sure tiles can only be swapped with adjacent tiles.

But how do you easily find tiles adjacent to a given tile?

Open up Tile.cs and add the following method underneath the SwapSprite method:

private GameObject GetAdjacent(Vector2 castDir) {
    RaycastHit2D hit = Physics2D.Raycast(transform.position, castDir);
    if (hit.collider != null) {
        return hit.collider.gameObject;
    }
    return null;
}

This method will retrieve a single adjacent tile by sending a raycast in the target specified by castDir. If a tile is found in that direction, return its GameObject.

AdjacentRaycasts

Next, add the following method below the GetAdjacent method:

private List<GameObject> GetAllAdjacentTiles() {
    List<GameObject> adjacentTiles = new List<GameObject>();
    for (int i = 0; i < adjacentDirections.Length; i++) {
        adjacentTiles.Add(GetAdjacent(adjacentDirections[i]));
    }
    return adjacentTiles;
}

This method uses GetAdjacent() to generate a list of tiles surrounding the current tile. This loops through all directions and adds any adjacent ones found to the adjacentDirections which was defined at the top of the script.

With the new handy methods you just created, you can now force the tile to only swap with its adjacent tiles.

Replace the following code in the OnMouseDown method:

else {
    SwapSprite(previousSelected.render);
    previousSelected.Deselect();
}

with this:

else {
    if (GetAllAdjacentTiles().Contains(previousSelected.gameObject)) { // 1
        SwapSprite(previousSelected.render); // 2
        previousSelected.Deselect();
    } else { // 3
        previousSelected.GetComponent<Tile>().Deselect();
        Select();
    }
}
  1. Call GetAllAdjacentTiles and check if the previousSelected game object is in the returned adjacent tiles list.
  2. Swap the sprite of the tile.
  3. The tile isn't next to the previously selected one, deselect the previous one and select the newly selected tile instead.

Save this script and return to the Unity editor.
Play your game and poke at it to make sure everything’s working as intended. You should only be able to swap two tiles that are adjacent to one another now.

Now you need to handle the real point of the game — matching!