Creating engaging browser-based games is a fantastic way to polish your programming skills. In this tutorial, we’ll walk through building a simple maze game with a 3D effect using HTML5 Canvas and JavaScript. The game involves guiding a player from the starting point to the goal, navigating through a randomly generated maze.
Features of the Maze Game
- 3D Visual Effect: Walls, the player, and the goal have subtle gradients for a 3D appearance.
- Random Maze Generation: Each play-through offers a unique challenge with a maze generated using recursive backtracking.
- Keyboard Navigation: Use arrow keys to navigate the player through the maze.
- Winning State: A congratulatory message appears when the player reaches the goal.
Game Setup
The game is built using HTML, CSS, and JavaScript. Here’s how it’s structured:
- HTML: Defines the canvas element and layout.
- CSS: Styles the game elements and adds 3D effects.
- JavaScript: Implements the game logic, including maze generation, rendering, and player movement.
Follow this video for complete guidance :
Full Source Code
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Find Your Way - 3D</title>
<style>
body {
text-align: center;
font-family: Arial, sans-serif;
background: linear-gradient(to bottom, #e0e0e0, #b0b0b0);
margin: 0;
padding: 0;
}
canvas {
border: 10px solid #222;
border-radius: 10px;
background: linear-gradient(to bottom, #f4f4f4, #d4d4d4);
box-shadow: 0px 8px 15px rgba(0, 0, 0, 0.5);
margin: 20px auto;
display: block;
}
#message {
font-size: 2em;
font-weight: bold;
color: green;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5);
display: none;
}
h1 {
color: #333;
text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.3);
}
</style>
</head>
<body>
<h1>Find Your Way</h1>
<div id="message">You Win!</div>
<canvas id="gameCanvas" width="400" height="400"></canvas>
<script>
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
const gridSize = 20;
const rows = canvas.height / gridSize;
const cols = canvas.width / gridSize;
let player = { x: 0, y: 0 };
let goal = { x: cols - 1, y: rows - 1 };
let maze = [];
// Maze Generator using Recursive Backtracking
function generateMaze() {
maze = Array.from({ length: rows }, () => Array(cols).fill(1)); // Fill maze with walls
const directions = [
{ dx: 0, dy: -1 }, // Up
{ dx: 0, dy: 1 }, // Down
{ dx: -1, dy: 0 }, // Left
{ dx: 1, dy: 0 } // Right
];
// Helper to shuffle directions for random exploration
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;
}
// Recursive function to carve paths
function carvePath(x, y) {
maze[y][x] = 0; // Mark cell as path
shuffle(directions).forEach(({ dx, dy }) => {
const nx = x + dx * 2;
const ny = y + dy * 2;
if (nx >= 0 && ny >= 0 && nx < cols && ny < rows && maze[ny][nx] === 1) {
maze[y + dy][x + dx] = 0; // Remove wall between cells
carvePath(nx, ny);
}
});
}
carvePath(0, 0); // Start carving from the top-left corner
ensureGoalPath();
}
// Ensure the bottom-right corner is reachable
function ensureGoalPath() {
maze[rows - 1][cols - 1] = 0; // Ensure goal position is a path
if (maze[rows - 2][cols - 1] === 1 && maze[rows - 1][cols - 2] === 1) {
maze[rows - 2][cols - 1] = 0; // Create path if isolated
}
}
// Draw Maze, Player, and Goal
function drawGame() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (let i = 0; i < rows; i++) {
for (let j = 0; j < cols; j++) {
if (maze[i][j] === 1) {
// Draw walls with a 3D effect
ctx.fillStyle = '#444';
ctx.fillRect(j * gridSize, i * gridSize, gridSize, gridSize);
ctx.fillStyle = '#555';
ctx.fillRect(j * gridSize + 2, i * gridSize + 2, gridSize - 4, gridSize - 4);
}
}
}
// Draw goal with gradient for 3D effect
const goalGradient = ctx.createLinearGradient(
goal.x * gridSize,
goal.y * gridSize,
(goal.x + 1) * gridSize,
(goal.y + 1) * gridSize
);
goalGradient.addColorStop(0, '#3fa34d');
goalGradient.addColorStop(1, '#2d7a35');
ctx.fillStyle = goalGradient;
ctx.fillRect(goal.x * gridSize, goal.y * gridSize, gridSize, gridSize);
// Draw player with gradient for 3D effect
const playerGradient = ctx.createLinearGradient(
player.x * gridSize,
player.y * gridSize,
(player.x + 1) * gridSize,
(player.y + 1) * gridSize
);
playerGradient.addColorStop(0, '#4a90e2');
playerGradient.addColorStop(1, '#357abf');
ctx.fillStyle = playerGradient;
ctx.fillRect(player.x * gridSize, player.y * gridSize, gridSize, gridSize);
}
// Movement Logic
function movePlayer(dx, dy) {
const newX = player.x + dx;
const newY = player.y + dy;
if (
newX >= 0 && newX < cols &&
newY >= 0 && newY < rows &&
maze[newY][newX] === 0
) {
player.x = newX;
player.y = newY;
if (player.x === goal.x && player.y === goal.y) {
document.getElementById('message').style.display = 'block';
document.removeEventListener('keydown', handleKeyDown);
}
}
drawGame();
}
// Key Controls
function handleKeyDown(e) {
if (e.key === 'ArrowUp') movePlayer(0, -1);
if (e.key === 'ArrowDown') movePlayer(0, 1);
if (e.key === 'ArrowLeft') movePlayer(-1, 0);
if (e.key === 'ArrowRight') movePlayer(1, 0);
}
// Game Initialization
function initGame() {
generateMaze();
drawGame();
document.getElementById('message').style.display = 'none';
player = { x: 0, y: 0 };
document.addEventListener('keydown', handleKeyDown);
}
initGame();
</script>
</body>
</html>
How to Run the Game
- Copy the code into an .html file.
- Open the file in your browser.
- Use the arrow keys to guide the player to the goal.
Enhancements
- Add Difficulty Levels: Increase maze size or player speed.
- Timer: Introduce a countdown for added challenge.
- Mobile Support: Implement touch controls for mobile devices.
This simple maze game is a fun and educational project to practice JavaScript and canvas drawing. Happy coding! 🎮
