How To Create Creating a Candy Crush Clone: HTML, CSS, and JavaScript Tutorial

codinglabsolution

Transform your aspirations of game development into tangible results! Dive into the world of web development by mastering HTML, CSS, and JavaScript, and embark on the journey to create your very own Candy Crush clone with our step-by-step guide.


How To Create Creating a Candy Crush Clone: HTML, CSS, and JavaScript Tutorial








Greetings, fellow game development enthusiasts! Welcome to the dynamic world of web development, where creating captivating games is an exhilarating fusion of creativity and technical prowess. In this comprehensive tutorial, we'll embark on an exciting voyage together to construct a Candy Crush clone from the ground up, harnessing the formidable capabilities of HTML, CSS, and JavaScript.


Harnessing the Potential of Web Technologies


Candy Crush, with its irresistible gameplay and vibrant aesthetics, has enraptured millions worldwide. Now, it's your turn to delve into the realm of game development and breathe life into your imaginative concepts. Whether you're a novice eager to grasp the fundamentals or a seasoned coder seeking a fresh challenge, this guide is tailored to accommodate all proficiency levels.


What Awaits You


Our tutorial will meticulously guide you through each phase, starting from crafting the foundational HTML structure to infusing interactive functionalities with JavaScript, and refining the visual allure using CSS.


So, equip yourself with your coding arsenal, unleash the depths of your creativity, and let's embark on this exhilarating odyssey of forging your very own Candy Crush clone. By the culmination of this journey, you'll not only possess a fully operational game but also a robust understanding of web game development principles. Let's script our triumph!

Source Code

Step 1 (HTML Code):

To get started, we will first need to create a basic HTML file. In this file, we will include the main structure for our game.


After creating the files just paste the following codes into your file. Make sure to save your HTML document with a .html extension, so that it can be properly viewed in a web browser.


Let's break down the code:


1. DOCTYPE HTML: This declaration specifies the document type and version of HTML being used. In this case, it indicates an HTML5 document.


2. HTML Root Element: This is the root element of the HTML document. The lang attribute is set to "en" (English), indicating the language of the document, and the dir attribute is set to "ltr" (left-to-right), indicating the text direction.


3. Head Section: This section contains meta-information about the document, such as setting the character encoding, title, linking external stylesheets, and scripts.


    - Charset Meta Tag: Sets the character encoding of the document to UTF-8.

    - Title Element: Sets the title of the web page, typically displayed in the browser's title bar or tab.

    - Stylesheet Links: Links to an external stylesheet named "style.css," which defines the presentation (styles) of the HTML document.

    - Google Fonts Link: Imports an external stylesheet from Google Fonts, importing the Montserrat font in weights 300 and 400 for use in the webpage.

    - Script Tag: Includes an external JavaScript file named "script.js," which contains the logic and functionality for the webpage.


4. Body Section: This section contains the main content of the HTML document.


5. Scoreboard Container: This element contains elements related to scoring in the game.


    - Score Heading: Contains the text "score" as a subheading.

    - Score Placeholder: Acts as a placeholder to display the actual score, which will be dynamically updated using JavaScript.


6. Grid Container: This element acts as a container for laying out the grid in the game, possibly for displaying candies in a Candy Crush-like game.


This is the basic structure of our Candy Crush clone using HTML, and now we can proceed to style it using CSS.

<!DOCTYPE html>
<html lang="en" dir="ltr">
  <head>
    <meta charset="utf-8">
    <title>JS Candy Crush</title>
    <link rel="stylesheet" href="style.css">
    <link href="https://fonts.googleapis.com/css?family=Montserrat:300,400&display=swap" rel="stylesheet">
    <script src="script.js" charset="utf-8"></script>
  </head>
  <body>
    <div class="scoreBoard">
      <h3>score</h3>
      <h1 id="score"></h1>
    </div>
    <div class="grid"></div>
  </body>
</html>

Step 2 (CSS Code):

Once the basic HTML structure of the clone game is in place, the next step is to add styling to the clone game using CSS.


Next, we will create our CSS file. In this file, we will use some basic CSS rules to style our clone game. Let's break down the code section by section:


1. Styling the Grid Container:

   - The grid container is styled to have a flexible layout using the `display: flex;` property.

   - It has a specified height, minimum width, margins, background color, padding, text color, border radius, and box shadow to enhance its appearance.


2. Styling the Grid Div Elements:

   - The div elements inside the grid container are styled to have a fixed height and width, creating uniform grid cells.


3. Styling Headings (h3 and h1):

   - Headings are styled with a specific font family and transformed to uppercase for consistency.


4. Styling the Body:

   - The body background image, maximum width, and display properties are defined.


5. Styling the Scoreboard:

   - The scoreboard container is styled with a specific background color, border radius, margins, dimensions, padding, and flex properties to arrange its content.


