(Part 1) How to Create Candy Crush in Unity: Setting up the project

Candy Crush in Unity

Have you always played video games like Candy Crush and wondered how difficult it is to make a Candy Crush clone in Unity?

Have you always dreamed of creating your game and publishing it on mobile stores?

The reality is that creating games has always required great computer skills, but thanks to the latest game engines like Unity 3D, becoming a game developer has become much easier.

In this article, I will teach you how to program a clone of the very famous match-three game Candy Crush Saga in Unity.

You will learn to create the game mechanics of a match-three game, to offer the player an interface to view the score and a menu to restart the game.

In our game we will be able to click on a cell to select it, then click on a side to perform an exchange, if in this way three or more cells of the same type will align these will disappear, the cells above will fall and new cells will be inserted in the spaces that will form at the top.

result of the match three mage
This is the game after you will finish this tutorial!

This is the first of three tutorials that will teach you how to complete this game.

In this first part you will learn how to set up the project and draw the grid of icons without matches of three or more elements. Stay tuned for the next parts of this tutorial!

Take a look to other parts:

Creating the project

To make this project I used Unity 2019.1, I recommend using the same version.

You can also use the current version 2019.3, but you have to update the asset database and import the Text Mesh Pro essentials on the first open.

Simply click yes when Unity asks for the Database Version 2 and “Import TMP Essentials” when prompted and continue with the tutorial.

At this link, you can find a project that I have already prepared for you, with all assets you will use to form the cells of the game. Click on “Source code” to download it. it’s a simple 2D basic project where I’ve already imported game assets (i.e. graphics files that will be used by the game) like Sprites. After the download completes, open it up with Unity.

Match three Initial project
The initial project you’ll find in the downloaded package

Creation of the game grid

To manage the game grid we will use a script called GridManager.

The homonym class will have the task of initializing the grid by inserting the images in the cells and checking if alignments of three or more identical images have occurred.

We will do things gradually, starting to populate our grid, then we will modify our algorithm to make sure that at the beginning of the game there are no alignments of three or more equal icons.

The grid will use the Row and Column indexes which will represent the rows and columns respectively, the index 0 will be at the bottom left.

match three game grid explanation
The indexes start from [0,0] in the bottom left corner.
We will scroll through all the elements of the grid, row by row, starting from the bottom, assigning a random image among those available.

To do this operation, let’s start by creating the GridManager script inside the Scripts folder, then create an empty Game Object and assign the GridManager to it. Now double click on the file to open it in Visual Studio.

Let’s take a moment to make a list of what we need:

  • A list of available icons, so that the initialization algorithm can choose which one to insert to populate our grid.
  • An array containing all the elements of the grid. Once the grid has been initialized, we have to save the result somewhere. This data structure will be used continuously by the algorithm that verifies the matches.
  • Our grid will have a size of 8×8

Trasformed in code, this is the result:

public List<Sprite> Sprites = new List<Sprite>();
public GameObject TilePrefab;
public int GridDimension = 8;
public float Distance = 1.0f;
private GameObject[,] Grid;

The Sprites list is where we are going to place the images that can appear in the grid, this attribute is public and will, therefore, be visible in the Unity inspector. Sprite is the class that unity uses to represent the concept of an image in the game. The TilePrefab attribute is a reference to a prefab a component needed to display the sprites on the screen.

Prefabs in Unity are reusable components that are widely used when many identical or similar elements need to be created.

In our case, this prefab will be used as a “stencil” to create our cells, which will subsequently be personalized by assigning a sprite. I have already created this prefab for you, it is located in Assets/Prefabs/Tile.prefab.

In this component, we are going to set a sprite extracted from the list above.

Next, we have GridDimension that store the size of the grid, Distance that store the distance of the cells when we will draw them and Grid, the actual grid represented as a two-dimensional array.

Candy Crush in Unity: Let’s populate the grid

Let’s go ahead, let’s create a function that will populate the grid:

void InitGrid()
{
    Vector3 positionOffset = transform.position - new Vector3(GridDimension * Distance / 2.0f, GridDimension * Distance / 2.0f, 0); // 1
    for (int row = 0; row < GridDimension; row++)
        for (int column = 0; column < GridDimension; column++) // 2
        {
            GameObject newTile = Instantiate(TilePrefab); // 3
            SpriteRenderer renderer = newTile.GetComponent<SpriteRenderer>(); // 4
            renderer.sprite = Sprites[Random.Range(0, Sprites.Count)]; // 5
            newTile.transform.parent = transform; // 6
            newTile.transform.position = new Vector3(column * Distance, row * Distance, 0) + positionOffset; // 7
                
            Grid[column, row] = newTile; // 8
        }
}

