Hey everyone. Welcome to today’s tutorial. In today’s tutorial, we will learn how to create a flags game. To build this project, you will need HTML, CSS and Javascript.
This is an intermediate-level javascript project. If you are looking for more projects to improve your javascript skills, you can check out this playlist here. This playlist consists of more than 100+ javascript projects. The difficulty of these projects varies from easy to quite complex.
Let us take a look at how this project works. We begin the game with a start screen. When the user clicks on the ‘Start Game’ button, we present the user with three random flag images.
Along with the flag images, we also provide empty boxes with corresponding country names. These boxes are placed in random order. To win this game, the user has to drag the flag images and drop them over the corresponding country-name box.
When all the three flags are in their right place, we display the win screen. The win screen consists of a ‘You Won’ message and a ‘Start Button.
Video Tutorial:
If you are interested to learn by watching a video tutorial rather than reading this blog post, you can watch the video down below. Also subscribe to my youtube channel where I post new tips, tricks and tutorials every alternate day.
Project Folder Structure:
Before we start coding let us take a look at the project folder structure. We create a project folder called – ‘Flags Game’. Inside this folder, we have three files. These files are – index.html, style.css and script.js. The first file is the HTML document, the next is the stylesheet and finally, we have the script file.
HTML:
We begin with the HTML code. First, copy the code below and paste it into your HTML document.
<!DOCTYPE html> <html lang="en"> <head> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Flags Game</title> <!-- Google Fonts --> <link href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;600&display=swap" rel="stylesheet" /> <!-- Stylesheet --> <link rel="stylesheet" href="style.css" /> </head> <body> <div class="container"> <h3>Drag & Drop The Flags Over Their Respective Country Names</h3> <div class="draggable-objects"></div> <div class="drop-points"></div> </div> <div class="controls-container"> <p id="result"></p> <button id="start">Start Game</button> </div> <!-- Script --> <script src="script.js"></script> </body> </html>
CSS:
Next, we style our project with CSS. For this copy, the code provided to you below and paste it into your stylesheet.
* { padding: 0; margin: 0; box-sizing: border-box; font-family: "Poppins", sans-serif; } body { background-color: #5372ef; } .container { width: 90%; max-width: 37.5em; background-color: #ffffff; padding: 3em 0.5em; position: absolute; transform: translate(-50%, -50%); top: 50%; left: 50%; border-radius: 0.8em; } h3 { text-align: center; width: 60%; margin: 0 auto 2em auto; font-size: 1.2em; font-weight: 600; letter-spacing: 0.03em; line-height: 1.8em; color: #010c39; } .draggable-objects, .drop-points { display: flex; justify-content: space-around; padding: 2em; } .draggable-image { width: 8em; cursor: move; } img { width: 8em; filter: drop-shadow(0 0.3em 0.9em rgba(0, 0, 0, 0.25)); } .countries { width: 10em; height: 8em; display: grid; place-items: center; border: 0.25em dashed #010c39; border-radius: 0.8em; } .dropped { padding: 0; background-color: #e5ffc8; } .controls-container { position: absolute; display: flex; align-items: center; justify-content: center; height: 100%; width: 100%; background-color: #5372ef; flex-direction: column; top: 0; } .controls-container button { font-size: 1.12em; padding: 0.8em 1em; border-radius: 0.2em; border: none; outline: none; color: #010c39; letter-spacing: 0.06em; cursor: pointer; } .controls-container p { color: #ffffff; font-size: 2em; margin-bottom: 1em; } .hide { display: none; }
Javascript:
Finally, we add functionality using Javascript. For this copy the code below and paste it into your script file.
//Initial References let draggableObjects; let dropPoints; const startButton = document.getElementById("start"); const result = document.getElementById("result"); const controls = document.querySelector(".controls-container"); const dragContainer = document.querySelector(".draggable-objects"); const dropContainer = document.querySelector(".drop-points"); const data = [ "belgium", "bhutan", "brazil", "china", "cuba", "ecuador", "georgia", "germany", "hong-kong", "india", "iran", "myanmar", "norway", "spain", "sri-lanka", "sweden", "switzerland", "united-states", "uruguay", "wales", ]; let deviceType = ""; let initialX = 0, initialY = 0; let currentElement = ""; let moveElement = false; //Detect touch device const isTouchDevice = () => { try { //We try to create Touch Event (It would fail for desktops and throw error) document.createEvent("TouchEvent"); deviceType = "touch"; return true; } catch (e) { deviceType = "mouse"; return false; } }; let count = 0; //Random value from Array const randomValueGenerator = () => { return data[Math.floor(Math.random() * data.length)]; }; //Win Game Display const stopGame = () => { controls.classList.remove("hide"); startButton.classList.remove("hide"); }; //Drag & Drop Functions function dragStart(e) { if (isTouchDevice()) { initialX = e.touches[0].clientX; initialY = e.touches[0].clientY; //Start movement for touch moveElement = true; currentElement = e.target; } else { //For non touch devices set data to be transfered e.dataTransfer.setData("text", e.target.id); } } //Events fired on the drop target function dragOver(e) { e.preventDefault(); } //For touchscreen movement const touchMove = (e) => { if (moveElement) { e.preventDefault(); let newX = e.touches[0].clientX; let newY = e.touches[0].clientY; let currentSelectedElement = document.getElementById(e.target.id); currentSelectedElement.parentElement.style.top = currentSelectedElement.parentElement.offsetTop - (initialY - newY) + "px"; currentSelectedElement.parentElement.style.left = currentSelectedElement.parentElement.offsetLeft - (initialX - newX) + "px"; initialX = newX; initialY - newY; } }; const drop = (e) => { e.preventDefault(); //For touch screen if (isTouchDevice()) { moveElement = false; //Select country name div using the custom attribute const currentDrop = document.querySelector(`div[data-id='${e.target.id}']`); //Get boundaries of div const currentDropBound = currentDrop.getBoundingClientRect(); //if the position of flag falls inside the bounds of the countru name if ( initialX >= currentDropBound.left && initialX <= currentDropBound.right && initialY >= currentDropBound.top && initialY <= currentDropBound.bottom ) { currentDrop.classList.add("dropped"); //hide actual image currentElement.classList.add("hide"); currentDrop.innerHTML = ``; //Insert new img element currentDrop.insertAdjacentHTML( "afterbegin", `<img src= "${currentElement.id}.png">` ); count += 1; } } else { //Access data const draggedElementData = e.dataTransfer.getData("text"); //Get custom attribute value const droppableElementData = e.target.getAttribute("data-id"); if (draggedElementData === droppableElementData) { const draggedElement = document.getElementById(draggedElementData); //dropped class e.target.classList.add("dropped"); //hide current img draggedElement.classList.add("hide"); //draggable set to false draggedElement.setAttribute("draggable", "false"); e.target.innerHTML = ``; //insert new img e.target.insertAdjacentHTML( "afterbegin", `<img src="${draggedElementData}.png">` ); count += 1; } } //Win if (count == 3) { result.innerText = `You Won!`; stopGame(); } }; //Creates flags and countries const creator = () => { dragContainer.innerHTML = ""; dropContainer.innerHTML = ""; let randomData = []; //for string random values in array for (let i = 1; i <= 3; i++) { let randomValue = randomValueGenerator(); if (!randomData.includes(randomValue)) { randomData.push(randomValue); } else { //If value already exists then decrement i by 1 i -= 1; } } for (let i of randomData) { const flagDiv = document.createElement("div"); flagDiv.classList.add("draggable-image"); flagDiv.setAttribute("draggable", true); if (isTouchDevice()) { flagDiv.style.position = "absolute"; } flagDiv.innerHTML = `<img src="${i}.png" id="${i}">`; dragContainer.appendChild(flagDiv); } //Sort the array randomly before creating country divs randomData = randomData.sort(() => 0.5 - Math.random()); for (let i of randomData) { const countryDiv = document.createElement("div"); countryDiv.innerHTML = `<div class='countries' data-id='${i}'> ${i.charAt(0).toUpperCase() + i.slice(1).replace("-", " ")} </div> `; dropContainer.appendChild(countryDiv); } }; //Start Game startButton.addEventListener( "click", (startGame = async () => { currentElement = ""; controls.classList.add("hide"); startButton.classList.add("hide"); //This will wait for creator to create the images and then move forward await creator(); count = 0; dropPoints = document.querySelectorAll(".countries"); draggableObjects = document.querySelectorAll(".draggable-image"); //Events draggableObjects.forEach((element) => { element.addEventListener("dragstart", dragStart); //for touch screen element.addEventListener("touchstart", dragStart); element.addEventListener("touchend", drop); element.addEventListener("touchmove", touchMove); }); dropPoints.forEach((element) => { element.addEventListener("dragover", dragOver); element.addEventListener("drop", drop); }); }) );
That’s it for this tutorial. If you face any issues while creating this project you can download the source code by clicking on the ‘Download Code’ button below. Also, I would love to hear from you guys. So if you have any queries, suggestions or feedback you can comment below.
Happy Coding!