By creating a CSS file named `styles.css` and applying these styles, our Candy Crush clone game will have an improved visual presentation. Remember to link the CSS file to your HTML document for the styles to take effect.

.grid {
  display: flex;
  flex-wrap: wrap;
  height: 560px;
  min-width: 560px;
  margin-left: 80px;
  margin-top: 50px;
  background-color: rgba(109, 127, 151, 0.5);
  padding: 5px;
  color: #85796b;
  border-radius: 10px;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.5) inset, 0 1px 0 #fff;
}

.grid div {
  height: 70px;
  width: 70px;
}

h3 {
  font-family: "Montserrat", sans-serif;
  text-transform: uppercase;
}

h1 {
  font-family: "Montserrat", sans-serif;
  text-transform: uppercase;
  margin-top: -10px;
}

.invisible {
  background-color: white;
}

body {
  background-image: url('https://raw.githubusercontent.com/arpit456jain/Amazing-Js-Projects/master/Candy%20Crush/utils/bg.png');
  max-width: 100vh;
  display: flex;
}

.scoreBoard {
  background-color: cyan;
  border-radius: 20px;
  margin-top: 200px;
  margin-left: 200px;
  width: auto;
  height: 120px;
  padding: 20px;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  align-items: center;
  text-align: center;
  color: #85796b;
}

Step 3 (JavaScript Code):

Finally, we need to create a function in JavaScript. Let's break down the code into sections:


1. Initialization:

   - The code initializes by adding an event listener that waits for the DOM to be fully loaded before calling the `candyCrushGame` function.


2. candyCrushGame Function:

   - This function sets up the Candy Crush game by:

     - Creating the game board, typically an 8x8 grid, and filling it with candies of different colors represented by div elements.

     - Defining initial variables to store information about the candies being dragged, replaced, and the corresponding square IDs.

     - Adding event listeners to each candy div for drag-and-drop functionality, including events like `dragstart`, `dragend`, `dragover`, `dragenter`, `dragleave`, and `drop`.

     - Implementing functions like `dragDrop` to swap the background images of dragged and dropped candies, `dragEnd` to validate moves and update background images, and `moveIntoSquareBelow` to drop candies into empty squares below when candies are cleared.


3. Checking for Matches:

   - The code includes functions to check for matches in the game board. Matches can be in rows or columns of three or four candies.

   - Functions like `checkRowForFour`, `checkColumnForFour`, `checkRowForThree`, and `checkColumnForThree` iterate through the grid, identify matching candies, and remove them.

   - The score is updated based on the number of candies cleared.


4. Interval Function:

   - The `setInterval` function is used to repeatedly check for matches and move candies down every 100 milliseconds.


By creating a JavaScript file named `script.js` and applying these functions, our Candy Crush clone game will have the necessary functionality to handle drag-and-drop interactions, check for candy matches, and update the game board accordingly. Ensure that the JavaScript file is properly linked to your HTML document for the scripts to be executed.

document.addEventListener("DOMContentLoaded", () => {
    candyCrushGame();
});

