Don't Step on the White Tile

JavaScriptJavaScriptBeginner
Practice Now

Introduction

This project guides you through creating a simple yet engaging web-based game titled "Don't Step on the White Tile." By following these steps, you'll learn to combine HTML, CSS, and JavaScript to build an interactive game where players must avoid stepping on white tiles to score points. This project is ideal for beginners looking to practice their web development skills.

👀 Preview

🎯 Tasks

In this project, you will learn:

  • How to set up a basic HTML structure to lay out your game's interface.
  • How to utilize CSS to style the game, making it visually appealing and user-friendly.
  • How to implement JavaScript to add dynamic functionalities such as moving tiles, scoring systems, and game logic.
  • How to handle user interactions through events like clicks, enhancing the game's interactivity.
  • How to manipulate the DOM to dynamically update the game's state, such as the score and game over conditions.
  • How to apply basic game development concepts like game loops, collision detection, and speed adjustments.

🏆 Achievements

After completing this project, you will be able to:

  • Demonstrate a solid understanding of how HTML, CSS, and JavaScript can be combined to create interactive web applications.
  • Apply practical experience in game development concepts such as animation, user input handling, and real-time updates.
  • Manipulate the DOM and handle events to create responsive web applications.
  • Improve your problem-solving skills through the implementation of game logic and handling edge cases like game over conditions.
  • Showcase your creativity in web design and game aesthetics, and explore further customizations and enhancements.
  • Take a foundational step towards more complex web development and game design projects, setting the stage for further learning and exploration in the field of web technologies.

Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL css(("`CSS`")) -.-> css/BasicConceptsGroup(["`Basic Concepts`"]) css(("`CSS`")) -.-> css/BasicStylingGroup(["`Basic Styling`"]) css(("`CSS`")) -.-> css/CoreLayoutGroup(["`Core Layout`"]) css(("`CSS`")) -.-> css/IntermediateStylingGroup(["`Intermediate Styling`"]) html(("`HTML`")) -.-> html/BasicStructureGroup(["`Basic Structure`"]) javascript(("`JavaScript`")) -.-> javascript/BasicConceptsGroup(["`Basic Concepts`"]) javascript(("`JavaScript`")) -.-> javascript/DOMManipulationGroup(["`DOM Manipulation`"]) javascript(("`JavaScript`")) -.-> javascript/ToolsandEnvironmentGroup(["`Tools and Environment`"]) css/BasicConceptsGroup -.-> css/selectors("`Selectors`") css/BasicStylingGroup -.-> css/colors("`Colors`") css/BasicStylingGroup -.-> css/text_styling("`Text Styling`") css/CoreLayoutGroup -.-> css/margin_and_padding("`Margin and Padding`") css/CoreLayoutGroup -.-> css/borders("`Borders`") css/CoreLayoutGroup -.-> css/width_and_height("`Width and Height`") css/CoreLayoutGroup -.-> css/positioning("`Positioning`") css/IntermediateStylingGroup -.-> css/backgrounds("`Backgrounds`") html/BasicStructureGroup -.-> html/basic_elems("`Basic Elements`") html/BasicStructureGroup -.-> html/head_elems("`Head Elements`") javascript/BasicConceptsGroup -.-> javascript/variables("`Variables`") javascript/BasicConceptsGroup -.-> javascript/data_types("`Data Types`") javascript/BasicConceptsGroup -.-> javascript/arith_ops("`Arithmetic Operators`") javascript/BasicConceptsGroup -.-> javascript/comp_ops("`Comparison Operators`") javascript/BasicConceptsGroup -.-> javascript/logic_ops("`Logical Operators`") javascript/BasicConceptsGroup -.-> javascript/cond_stmts("`Conditional Statements`") javascript/BasicConceptsGroup -.-> javascript/loops("`Loops`") javascript/BasicConceptsGroup -.-> javascript/functions("`Functions`") javascript/BasicConceptsGroup -.-> javascript/str_manip("`String Manipulation`") javascript/BasicConceptsGroup -.-> javascript/array_methods("`Array Methods`") javascript/BasicConceptsGroup -.-> javascript/obj_manip("`Object Manipulation`") javascript/DOMManipulationGroup -.-> javascript/dom_select("`DOM Selection`") javascript/DOMManipulationGroup -.-> javascript/dom_manip("`DOM Manipulation`") javascript/DOMManipulationGroup -.-> javascript/event_handle("`Event Handling`") javascript/ToolsandEnvironmentGroup -.-> javascript/bom("`Browser Object Model`") subgraph Lab Skills css/selectors -.-> lab-298977{{"`Don't Step on the White Tile`"}} css/colors -.-> lab-298977{{"`Don't Step on the White Tile`"}} css/text_styling -.-> lab-298977{{"`Don't Step on the White Tile`"}} css/margin_and_padding -.-> lab-298977{{"`Don't Step on the White Tile`"}} css/borders -.-> lab-298977{{"`Don't Step on the White Tile`"}} css/width_and_height -.-> lab-298977{{"`Don't Step on the White Tile`"}} css/positioning -.-> lab-298977{{"`Don't Step on the White Tile`"}} css/backgrounds -.-> lab-298977{{"`Don't Step on the White Tile`"}} html/basic_elems -.-> lab-298977{{"`Don't Step on the White Tile`"}} html/head_elems -.-> lab-298977{{"`Don't Step on the White Tile`"}} javascript/variables -.-> lab-298977{{"`Don't Step on the White Tile`"}} javascript/data_types -.-> lab-298977{{"`Don't Step on the White Tile`"}} javascript/arith_ops -.-> lab-298977{{"`Don't Step on the White Tile`"}} javascript/comp_ops -.-> lab-298977{{"`Don't Step on the White Tile`"}} javascript/logic_ops -.-> lab-298977{{"`Don't Step on the White Tile`"}} javascript/cond_stmts -.-> lab-298977{{"`Don't Step on the White Tile`"}} javascript/loops -.-> lab-298977{{"`Don't Step on the White Tile`"}} javascript/functions -.-> lab-298977{{"`Don't Step on the White Tile`"}} javascript/str_manip -.-> lab-298977{{"`Don't Step on the White Tile`"}} javascript/array_methods -.-> lab-298977{{"`Don't Step on the White Tile`"}} javascript/obj_manip -.-> lab-298977{{"`Don't Step on the White Tile`"}} javascript/dom_select -.-> lab-298977{{"`Don't Step on the White Tile`"}} javascript/dom_manip -.-> lab-298977{{"`Don't Step on the White Tile`"}} javascript/event_handle -.-> lab-298977{{"`Don't Step on the White Tile`"}} javascript/bom -.-> lab-298977{{"`Don't Step on the White Tile`"}} end