In order, the code of the InitGrid function takes care of:

  1. Calculate an offset so that the grid is centered in the position of the GameObject. This value will be added to the position of every cell later.
  2. The next instructions are performed for all the cells and since the data structure that houses them is a two-dimensional array, we use a nested cycle.
  3. To create a new GameObject we must use the Instantiate function, which accepts a prefab or a GameObject in scene as parameters. Our prefab is then used to create a new cell.
  4. From the new cell, we are going to get the reference to the SpriteRenderer component, where we will set the sprite of the cell.
  5. Let’s assign the sprite. The component has, in fact, a sprite attribute which is exactly what we need: we choose a random element from the list of sprites and assign it.
  6. We want all the cells to be childs of the grid, the advantage is that if we move the grid in the scene, all the cells will also move with her. Let’s assign to the parent attribute of the transform of the cell the transform of the grid.
  7. Assign the position of the cell. Let’s add the offset calculated before, so as to obtain a grid whose center corresponds to the position of the GameObject grid.
  8. We then save the reference to the newly created cell.

One more thing is missing! The function we just wrote is not called anywhere! In addition, the two-dimensional array has to be initialized, in fact, we cannot create it immediately like the list of sprites, because we do not know the size until the game is started.
Let’s then insert the following lines within the Start function:

Grid = new GameObject[GridDimension, GridDimension];
InitGrid();

Now save the file, and return to Unity.

We still have to go configure our GridManager in the inspector!

Select the Grid object, the component we have just written should now have four fields. Expand Sprites by clicking on the arrow, write ‘9’ (without quotes) next to Size to bring up nine new spaces.

One by one, through Drag & Drop all the sprites. You can also click on the dot on the right, and select the sprites from there.
Drag the Tile’s prefab from the prefab folder into the TilePrefab field.
We can leave the other fields as they are, we have already initialized them in the code.

inspector grid manager
This is how will appear the Grid Manager inspector after all properties are set

Now press play and the grid will be populated with random icons:

first iteration result
Result of the generation by the grid manager

Bonus: configurable features

Try to change these values, see how the grid changes thanks to these configurable parameters. it is always good to make the algorithms configurable.

If you work in a team, you could provide configurable components so that the non-programmers team members can change the behaviours of the game as they wish without stealing your precious time!
What else could be made configurable in this component? If we wanted the grid not to be square but rectangular how should we change the GridManager? Try it yourself, then discuss it in the comments!

Avoid sequence of three or more elements on initialization

We have therefore created our grid, but if you have looked carefully you will surely have noticed that can occur sequences of three or more elements, which we want to avoid! We must therefore find a way to limit the images to choose from within the InitGrid function.

Let’s take a moment to analyze how our algorithm should fill the cells:

match avoiding algorithm
How the algorithm to avoid matches on grid generation works

The algorithm starts from the bottom left, following each line to the right and moving up to the next line.

For each cell, we must take care to verify that the element we are going to insert does not form a match with those already assigned, in our implementation the two cells on the left, and the two at the bottom.

If one of them have the same icon, to avoid a match we will have to remove it from the sprites available for this cell and choose from the others.

In the picture, the dashed orange cell represents a cell with invalid indexes (in this negative case, but it could be greater than the size of the grid), which obviously must not be taken into consideration.

Let’s turn this reasoning into code. To compare the sprites of two cells, a function that gives us a sprite given its coordinates can be useful:

Sprite GetSpriteAt(int column, int row)
{
    if (column < 0 || column >= GridDimension
        || row < 0 || row >= GridDimension)
        return null;
    GameObject tile = Grid[column, row];
    SpriteRenderer renderer = tile.GetComponent();
    return renderer.sprite;
}

This function obtains as input the coordinates of the tile and ensures that they are valid, if negative or greater than the size of the table it returns null.

He then get the SpriteRenderer component and returns the sprite assigned to him.

Let’s use this function for our purposes. Inside the InitGrid function, at the beginning of the nested for loops, insert these lines of code:

List possibleSprites = new List(Sprites); // 1

