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
Complain Management using Python with a Graphical User Interface (GUI) Introduction: The Complain Management using Python program designed to manage complaints effectively …
COVID 19 Hospital Management Using Python [Django Framework] Introduction: The COVID-19 Hospital Management is a Python-based application that tracks web applications for Hospitals. …
Drawing Ganesha Using Python Turtle Graphics[Drawing Ganapati Using Python] Introduction In this blog post, we will learn how to draw Lord Ganesha …
Contact Management System in Python with a Graphical User Interface (GUI) Introduction: The Contact Management System is a Python-based application designed to …
KBC Game using Python with Source Code Introduction : Welcome to this blog post on building a “Kaun Banega Crorepati” (KBC) game …
Basic Logging System in C++ With Source Code Introduction : It is one of the most important practices in software development. Logging …