Match-3 games are a great first project in Unity. They teach grid logic, input handling, and simple game state without heavy art or physics. This tutorial walks you through building a minimal match-3 puzzle game in Unity: a grid of gems, swap-on-click, and match detection that clears rows or columns.

You will need Unity 2022 LTS or newer (or Unity 6) and basic familiarity with the editor and C#. No packages beyond the built-in 2D setup are required.

What You Will Build

By the end you will have:

  • A configurable grid (rows and columns).
  • Gems (or colored tiles) that the player can select and swap.
  • Match detection for three or more in a row or column.
  • Matched gems removed and replaced so the board refills.

We will keep the design simple so you can extend it with scoring, combos, or special pieces later.

Step 1 - Project and Scene Setup

Create a new 2D Unity project. In your scene:

  1. Add an Orthographic Camera (default in 2D templates).
  2. Create an empty GameObject and name it GameBoard. This will hold the grid and logic.
  3. Optionally add a Panel or Sprite as a background so the board has clear bounds.

Set your camera size so that a grid of 8x8 or 6x7 cells fits comfortably. For example, with cell size 1 unit, an 8x8 grid fits in a camera size of about 5–6.

Pro tip: Use the same scale for all tiles (e.g. 1x1 world units per cell) so grid math stays simple. You can scale sprites in the Sprite Renderer to fit.

Step 2 - The Grid Data Structure

Create a C# script Match3Board.cs and attach it to GameBoard. This script will own the grid and game logic.

Start with a 2D array of “gem” types. For simplicity, use an integer or enum for each cell (e.g. 0 = red, 1 = green, 2 = blue). You can replace this later with references to prefabs or ScriptableObjects.

public class Match3Board : MonoBehaviour
{
    [Header("Grid")]
    public int rows = 8;
    public int cols = 8;
    public int gemTypes = 5;

    private int[,] grid;

    void Awake()
    {
        grid = new int[rows, cols];
        FillBoard();
    }

    void FillBoard()
    {
        for (int r = 0; r < rows; r++)
            for (int c = 0; c < cols; c++)
                grid[r, c] = Random.Range(0, gemTypes);
    }
}

Run the scene and confirm there are no errors. The board is still data-only; next we add visual tiles.

Step 3 - Spawning Tile Objects

Create a Gem prefab: a SpriteRenderer (with a simple sprite or colored quad) and a collider so we can click it. Add a small script Gem.cs that holds its grid position and type:

public class Gem : MonoBehaviour
{
    public int row;
    public int col;
    public int type;
}

In Match3Board, add a gemPrefab reference and a 2D array or list to track spawned gems. In FillBoard (or a separate SpawnAllGems method), instantiate a gem for each cell, set its position from row/col (e.g. transform.position = new Vector3(col, row, 0)), and set its Gem component’s row, col, and type from the grid. Parent them to the GameBoard so the hierarchy stays clean.

Pro tip: Use a prefab variant per gem type if you want different sprites per color; otherwise one prefab with a material or sprite swap is enough.

Step 4 - Player Input and Swap Logic

The player selects two adjacent gems to swap them. A simple approach:

  1. On first click, store the clicked gem (e.g. selectedGem).
  2. On second click, check if the new gem is a neighbor of the first (same row, adjacent column, or same column, adjacent row). If not, treat the new click as a new selection.
  3. If it is a neighbor, swap the two gems in the grid and in the scene (update positions and Gem row/col), then run match detection.

Implement IsNeighbor(int r1, int c1, int r2, int c2) so that it returns true only when (r1 == r2 && Mathf.Abs(c1 - c2) == 1) || (c1 == c2 && Mathf.Abs(r1 - r2) == 1). Use Swap(int r1, int c1, int r2, int c2) to swap values in the grid and move the two Gem transforms.

Common mistake: Forgetting to swap both the grid data and the visual positions. Always update both so that later logic (match detection) and the display stay in sync.

Step 5 - Match Detection

After a swap, check if either of the swapped positions is part of a match of three or more in a row or column. A straightforward method:

  • For each cell, look left and right (or up and down) and count consecutive same-type cells. If count >= 3, mark those cells as matched.
  • Do the same for the other axis.
  • Use a HashSet or a separate bool[,] to mark which cells form a match so you do not double-count.

Scan the whole board (or only rows/columns that contain the two swapped cells) and collect all matched cells. Then remove those gems from the grid and the scene, and refill the columns (see below).

Pro tip: Start with “match of exactly 3” logic; you can extend later to “3 or more” and special pieces that clear whole rows or columns.

Step 6 - Clearing and Refilling

When you clear matched cells:

  1. Remove the gem objects and set those grid slots to “empty” (e.g. -1 or a dedicated value).
  2. Drop gems above: move each column down so empty slots are at the top (shift grid values and gem positions).
  3. Refill the top row with new random types and spawn new gem objects.

Implement DropAndRefill() so that it runs after you clear matches. Then call match detection again on the new state; if new matches appear (e.g. from refill), clear them and repeat until no matches remain. That gives you a simple “chain” effect.

Step 7 - Valid Move Check (Optional but Recommended)

To avoid deadlock, only allow a swap if it creates at least one match. Before applying the swap, simulate it in a copy of the grid (or temporarily swap, run match detection, then revert if no match). If there is no match, do not perform the swap and optionally shake the selection or play a sound. You can also add a “shuffle” that runs when no valid moves exist.

Summary

You now have a minimal match-3 game in Unity: a data grid, spawned gems, click-to-select and swap, match detection for rows and columns, and clear-and-refill with drop. From here you can add scoring, UI, levels, or special gems. For more Unity basics, see our Unity guide and first 2D game tutorial.

Frequently Asked Questions

Do I need the Unity 2D package?
For a simple match-3, the built-in 2D template is enough. You only need sprites and an orthographic camera.

How do I make the board look better?
Add a background sprite, give each gem type a distinct sprite or color, and add simple tweening (e.g. DOTween or Unity’s Animation) when swapping and when gems fall.

Can I make matches of 4 or 5?
Yes. Use the same “count consecutive same type” logic; if count >= 3 you already support 3, 4, and 5. You can then spawn special gems when count >= 4.

How do I add a score?
Increment a score variable when you clear matches (e.g. 10 points per gem, or 30 for a match of 3). Display it with a Text or TextMeshPro UI element.

Found this useful? Bookmark it for your next Unity project or share it with your team.