Maze Game using HTML CSS JavaScript With Source Code
Introduction :
The Maze Game is a fun Maze Game using HTML CSS JavaScript, interactive browser-based game developed using HTML, CSS, and JavaScript. The objective of the game is to navigate a player through a maze from the starting point to the finish line. This project demonstrates the use of front-end technologies to create a dynamic and engaging game that runs directly in the browser without the need for any plugins or additional software.
Tech Stack
- HTML5: Provides the basic structure of the game.
- CSS3: Used to style the maze, player, and other game elements.
- JavaScript: Implements the game logic, including player movement, collision detection, and win conditions.
Features of the Maze Game
Interactive Gameplay:
The player can navigate through the maze using keyboard controls, providing an engaging and interactive experience.Responsive Design:
The game is designed to be responsive, adapting to different screen sizes and devices, including desktops, laptops, and tablets.Simple and Clean Interface:
The interface is minimalistic and user-friendly, with clear paths and intuitive controls.Collision Detection:
JavaScript is used to detect collisions between the player and the maze walls, preventing movement through walls.Win Condition:
A winning message is displayed when the player successfully reaches the finish line.
How to Run Below Source Code:
To run the provided code, you can follow these steps:
Create an HTML file: Open a text editor (like Notepad, Visual Studio Code, or Sublime Text) and copy the entire code into a new file. Save the file with a
.html
extension, for example,maze_game.html
.Open the HTML file in a web browser: Double-click on the HTML file you created, and it should open in your default web browser. Alternatively, you can right-click on the file and choose “Open with” to select a specific browser.
Play the game: Once the HTML file is opened in the browser, you should see the maze grid displayed on the screen. You can use the arrow keys on your keyboard to navigate the blue cell (representing the player) through the maze. The goal is to reach the red cell (the end of the maze). If you reach the end, an alert will pop up declaring victory.
How the Maze Game Works
1. HTML Structure
The HTML file sets up the basic structure of the game, including the game board (maze), player, and goal. The main components include:
- Game Board: A container element (
<div>
) representing the maze. - Player: A movable element within the maze.
- Goal: The target area the player needs to reach.
Here is a simplified example of the HTML structure:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Maze Game</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div id="maze">
<div id="player"></div>
<div id="goal"></div>
</div>
<script src="script.js"></script>
</body>
</html>
2. CSS Styling
CSS is used to style the maze, the player, and other elements to create a visually appealing game environment. Key styles include:
- Flexbox and Positioning: CSS Flexbox is used for layout, and absolute positioning is used to place elements within the maze.
- Background Colors and Borders: Different colors and borders are used to define walls, paths, the player, and the goal.
An example of the CSS styling:
body {
margin: 0;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background-color: #333;
}
#maze {
width: 300px;
height: 300px;
position: relative;
border: 2px solid #fff;
}
#player {
width: 20px;
height: 20px;
background-color: red;
position: absolute;
top: 10px;
left: 10px;
}
#goal {
width: 20px;
height: 20px;
background-color: green;
position: absolute;
bottom: 10px;
right: 10px;
}
3. JavaScript Logic
JavaScript is used to handle game logic, including player movement, collision detection, and the win condition.
Player Movement:
The player can move using keyboard arrow keys. Event listeners are added to listen for key presses and update the player’s position accordingly.
document.addEventListener('keydown', movePlayer);
function movePlayer(event) {
const player = document.getElementById('player');
let top = parseInt(player.style.top);
let left = parseInt(player.style.left);
switch (event.key) {
case 'ArrowUp':
top -= 10;
break;
case 'ArrowDown':
top += 10;
break;
case 'ArrowLeft':
left -= 10;
break;
case 'ArrowRight':
left += 10;
break;
}
if (canMoveTo(left, top)) {
player.style.left = `${left}px`;
player.style.top = `${top}px`;
}
}
function canMoveTo(left, top) {
// Collision detection logic to ensure the player doesn't move through walls
return true; // Placeholder for actual collision detection
}
Collision Detection:
A basic function is used to check if the player’s new position will collide with a wall. If there is a collision, the player’s position is not updated.
Win Condition:
When the player reaches the goal position, a win message is displayed:
function checkWinCondition() {
const player = document.getElementById('player');
const goal = document.getElementById('goal');
if (player.style.left === goal.style.left && player.style.top === goal.style.top) {
alert('Congratulations! You reached the goal!');
}
}
Source Code:
HTML (Index.html)
Maze Game
CSS (Style.css)
body {
display: flex;
flex-direction: column;
align-items: center;
height: 100vh;
margin: 70px;
background-color: #d8f3dc;
overflow: hidden;
}
:root {
--border-color: #38a3a5;
--border-size: 1px;
--border-wh: 100%;
--cell-size: 20px;
}
button {
background: #38a3a5;
border: 2px solid #57cc99;
color: #d8f3dc;
padding: 5px;
font-size: large;
}
input#size {
border: 1px solid #57cc99;
padding: 5px;
background: #ffffff;
color: #38a3a5;
}
label {
color: #38a3a5;
}
.cell.start {
background-color: green;
}
.cell.end {
background-color: red;
}
.cell.player {
background: radial-gradient(circle at center, black 0.25rem, transparent 0);
}
.cell.solution {
background-color: #57cc99;
}
#controls {
margin: 20px;
}
#maze-container {
display: grid;
gap: 0;
border: var(--border-color) 11px solid;
}
.cell {
position: relative;
width: var(--cell-size);
height: var(--cell-size);
background-color: white;
}
.cell::before,
.cell::after {
content: "";
position: absolute;
background-color: var(--border-color);
z-index: 1;
}
.cell.top::before {
width: var(--border-wh);
height: var(--border-size);
/* top: -10px;
left: -10px; */
top: 0;
left: 0;
}
.cell.right::after {
width: var(--border-size);
height: var(--border-wh);
top: 0px;
right: 0px;
}
span {
font-size: xx-small;
}
span.right-hand::before {
content: "";
display: block;
background: black;
width: 50%;
height: 2px;
position: absolute;
top: 50%;
left: 0;
transform: translate(0%, -50%);
}
span.left-hand::before {
content: "";
display: block;
background: black;
width: 50%;
height: 2px;
position: absolute;
top: 50%;
right: 0;
transform: translate(0%, -50%);
}
span.bottom-hand::before {
content: "";
display: block;
background: black;
width: 2px;
height: 50%;
position: absolute;
top: 0;
left: 50%;
transform: translate(-50%, 0%);
}
span.top-hand::before {
content: "";
display: block;
background: black;
width: 2px;
height: 50%;
position: absolute;
bottom: 0;
left: 50%;
transform: translate(-50%, 0%);
}
span.to-left::after {
content: "";
display: block;
background: black;
width: 50%;
height: 2px;
position: absolute;
top: 50%;
left: 0;
transform: translate(0%, -50%);
}
span.to-right::after {
content: "";
display: block;
background: black;
width: 50%;
height: 2px;
position: absolute;
top: 50%;
right: 0;
transform: translate(0%, -50%);
}
span.to-top::after {
content: "";
display: block;
background: black;
width: 2px;
height: 50%;
position: absolute;
top: 0;
left: 50%;
transform: translate(-50%, 0%);
}
span.to-bottom::after {
content: "";
display: block;
background: black;
width: 2px;
height: 50%;
position: absolute;
bottom: 0;
left: 50%;
transform: translate(-50%, 0%);
}
#controls2 {
position: absolute;
top: 50%;
left: 100px;
transform: translate(-50%, -50%);
}
Javascript(Script.js)
let mazeContainer = document.getElementById("maze-container");
let sizeInput = document.getElementById("size");
let generateButton = document.getElementById("generate");
let solveButton = document.getElementById("solve");
let size = parseInt(sizeInput.value);
let maze = generateMaze(size);
let playerPosition = { x: 0, y: 0 };
let previousPosition = { x: 0, y: 0 };
let visited = {};
let previousPositions = [];
let PlayerCanMove = true;
renderMaze(maze);
generateButton.addEventListener("click", () => {
size = parseInt(sizeInput.value);
maze = generateMaze(size);
playerPosition = { x: 0, y: 0 };
visited = {};
PlayerCanMove = true;
renderMaze(maze);
});
solveButton.addEventListener("click", () => {
PlayerCanMove = false;
const solution = solveMaze(maze, size);
animateSolution(solution);
});
document.addEventListener("keydown", movePlayer);
function generateMaze(size) {
const maze = Array.from({ length: size }, () => Array(size).fill(15));
const visited = Array.from({ length: size }, () => Array(size).fill(false));
const walls = [];
function addWalls(x, y) {
if (x > 0 && !visited[y][x - 1]) walls.push({ x, y, direction: "left" });
if (x < size - 1 && !visited[y][x + 1])
walls.push({ x, y, direction: "right" });
if (y > 0 && !visited[y - 1][x]) walls.push({ x, y, direction: "up" });
if (y < size - 1 && !visited[y + 1][x])
walls.push({ x, y, direction: "down" });
}
let x = Math.floor(Math.random() * size);
let y = Math.floor(Math.random() * size);
visited[y][x] = true;
addWalls(x, y);
while (walls.length > 0) {
const { x, y, direction } = walls.splice(
Math.floor(Math.random() * walls.length),
1
)[0];
let nx = x,
ny = y;
if (direction === "left") nx--;
if (direction === "right") nx++;
if (direction === "up") ny--;
if (direction === "down") ny++;
if (nx >= 0 && ny >= 0 && nx < size && ny < size && !visited[ny][nx]) {
visited[ny][nx] = true;
if (direction === "left") {
maze[y][x] &= ~1;
maze[ny][nx] &= ~4;
} else if (direction === "right") {
maze[y][x] &= ~4;
maze[ny][nx] &= ~1;
} else if (direction === "up") {
maze[y][x] &= ~2;
maze[ny][nx] &= ~8;
} else if (direction === "down") {
maze[y][x] &= ~8;
maze[ny][nx] &= ~2;
}
addWalls(nx, ny);
}
}
return maze;
}
function shuffle(array) {
for (let i = array.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[array[i], array[j]] = [array[j], array[i]];
}
return array;
}
function renderMaze(maze, solution = []) {
mazeContainer.style.gridTemplateColumns = `repeat(${size}, var(--cell-size))`;
mazeContainer.style.gridTemplateRows = `repeat(${size}, var(--cell-size))`;
mazeContainer.innerHTML = "";
for (let y = 0; y < size; y++) {
for (let x = 0; x < size; x++) {
const cell = document.createElement("div");
cell.className = "cell";
cell.dataset.x = x;
cell.dataset.y = y;
if (x === 0 && y === 0) cell.classList.add("start");
if (x === size - 1 && y === size - 1) cell.classList.add("end");
if (solution.some((pos) => pos.x === x && pos.y === y)) {
cell.classList.add("solution");
}
addWalls(cell, maze[y][x]);
mazeContainer.appendChild(cell);
}
}
const playerCell = document.querySelector(
`.cell[data-x="${playerPosition.x}"][data-y="${playerPosition.y}"]`
);
playerCell.classList.add("player");
}
function addWalls(cell, value) {
if (value & 1) cell.classList.add("left");
if (value & 2) cell.classList.add("top");
if (value & 4) cell.classList.add("right");
if (value & 8) cell.classList.add("bottom");
}
function solveMaze(maze, size) {
const directions = [
{ x: 1, y: 0 },
{ x: -1, y: 0 },
{ x: 0, y: 1 },
{ x: 0, y: -1 }
];
const start = { x: 0, y: 0 };
const end = { x: size - 1, y: size - 1 };
const queue = [[start]];
const visited = Array.from({ length: size }, () => Array(size).fill(false));
visited[0][0] = true;
while (queue.length) {
const path = queue.shift();
const { x, y } = path[path.length - 1];
if (x === end.x && y === end.y) {
return path;
}
for (const { x: dx, y: dy } of directions) {
const nx = x + dx;
const ny = y + dy;
if (
nx >= 0 &&
ny >= 0 &&
nx < size &&
ny < size &&
!visited[ny][nx] &&
canMove(maze[y][x], dx, dy)
) {
visited[ny][nx] = true;
queue.push([...path, { x: nx, y: ny }]);
}
}
}
return [];
}
function canMove(cellValue, dx, dy) {
if (dx === 1 && !(cellValue & 4)) return true;
if (dx === -1 && !(cellValue & 1)) return true;
if (dy === 1 && !(cellValue & 8)) return true;
if (dy === -1 && !(cellValue & 2)) return true;
return false;
}
function animateSolution(solution) {
let index = 0;
const interval = setInterval(() => {
if (index >= solution.length) {
clearInterval(interval);
return;
}
const { x, y } = solution[index];
const cell = document.querySelector(`.cell[data-x="${x}"][data-y="${y}"]`);
cell.classList.add("solution");
index++;
}, 100);
}
function movePlayer(event) {
const directionMap = {
ArrowUp: { dx: 0, dy: -1 },
ArrowDown: { dx: 0, dy: 1 },
ArrowLeft: { dx: -1, dy: 0 },
ArrowRight: { dx: 1, dy: 0 }
};
if (PlayerCanMove) {
if (directionMap[event.key]) {
const { dx, dy } = directionMap[event.key];
const newX = playerPosition.x + dx;
const newY = playerPosition.y + dy;
if (
newX >= 0 &&
newY >= 0 &&
newX < size &&
newY < size &&
canMove(maze[playerPosition.y][playerPosition.x], dx, dy)
) {
previousPosition = { ...playerPosition };
playerPosition.x = newX;
playerPosition.y = newY;
updatePlayerPosition(dx, dy);
}
}
}
}
function updatePlayerPosition(dx, dy) {
const oldCell = document.querySelector(
`.cell[data-x="${previousPosition.x}"][data-y="${previousPosition.y}"]`
);
const newCell = document.querySelector(
`.cell[data-x="${playerPosition.x}"][data-y="${playerPosition.y}"]`
);
oldCell.classList.remove("player");
newCell.classList.add("player");
let oldSpan = oldCell.querySelector("span");
let newSpan = newCell.querySelector("span");
if (!oldSpan) {
oldSpan = document.createElement("span");
oldCell.appendChild(oldSpan);
}
if (!newSpan) {
newSpan = document.createElement("span");
newCell.appendChild(newSpan);
}
// Oyuncu geri giderse class güncelleme
if (
previousPositions.length > 0 &&
previousPositions[previousPositions.length - 1].x === playerPosition.x &&
previousPositions[previousPositions.length - 1].y === playerPosition.y
) {
previousPositions.pop();
if (oldSpan) {
oldSpan.className = "";
}
if (dx === 1) {
newSpan.classList.remove("to-left");
} else if (dx === -1) {
newSpan.classList.remove("to-right");
} else if (dy === 1) {
newSpan.classList.remove("to-top");
} else if (dy === -1) {
newSpan.classList.remove("to-bottom");
}
} else {
if (dx === 1) {
oldSpan.classList.add("to-right");
newSpan.classList.add("right-hand");
} else if (dx === -1) {
oldSpan.classList.add("to-left");
newSpan.classList.add("left-hand");
} else if (dy === 1) {
oldSpan.classList.add("to-bottom");
newSpan.classList.add("bottom-hand");
} else if (dy === -1) {
oldSpan.classList.add("to-top");
newSpan.classList.add("top-hand");
}
previousPositions.push({ ...previousPosition });
}
}
Output :
See the Pen HMTL Maze Game by Abdullah-Yilmazer (@Abdullah-Yilmazer) on CodePen.
Find More Projects
Build a Quiz Game Using HTML CSS and JavaScript Introduction Hello coders, you might have played various games, but were you aware …
Emoji Catcher Game Using HTML CSS and JavaScript Introduction Hello Coders, Welcome to another new blog. In this article we’ve made a …
Typing Challenge Using HTML CSS and JavaScript Introduction Hello friends, all you developer friends are welcome to our new project. If you …
Breakout Game Using HTML CSS and JavaScript With Source Code Introduction Hello friends, welcome to today’s new blog post. All of you …
Digital and Analog Clock using HTML CSS and JavaScript Introduction : This project is a digital clock and stopwatch system, which allows …
Coffee Shop Website using HTML, CSS & JavaScript Introduction : This project is a website for coffee house business. It uses HTML …