function candyCrushGame() {
    const grid = document.querySelector(".grid");
    const scoreDisplay = document.getElementById("score");
    const width = 8;
    const squares = [];
    let score = 0;

    const candyColors = [
        "url(https://raw.githubusercontent.com/arpit456jain/Amazing-Js-Projects/master/Candy%20Crush/utils/red-candy.png)",
        "url(https://raw.githubusercontent.com/arpit456jain/Amazing-Js-Projects/master/Candy%20Crush/utils/blue-candy.png)",
        "url(https://raw.githubusercontent.com/arpit456jain/Amazing-Js-Projects/master/Candy%20Crush/utils/green-candy.png)",
        "url(https://raw.githubusercontent.com/arpit456jain/Amazing-Js-Projects/master/Candy%20Crush/utils/yellow-candy.png)",
        "url(https://raw.githubusercontent.com/arpit456jain/Amazing-Js-Projects/master/Candy%20Crush/utils/orange-candy.png)",
        "url(https://raw.githubusercontent.com/arpit456jain/Amazing-Js-Projects/master/Candy%20Crush/utils/purple-candy.png)",
    ];

    // Creating Game Board
    function createBoard() {
        for (let i = 0; i < width * width; i++) {
            const square = document.createElement("div");
            square.setAttribute("draggable", true);
            square.setAttribute("id", i);
            let randomColor = Math.floor(Math.random() * candyColors.length);
            square.style.backgroundImage = candyColors[randomColor];
            grid.appendChild(square);
            squares.push(square);
        }
    }
    createBoard();

    // Dragging the Candy
    let colorBeingDragged;
    let colorBeingReplaced;
    let squareIdBeingDragged;
    let squareIdBeingReplaced;

    squares.forEach((square) =>
        square.addEventListener("dragstart", dragStart)
    );
    squares.forEach((square) => square.addEventListener("dragend", dragEnd));
    squares.forEach((square) => square.addEventListener("dragover", dragOver));
    squares.forEach((square) =>
        square.addEventListener("dragenter", dragEnter)
    );
    squares.forEach((square) =>
        square.addEventListener("drageleave", dragLeave)
    );
    squares.forEach((square) => square.addEventListener("drop", dragDrop));

    function dragStart() {
        colorBeingDragged = this.style.backgroundImage;
        squareIdBeingDragged = parseInt(this.id);
        // this.style.backgroundImage = ''
    }

    function dragOver(e) {
        e.preventDefault();
    }

    function dragEnter(e) {
        e.preventDefault();
    }

    function dragLeave() {
        this.style.backgroundImage = "";
    }

    function dragDrop() {
        colorBeingReplaced = this.style.backgroundImage;
        squareIdBeingReplaced = parseInt(this.id);
        this.style.backgroundImage = colorBeingDragged;
        squares[
            squareIdBeingDragged
        ].style.backgroundImage = colorBeingReplaced;
    }

    function dragEnd() {
        //Defining, What is a valid move?
        let validMoves = [
            squareIdBeingDragged - 1,
            squareIdBeingDragged - width,
            squareIdBeingDragged + 1,
            squareIdBeingDragged + width
        ];
        let validMove = validMoves.includes(squareIdBeingReplaced);

        if (squareIdBeingReplaced && validMove) {
            squareIdBeingReplaced = null;
        } else if (squareIdBeingReplaced && !validMove) {
            squares[
                squareIdBeingReplaced
            ].style.backgroundImage = colorBeingReplaced;
            squares[
                squareIdBeingDragged
            ].style.backgroundImage = colorBeingDragged;
        } else
            squares[
                squareIdBeingDragged
            ].style.backgroundImage = colorBeingDragged;
    }

    //Dropping candies once some have been cleared
    function moveIntoSquareBelow() {
        for (i = 0; i < 55; i++) {
            if (squares[i + width].style.backgroundImage === "") {
                squares[i + width].style.backgroundImage =
                    squares[i].style.backgroundImage;
                squares[i].style.backgroundImage = "";
                const firstRow = [0, 1, 2, 3, 4, 5, 6, 7];
                const isFirstRow = firstRow.includes(i);
                if (isFirstRow && squares[i].style.backgroundImage === "") {
                    let randomColor = Math.floor(
                        Math.random() * candyColors.length
                    );
                    squares[i].style.backgroundImage = candyColors[randomColor];
                }
            }
        }
    }

    ///-> Checking for Matches <-///

    //For Row of Four
    function checkRowForFour() {
        for (i = 0; i < 60; i++) {
            let rowOfFour = [i, i + 1, i + 2, i + 3];
            let decidedColor = squares[i].style.backgroundImage;
            const isBlank = squares[i].style.backgroundImage === "";

            const notValid = [
                5,
                6,
                7,
                13,
                14,
                15,
                21,
                22,
                23,
                29,
                30,
                31,
                37,
                38,
                39,
                45,
                46,
                47,
                53,
                54,
                55
            ];
            if (notValid.includes(i)) continue;

            if (
                rowOfFour.every(
                    (index) =>
                        squares[index].style.backgroundImage === decidedColor &&
                        !isBlank
                )
            ) {
                score += 4;
                scoreDisplay.innerHTML = score;
                rowOfFour.forEach((index) => {
                    squares[index].style.backgroundImage = "";
                });
            }
        }
    }
    checkRowForFour();

    //For Column of Four
    function checkColumnForFour() {
        for (i = 0; i < 39; i++) {
            let columnOfFour = [i, i + width, i + width * 2, i + width * 3];
            let decidedColor = squares[i].style.backgroundImage;
            const isBlank = squares[i].style.backgroundImage === "";

            if (
                columnOfFour.every(
                    (index) =>
                        squares[index].style.backgroundImage === decidedColor &&
                        !isBlank
                )
            ) {
                score += 4;
                scoreDisplay.innerHTML = score;
                columnOfFour.forEach((index) => {
                    squares[index].style.backgroundImage = "";
                });
            }
        }
    }
    checkColumnForFour();

    //For Row of Three
    function checkRowForThree() {
        for (i = 0; i < 61; i++) {
            let rowOfThree = [i, i + 1, i + 2];
            let decidedColor = squares[i].style.backgroundImage;
            const isBlank = squares[i].style.backgroundImage === "";

            const notValid = [
                6,
                7,
                14,
                15,
                22,
                23,
                30,
                31,
                38,
                39,
                46,
                47,
                54,
                55
            ];
            if (notValid.includes(i)) continue;

            if (
                rowOfThree.every(
                    (index) =>
                        squares[index].style