How to Make a Match 3 Game in Unity
Learn how to make a Match 3 game in this Unity tutorial! By Jeff Fisher.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
How to Make a Match 3 Game in Unity
30 mins
Prevent Repeating Tiles
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);
- Create a list of possible characters for this sprite.
- Add all characters to the list.
- 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
:
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!
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
}
}
}
- 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.
-
if (isSelected)
determines whether to select or deselect the tile. If it's already been selected, deselect it. - Check if there's already another tile selected. When
previousSelected
is null, it's the first one, so select it. - 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.
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:
- Accept a SpriteRenderer called
render2
as a parameter which will be used together withrender
to swap sprites. - 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. - Create a
tempSprite
to hold the sprite ofrender2
. - Swap out the second sprite by setting it to the first.
- Swap out the first sprite by setting it to the second (which has been put into
tempSprite
. - 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:
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.
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();
}
}
- Call
GetAllAdjacentTiles
and check if thepreviousSelected
game object is in the returned adjacent tiles list. - Swap the sprite of the tile.
- 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!