Learn how to create your own 2048 game online using HTML, CSS, and JavaScript. Follow our step-by-step tutorial and get hands-on with game development. Source code included.
Table of Contents
The 2048 game is an addictive puzzle game that has gained immense popularity among puzzle enthusiasts and casual gamers. The objective of the game is to combine numbered tiles on a grid to create a tile with a value of 2048. The game is played on a 4x4 grid, but variations with different grid sizes also exist.
The game starts with two tiles, each with a value of either 2 or 4, randomly placed on the grid. The player can move the tiles in four directions: up, down, left, and right. When the player moves the tiles, all the tiles on the grid slide in that direction, with empty spaces being filled by new tiles appearing with a value of 2 or 4.
When two tiles with the same value collide while moving, they merge into a single tile with their values added together. For example, if two tiles with a value of 2 collide, they merge into a single tile with a value of 4. The player's goal is to strategically move the tiles to combine them and create higher-value tiles. The game is won when a tile with a value of 2048 is created, although it is possible to continue playing and achieve higher scores.
However, the game becomes more challenging as the grid fills up with tiles and there are fewer empty spaces to maneuver. The player needs to plan their moves carefully to avoid filling up the grid completely and not being able to make any valid moves. The game ends when there are no more possible moves available, and the player's final score is determined by the total value of the merged tiles on the grid.
The simplicity of the game's rules, coupled with the strategic thinking required to achieve high scores, has made 2048 a highly addictive and engaging puzzle game. It has captivated players of all ages and has become a popular choice for both casual gaming and brain training. In this tutorial, we will guide you through the process of creating your own version of the 2048 game using HTML, CSS, and JavaScript, allowing you to experience the thrill of game development while honing your web development skills.
Let's start making an amazing 2048 game using HTML, CSS, and JavaScript step by step.
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 2048 game.
After creating the files just paste the following below codes into your file. Make sure to save your HTML document with a .html extension to properly view it in a web browser.
Let's go through it step by step:
<!DOCTYPE html>: This is the document type declaration. It informs the web browser that the document is an HTML5 document.
<html lang="en" dir="ltr">: This is the opening tag of the HTML document. It defines the root element of the HTML page. The lang attribute specifies the language of the document (English in this case), and the dir attribute defines the text direction (left to right).
<head>: This is the head section of the HTML document. It contains meta-information about the web page, such as the character encoding, title, stylesheets, and scripts.
<meta charset="utf-8">: This meta tag specifies the character encoding for the document. UTF-8 is a widely used character encoding that supports a wide range of characters.
<title>2048 Game Online</title>: This is the title of the web page. It is displayed on the browser's title bar or tab.
<link rel="stylesheet" href="styles.css">: This line links an external CSS (Cascading Style Sheets) file named "styles.css" to the HTML document. The CSS file is used to define the visual presentation and layout of the web page.
<script src="script.js" charset="utf-8"></script>: This line includes an external JavaScript file named "script.js" into the HTML document. The JavaScript file contains code that can be executed by the web browser to add interactivity and functionality to the web page.
<body>: This is the body section of the HTML document. It contains the visible content of the web page.
<div class="container">: This is a div element with the class "container". It acts as a wrapper for the entire content of the web page.
<div class="info">: This is a div element with the class "info". It represents an informational section.
<h1>2048</h1>: This is a heading element (h1) that displays the text "2048". It represents the title or heading of the web page.
<div class="score-container">: This is a div element with the class "score-container". It contains the score information.
<div class="score-title">score</div>: This is a div element with the class "score-title". It displays the text "score" as a label for the score.
<span id="score">0</span>: This is a span element with the id "score". It displays the current score value, which is initially set to 0.
<span id="result">Join the numbers and get to the <b>2048</b> tile!</span>: This is a span element with the id "result". It displays a message instructing the user to join numbers and reach the 2048 tile. The <b> tag is used to make the number "2048" bold.
<div class="grid"></div>: This is a div element with the class "grid". It represents a grid or game board where the gameplay of the 2048 game will take place.
</body>: This is the closing tag for the body section.
</html>: This is the closing tag for the HTML document.
This is the basic structure of our 2048 game using HTML, and now we can move on to styling it using CSS.
Step 2 (CSS Code):
Once the basic HTML structure of the game is in place, the next step is to add styling to the game using CSS.
Next, we will create our CSS file. In this file, we will use some basic CSS rules to create our game.
Let's break down the code:
The first part, body { ... }, is defining the styles for the entire web page. It sets the background color to a light beige (#faf8ef) and sets some other properties like the font family, which determines the type of text used.
The next part, h1 { ... }, specifies the styles for the heading element (<h1>). It sets the font size to 80 pixels, makes the text color a dark brownish-gray (#776E65), and removes any margin (spacing) around the heading.
The .container { ... } section is defining styles for an element with the class "container." It sets the width of the container to 468 pixels and adds a small margin at the top.
The .info { ... } part defines styles for an element with the class "info." It arranges the content inside this element to be evenly spaced with some margin at the bottom.
The .grid { ... } section sets styles for an element with the class "grid." It arranges the content inside this element in a grid-like layout. The grid has a width and height of 456 pixels, a background color of light brown (#BBADA0), and a border with the same color. It also has rounded corners and a margin at the top.
The .grid div { ... } part specifies styles for the individual cells inside the grid. Each cell has a width and height of 100 pixels, a small margin, rounded corners, and a background color of light beige (#EEE4DA). The text inside the cells is a light grayish-brown color (#afa192) and is bold and centered. The font size is 60 pixels, and the line height determines the spacing between lines of text.
The .score-container { ... } section sets styles for an element with the class "score-container." It defines a text container with a width of 70 pixels and a height of 60 pixels. The container has rounded corners and a background color of a dark brownish-gray (#8f7a66). The text inside this container is white (#FFFFFF).
The #score { ... } part specifies styles for an element with the ID "score." It sets the font size to 30 pixels.
Lastly, the .score-title { ... } section defines styles for an element with the class "score-title." It sets the font size to 16 pixels.
This will give our 2048 game an upgraded presentation. Create a CSS file with the name of styles.css and paste the given codes into your CSS file. Remember that you must create a file with the .css extension.
body {
background-color: #faf8ef;
display: flex;
justify-content: center;
font-family: "Clear Sans", "Helvetica Neue";
}
h1 {
font-size: 80px;
line-height: 0.7;
color: #776E65;
margin: 0px;
}
.container {
width: 468px;
margin-top: 10px;
}
.info {
display: flex;
justify-content: space-between;
margin-bottom: 20px;
}
.grid{
display: flex;
flex-wrap: wrap;
width: 456px;
height: 456px;
background-color: #BBADA0;
border: 7px solid #BBADA0;
border-radius: 6px;
margin-top: 20px;
}
.grid div {
width: 100px;
height: 100px;
margin: 7px;
border-radius: 3px;
background-color: #EEE4DA;
color: #afa192;
font-weight: bold;
text-align: center;
font-size: 60px;
line-height: 1.6;
}
.score-container {
text-align: center;
width: 70px;
height: 60px;
border-radius: 3px;
background-color: #8f7a66;
color: #FFFFFF;
}
#score {
font-size: 30px;
}
.score-title {
font-size: 16px;
}
Step 3 (JavaScript Code):
Finally, we need to implement game logic using JavaScript.
Let's go through the code and understand its structure and functionality.
The code starts with an event listener that waits for the DOM (Document Object Model) to be fully loaded and ready. Once the DOM is ready, the code executes the callback function, which contains the main logic of the game.
The code declares several variables, including gridDisplay, scoreDisplay, and resultDisplay, which store references to HTML elements in the game interface. The squares variable is an array that will hold references to individual grid cells. The width variable is set to 4, indicating the size of the game grid. The score variable keeps track of the player's score.
The createBoard function is responsible for generating the initial game board. It loops through the grid cells, creates a
The generate function generates a new number (either 2 or 4) in a random empty cell on the board. It uses Math.random() to get a random index within the squares array and checks if the corresponding cell is empty (i.e., its innerHTML is 0). If it's empty, it sets the cell's value to 2 and calls the checkForGameOver function. Otherwise, it recursively calls itself to find another empty cell.
Next, there are four functions: moveRight, moveLeft, moveUp, and moveDown. These functions handle the movement of numbers on the game board. They are similar in structure but differ in the direction of movement. For example, moveRight combines numbers in each row by merging adjacent cells with the same value and moving them to the right. It uses an array representation of each row, filters out the zeros, adds zeros to the beginning or end of the row as needed, and then updates the corresponding cells in the grid.
The combineRow and combineColumn functions handle the merging of adjacent cells with the same value. They iterate through each row or column and check if the current cell's value is equal to the next cell's value. If they are equal, the cells are combined by adding their values and updating the score.
The control function is an event handler for key presses. It listens for keyup events and calls the corresponding movement functions based on the pressed key: arrow left (keyCode === 37), arrow up (keyCode === 38), arrow right (keyCode === 39), or arrow down (keyCode === 40).
The code attaches the control function as an event listener to the keyup event on the document object, allowing the player to control the game using arrow keys.
The keyRight, keyLeft, keyUp, and keyDown functions are invoked by the control function based on the pressed key, and they handle the movement and merging of cells accordingly.
The checkForWin function checks if any cell on the board contains the value 2048, indicating that the player has won the game. If such a cell is found, it displays a "You WIN" message, removes the event listener for keyup events, and sets a timeout to call the clear function after 3 seconds.
The checkForGameOver function checks if there are any empty cells remaining on the board. If all cells are filled and no more moves are possible, it displays a "You LOSE" message, removes the event listener for keyup events, and sets a timeout to call the clear function after 3 seconds.
The clear function clears the interval timer that was set earlier to periodically update the colors of the grid cells.
The addColours function assigns colors to the grid cells based on their values. It loops through each cell and applies a specific background color based on the cell's value. The colors are defined using CSS color codes.
After defining the addColours function, it is invoked immediately to apply the initial colors to the grid cells. Then, a timer interval is set using setInterval to call the addColours function every 50 milliseconds, which updates the colors of the grid cells periodically.
Finally, outside the event listener callback function, the code adds an event listener for the keyup event on the document object and calls the control function to enable keyboard controls for the game.
Create a JavaScript file with the name of script.js and paste the given codes into your JavaScript file and make sure it's linked properly to your HTML document, so that the scripts are executed on the page. Remember, you’ve to create a file with .js extension.
document.addEventListener('DOMContentLoaded', () => {
const gridDisplay = document.querySelector('.grid')
const scoreDisplay = document.getElementById('score')
const resultDisplay = document.getElementById('result')
let squares = []
const width = 4
let score = 0
//create the playing board
function createBoard() {
for (let i=0; i < width*width; i++) {
square = document.createElement('div')
square.innerHTML = 0
gridDisplay.appendChild(square)
squares.push(square)
}
generate()
generate()
}
createBoard()
//generate a new number
function generate() {
randomNumber = Math.floor(Math.random() * squares.length)
if (squares[randomNumber].innerHTML == 0) {
squares[randomNumber].innerHTML = 2
checkForGameOver()
} else generate()
}
function moveRight() {
for (let i=0; i < 16; i++) {
if (i % 4 === 0) {
let totalOne = squares[i].innerHTML
let totalTwo = squares[i+1].innerHTML
let totalThree = squares[i+2].innerHTML
let totalFour = squares[i+3].innerHTML
let row = [parseInt(totalOne), parseInt(totalTwo), parseInt(totalThree), parseInt(totalFour)]
let filteredRow = row.filter(num => num)
let missing = 4 - filteredRow.length
let zeros = Array(missing).fill(0)
let newRow = zeros.concat(filteredRow)
squares[i].innerHTML = newRow[0]
squares[i +1].innerHTML = newRow[1]
squares[i +2].innerHTML = newRow[2]
squares[i +3].innerHTML = newRow[3]
}
}
}
function moveLeft() {
for (let i=0; i < 16; i++) {
if (i % 4 === 0) {
let totalOne = squares[i].innerHTML
let totalTwo = squares[i+1].innerHTML
let totalThree = squares[i+2].innerHTML
let totalFour = squares[i+3].innerHTML
let row = [parseInt(totalOne), parseInt(totalTwo), parseInt(totalThree), parseInt(totalFour)]
let filteredRow = row.filter(num => num)
let missing = 4 - filteredRow.length
let zeros = Array(missing).fill(0)
let newRow = filteredRow.concat(zeros)
squares[i].innerHTML = newRow[0]
squares[i +1].innerHTML = newRow[1]
squares[i +2].innerHTML = newRow[2]
squares[i +3].innerHTML = newRow[3]
}
}
}
function moveUp() {
for (let i=0; i < 4; i++) {
let totalOne = squares[i].innerHTML
let totalTwo = squares[i+width].innerHTML
let totalThree = squares[i+(width*2)].innerHTML
let totalFour = squares[i+(width*3)].innerHTML
let column = [parseInt(totalOne), parseInt(totalTwo), parseInt(totalThree), parseInt(totalFour)]
let filteredColumn = column.filter(num => num)
let missing = 4 - filteredColumn.length
let zeros = Array(missing).fill(0)
let newColumn = filteredColumn.concat(zeros)
squares[i].innerHTML = newColumn[0]
squares[i +width].innerHTML = newColumn[1]
squares[i+(width*2)].innerHTML = newColumn[2]
squares[i+(width*3)].innerHTML = newColumn[3]
}
}
function moveDown() {
for (let i=0; i < 4; i++) {
let totalOne = squares[i].innerHTML
let totalTwo = squares[i+width].innerHTML
let totalThree = squares[i+(width*2)].innerHTML
let totalFour = squares[i+(width*3)].innerHTML
let column = [parseInt(totalOne), parseInt(totalTwo), parseInt(totalThree), parseInt(totalFour)]
let filteredColumn = column.filter(num => num)
let missing = 4 - filteredColumn.length
let zeros = Array(missing).fill(0)
let newColumn = zeros.concat(filteredColumn)
squares[i].innerHTML = newColumn[0]
squares[i +width].innerHTML = newColumn[1]
squares[i+(width*2)].innerHTML = newColumn[2]
squares[i+(width*3)].innerHTML = newColumn[3]
}
}
function combineRow() {
for (let i =0; i < 15; i++) {
if (squares[i].innerHTML === squares[i +1].innerHTML) {
let combinedTotal = parseInt(squares[i].innerHTML) + parseInt(squares[i +1].innerHTML)
squares[i].innerHTML = combinedTotal
squares[i +1].innerHTML = 0
score += combinedTotal
scoreDisplay.innerHTML = score
}
}
checkForWin()
}
function combineColumn() {
for (let i =0; i < 12; i++) {
if (squares[i].innerHTML === squares[i +width].innerHTML) {
let combinedTotal = parseInt(squares[i].innerHTML) + parseInt(squares[i +width].innerHTML)
squares[i].innerHTML = combinedTotal
squares[i +width].innerHTML = 0
score += combinedTotal
scoreDisplay.innerHTML = score
}
}
checkForWin()
}
//assign functions to keyCodes
function control(e) {
if(e.keyCode === 37) {
keyLeft()
} else if (e.keyCode === 38) {
keyUp()
} else if (e.keyCode === 39) {
keyRight()
} else if (e.keyCode === 40) {
keyDown()
}
}
document.addEventListener('keyup', control)
function keyRight() {
moveRight()
combineRow()
moveRight()
generate()
}
function keyLeft() {
moveLeft()
combineRow()
moveLeft()
generate()
}
function keyUp() {
moveUp()
combineColumn()
moveUp()
generate()
}
function keyDown() {
moveDown()
combineColumn()
moveDown()
generate()
}
//check for the number 2048 in the squares to win
function checkForWin() {
for (let i=0; i < squares.length; i++) {
if (squares[i].innerHTML == 2048) {
resultDisplay.innerHTML = 'You WIN'
document.removeEventListener('keyup', control)
setTimeout(() => clear(), 3000)
}
}
}
//check if there are no zeros on the board to lose
function checkForGameOver() {
let zeros = 0
for (let i=0; i < squares.length; i++) {
if (squares[i].innerHTML == 0) {
zeros++
}
}
if (zeros === 0) {
resultDisplay.innerHTML = 'You LOSE'
document.removeEventListener('keyup', control)
setTimeout(() => clear(), 3000)
}
}
//clear timer
function clear() {
clearInterval(myTimer)
}
//add colours
function addColours() {
for (let i=0; i < squares.length; i++) {
if (squares[i].innerHTML == 0) squares[i].style.backgroundColor = '#afa192'
else if (squares[i].innerHTML == 2) squares[i].style.backgroundColor = '#eee4da'
else if (squares[i].innerHTML == 4) squares[i].style.backgroundColor = '#ede0c8'
else if (squares[i].innerHTML == 8) squares[i].style.backgroundColor = '#f2b179'
else if (squares[i].innerHTML == 16) squares[i].style.backgroundColor = '#ffcea4'
else if (squares[i].innerHTML == 32) squares[i].style.backgroundColor = '#e8c064'
else if (squares[i].innerHTML == 64) squares[i].style.backgroundColor = '#ffab6e'
else if (squares[i].innerHTML == 128) squares[i].style.backgroundColor = '#fd9982'
else if (squares[i].innerHTML == 256) squares[i].style.backgroundColor = '#ead79c'
else if (squares[i].innerHTML == 512) squares[i].style.backgroundColor = '#76daff'
else if (squares[i].innerHTML == 1024) squares[i].style.backgroundColor = '#beeaa5'
else if (squares[i].innerHTML == 2048) squares[i].style.backgroundColor = '#d7d4f0'
}
}
addColours()
var myTimer = setInterval(addColours, 50)
})
Final Output:
Conclusion:
Congratulations! You have successfully completed the tutorial on creating your own 2048 game using HTML, CSS, and JavaScript. Throughout this guide, you have learned the essential steps and code snippets required to build an engaging online game.
By following the instructions provided in this tutorial, you have gained valuable experience in structuring the HTML, styling the game board with CSS, implementing game logic using JavaScript, and adding interactivity and animations to enhance the gaming experience.
Creating a game like 2048 allows you to explore the exciting world of game development and helps improve your skills in HTML, CSS, and JavaScript. You have learned how to manipulate the DOM, handle user input, and implement game mechanics like tile movements and merging.
Remember that this tutorial provides a solid foundation for creating a 2048 game, but there are endless possibilities for customization and improvement. Feel free to experiment with different designs, animations, and game variations to make your game unique.
As you continue to explore the realms of web development, you can further enhance your game by incorporating additional features such as score tracking, difficulty levels, and responsive design for mobile devices.
We hope this tutorial has inspired you to delve deeper into the world of game development and continue exploring new creative projects. The knowledge and skills you gained from creating the 2048 game will be a valuable asset in your web development journey.
Now it's time to share your creation with others and challenge them to beat your high score. Have fun, keep learning, and let your creativity shine in your future game development endeavors!
Thank you for joining us on this exciting game development journey. Happy coding!
That’s a wrap!
I hope you enjoyed this post. Now, with these examples, you can create your own amazing page.
Did you like it? Let me know in the comments below 🔥 and you can support me by buying me a coffee
And don’t forget to sign up to our email newsletter so you can get useful content like this sent right to your inbox!
Thanks!
Faraz 😊