//Choose what sprite to use for this cell
Sprite left1 = GetSpriteAt(column - 1, row); //2
Sprite left2 = GetSpriteAt(column - 2, row);
if (left2 != null && left1 == left2) // 3
{
   possibleSprites.Remove(left1); // 4
}

Sprite down1 = GetSpriteAt(column, row - 1); // 5
Sprite down2 = GetSpriteAt(column, row - 2);
if (down2 != null && down1 == down2)
{
    possibleSprites.Remove(down1);
}
  1. First, let’s create a copy of the sprite list from which we can choose an icon.
    We must check the two cell on the left and the two on the bottom. let’s start from the left:
  2. Get sprites using the function we wrote earlier. As indices we want the two on the left, so we subtract from the index which represents the current column 1 and 2. It is not necessary to check if this value is valid, it is already carried out in the function.
  3. To decide whether to remove a sprite from the selectable ones, we check if we have a null value to see if it is a valid cell or not (in case the indices are not valid) and if the two cells are the same. If they are, their sprite must be removed from the selectable list
  4. Remove the sprite. In this instruction, it is indifferent to use the variable left1 or left2, since they have the same value.
  5. We repeat the same operations also for the two cells below.

The end result will be this:

Grid without matches in candy crash clone
The resulting grid without matches

Conclusions

In this first part of the tutorial, you learned how to create the grid of elements without matches of three or more elements.

In the next two parts, you will learn how to swap tiles, how to delete cells that form match and how to create a GUI for the game, with in-game info and a menu to restart the game.

And here the next part for moving the cells!

I hope you enjoyed this tutorial, let me know in the comments what do you think and share with your friends!

More from Andrea Peretti

(Part 3) Create Candy Crush Clone: Identify matches + exercise

Hello my friend, welcome to the third part of this tutorial on...
Read More

9 Comments

  • Thanks for the interesting tutorial.
    When I was trying for the first time Unity and VS find an error “CS0411 C# The type arguments for the method cannot be inferred from the usage. Try specifying the type arguments explicitly” in SpriteRenderer renderer = newTile.GetComponent();. Solved by add generic function to GetComponent. SpriteRenderer renderer = newTile.GetComponent();.

    • The tutorial doesn’t tell you to update the line where renderer.sprite is assigned. Rather than randomly selecting from Sprites, you need to randomly select from possibleSprites

  • I had the same issue here.
    But I solved it like this:
    I used
    “renderer.sprite = possibleSprites[Random.Range(0, possibleSprites.Count)]; // 5”
    instead of
    “renderer.sprite = Sprites[Random.Range(0, Sprites.Count)]; // 5”

    I also had to change the following line
    “List possibleSprites = new List(Sprites); // 1”
    into
    “List possibleSprites = new List(Sprites); // 1”
    cause the original line brought an error in VisualStudio saying: “The usage of Type “List” (generic) requires 1-argument

    Maybe that helps.

  • In order to get the code to work, I made the following changes.

    Change
    “List possibleSprites = new List(Sprites); // 1”
    to
    “List possibleSprites = new List(Sprites); // 1”

    The best explanation I can come up for this scouring the internet is that a List must be accompanied by a ‘type’ of the things that will go in the list. You must specify that the elements of the list will be Sprites. This fixes “The usage of Type “List” requires 1-argument”.

    You will also need to change
    “renderer.sprite = Sprites[Random.Range(0, Sprites.Count)]; // 5”
    to
    “renderer.sprite = possibleSprites[Random.Range(0, possibleSprites.Count)]; // 5”

    keeping in mind that our reference list of Sprites is no longer Sprites but possibleSprites — the entire reason we implement the new code.

    Finally I had an issue in the GetSpriteAt function. Changing

    ” SpriteRenderer renderer = tile.GetComponent(); ”
    to
    ” SpriteRenderer renderer = tile.GetComponent(); ”
    will fix the error, as it specifies that the component you want is a SpriteRenderer.

    • You need to create two variables instead of gridDimension, say gridHeight and gridWidth, and change it accordingly in the code. basically whenever the original code uses gridDimension, you should substitute it by either width or height…

      I know it is a one year late answer, but I would like to keep this message here if anyone else ever needs it.

  • i have set up everything as per instruction. when i run the game and click the sprites it plays sound and changes color but it does not move. does not find match

    my tile has box collider and the tile script

Leave a Reply

Your email address will not be published. Required fields are marked *