Setting Up the HTML Structure

Start by creating the basic HTML structure for the game in index.html. This includes the game's title, score display, main game area (#main), and the start button. The main game area will contain the moving rows of tiles.

<!doctype html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>Don't Step on the White Tile</title>
    <link rel="stylesheet" href="index.css" />
  </head>
  <body>
    <h2>Score</h2>
    <h2 id="score">0</h2>
    <div id="main">
      <div id="con"></div>
    </div>
    <div class="btn">
      <button class="start" onclick="start()">Start Game</button>
    </div>
    <script src="index.js"></script>
  </body>
</html>

In this step, you've established the foundational HTML structure for the game. The structure includes a title for the game, a display for the score, a main game area identified by #main for the moving tiles, and a start button to begin the game. The #main area will later be populated with rows of tiles that players will interact with during the game. This setup is crucial as it lays out the skeleton of the game, onto which CSS and JavaScript will add style and functionality.

Crafting the CSS Styles

Define the CSS styles to visually structure the game in index.css. This step involves styling the main game container, the individual tiles (cells), and the start button to make the game visually appealing.

#main {
  width: 408px;
  height: 408px;
  background: white;
  border: 2px solid gray;
  margin: 0 auto;
  overflow: hidden;
}

h2 {
  text-align: center;
}

#con {
  width: 100%;
  height: 400px;
  position: relative;
  top: -408px;
  border-collapse: collapse;
}

.row {
  height: 100px;
  width: 100%;
}

.cell {
  height: 100px;
  width: 100px;
  float: left;
  border: rgb(54, 74, 129) 1px solid;
}

.black {
  background: black;
}

.btn {
  width: 100%;
  text-align: center;
}

.start {
  margin: 20px auto;
  width: 150px;
  height: 50px;
  border-radius: 10px;
  background: yellowgreen;
  line-height: 50px;
  color: #fff;
}

You've defined the CSS styles that determine the visual aspects of the game. The styles include the layout of the main game area, the appearance of the tiles (or cells), and the styling of the start button. By setting these styles, you've made the game visually appealing and defined the user interface elements that players will interact with, such as the game board and the start button. These styles are essential for making the game engaging and accessible to players.

Game Initialization

In this step, you'll start writing the JavaScript required to bring your game to life in index.js. Begin by creating the start and init functions to initialize the game and dynamically create the initial set of rows for the game area.

// Helper function to get element by ID
function $(id) {
  return document.getElementById(id);
}

// Function to create a div with a given class name
function createDiv(className) {
  var div = document.createElement("div");
  div.className = className;
  return div;
}

var gameStarted = false;

// Function to start the game
function start() {
  if (!gameStarted) {
    init();
  } else {
    alert("The game has already started, no need to click again!");
  }
}

// Initialize the game
function init() {
  gameStarted = true;
  for (var i = 0; i < 4; i++) {
    createRow();
  }
}

At this stage, you've begun to breathe life into the game with JavaScript. The code you've written initializes the game and sets up the mechanics for creating the initial rows of tiles. This includes defining helper functions for DOM manipulation, setting a flag to prevent multiple game starts, and laying out the foundation for dynamically adding rows to the game area. This step is critical as it sets up the game's dynamic elements, preparing for the interactive part of the game where tiles move, and players can start to engage with the game.

Handling Row Movement and Game Over Check

Extend the JavaScript functionality to include moving the rows downwards and checking if the game is over. This involves creating a game loop that updates the position of the rows and checks if any row has passed the allowed boundary without being 'stepped' on.

// Continue in index.js

var speed = 6; // Initial speed of the moving rows
var clock = null;

// Move the rows down
function move() {
  var con = $("con");
  var top = parseInt(window.getComputedStyle(con, null)["top"]);
  if (speed + top > 0) {
    top = 0;
  } else {
    top += speed;
  }
  con.style.top = top + "px";
  checkGameOver();
  if (top == 0) {
    createRow();
    con.style.top = "-102px";
    deleteRow();
  }
}

// Check if the game is over
function checkGameOver() {
  var con = $("con");
  var rows = con.childNodes;
  var conTop = parseInt(window.getComputedStyle(con, null)["top"]);
  var conHeight = con.offsetHeight;
  for (var i = 0; i < rows.length; i++) {
    var row = rows[i];
    var rowTop = conTop + i * row.offsetHeight;
    if (rowTop >= conHeight && row.passed !== 1) {
      fail();
      break;
    }
  }
}

Here, you've expanded the game's functionality by adding the logic for moving rows downwards and checking for game over conditions. The move function updates the position of the rows, simulating the movement of tiles that players need to avoid stepping on. The checkGameOver function monitors if any row has passed the bottom of the game area without being 'stepped' on, which would end the game. This step introduces the main gameplay mechanic and challenge, making the game interactive and engaging.

Implementing Scoring and Speed Increase

In this step, focus on implementing the game's scoring mechanism and increasing the speed of the rows as the player's score increases. This adds a level of challenge to the game, keeping it engaging.

// Continue in index.js

// Update the score
function score() {
  var newScore = parseInt($("score").innerHTML) + 1;
  $("score").innerHTML = newScore;
  if (newScore % 10 == 0) {
    speedUp();
  }
}

// Increase the speed of the moving rows
function speedUp() {
  speed += 2;
  if (speed == 20) {
    alert("Incredible speed!");
  }
}

In this step, you've implemented the game's scoring system and added a feature to increase the speed of moving rows as the player's score increases. This not only provides feedback to the player about their performance but also progressively increases the game's difficulty. The scoring mechanism rewards players for successfully avoiding the white tiles, and the increasing speed challenges the player's reaction times, making the game more engaging and competitive.

Handling User Interactions

Implement the logic to handle user clicks on the tiles. Players should score when clicking on black tiles and lose when clicking on white tiles.

// Continue in index.js

// Judge the player's action
function judge(ev) {
  ev = ev || event;
  if (ev.target.className.indexOf("black") !== -1) {
    ev.target.className = "cell";
    ev.target.parentNode.passed = 1;
    score();
  } else if (ev.target.className.indexOf("cell") !== -1) {
    fail();
  }
}

In this step, you've implemented the judge function to handle user clicks within the game. When a player clicks on a tile, the function determines if the tile is black or not. If the tile is black (correct move), it turns to a regular cell, and the score is updated. If the tile is not black (incorrect move), it triggers the game over sequence. This function is crucial for the game's interactivity, allowing players to interact with the game by clicking on tiles and receiving immediate feedback on their actions.

Creating and Deleting Rows

Develop functions to dynamically create new rows of tiles and delete the oldest row when it's no longer visible to keep the game running smoothly.

// Continue in index.js

// Randomly assign the black cell in a row
function createCell() {
  var temp = ["cell", "cell", "cell", "cell"];
  var i = Math.floor(Math.random() * 4);
  temp[i] = "cell black";
  return temp;
}

// Create a new row of tiles
function createRow() {
  var con = $("con");
  var row = createDiv("row");
  var arr = createCell();
  for (var i = 0; i < 4; i++) {
    row.appendChild(createDiv(arr[i]));
  }
  if (con.firstChild == null) {
    con.appendChild(row);
  } else {
    con.insertBefore(row, con.firstChild);
  }
}

// Delete the last row if there are more than 5 rows
function deleteRow() {
  var con = $("con");
  if (con.childNodes.length == 6) {
    con.removeChild(con.lastChild);
  }
}

You've added the createRow function to dynamically generate rows of tiles with one black tile in a random position, enhancing the game's unpredictability and challenge. The deleteRow function removes the oldest row that's no longer visible, optimizing the game's performance and ensuring that the game area doesn't overflow with unused elements. These functions work together to maintain a continuous flow of tiles for the player to interact with.

Implementing the Game Over Logic

Define the conditions under which the game will end, such as clicking on a white tile or missing a black tile. Display the player's final score and offer an option to restart the game.

// Continue in index.js

// End the game
function fail() {
  clearInterval(clock);
  gameStarted = false;
  confirm("Your final score is " + parseInt($("score").innerHTML));
  window.location.reload();
}

By defining the fail function, you've established the conditions under which the game ends. This function is called when the player makes an incorrect move or misses a black tile. It stops the game loop, displays the player's final score, and reloads the page for a fresh start. This step is vital for providing a complete game experience, including the challenge of avoiding mistakes and the finality of the game ending.

Starting the Game Loop

Set up the main game loop that keeps the tiles moving down the screen. Adjust the speed of movement based on the player's score to increase difficulty.

// Continue in index.js

// Start the game loop
function start() {
  if (!gameStarted) {
    init();
    clock = setInterval("move()", 30);
  }
}

You've set up the main game loop with the move function, which continuously moves the rows down the screen, simulating the game's progression. The speed of movement increases as the player's score rises, adding to the game's difficulty. This loop is the heartbeat of the game, driving the gameplay and challenging the player to keep up with the increasing pace.

Adding Event Listener

Attach event listener to the game area to detect and respond to player actions, such as clicking on tiles.

// Continue in index.js

// Add event listener for the main game container
$("main").onclick = function (ev) {
  judge(ev);
};

In this step, you've attached an event listener to the main game area, enabling it to respond to player clicks. This functionality is essential for capturing user interactions, allowing the game to process player moves and update the game state accordingly. It's what makes the game interactive and responsive to player actions.

To see the following effects, click on Go Live button in the bottom right corner of WebIDE, and switch to the "Web 8080" tab.

Summary

By completing this project, you have created a functional web-based game titled "Don't Step on the White Tile." This project not only enhances your understanding of how HTML, CSS, and JavaScript work together to create interactive web content but also provides a foundation for creating more complex web-based games in the future. Experiment with different styles, features, and functionalities to make the game uniquely yours. Happy coding!

Other JavaScript Tutorials you may like