Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <title>Circular Maze Game</title>
- <style>
- body {
- margin: 0;
- padding: 20px;
- background: linear-gradient(135deg, #1e3c72, #2a5298);
- font-family: Arial, sans-serif;
- display: flex;
- flex-direction: column;
- align-items: center;
- min-height: 100vh;
- color: white;
- }
- .game-container {
- background: rgba(255, 255, 255, 0.1);
- border-radius: 20px;
- padding: 20px;
- backdrop-filter: blur(10px);
- box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
- }
- #gameCanvas {
- border: 3px solid #fff;
- border-radius: 15px;
- background: #000;
- display: block;
- }
- .controls {
- margin-top: 20px;
- text-align: center;
- font-size: 18px;
- }
- .instructions {
- margin-top: 15px;
- text-align: center;
- opacity: 0.8;
- }
- .status {
- margin-top: 10px;
- text-align: center;
- font-size: 20px;
- font-weight: bold;
- color: #4CAF50;
- }
- button {
- margin-top: 15px;
- padding: 10px 20px;
- font-size: 16px;
- background: linear-gradient(45deg, #FF6B6B, #4ECDC4);
- border: none;
- border-radius: 25px;
- color: white;
- cursor: pointer;
- transition: transform 0.2s;
- }
- button:hover {
- transform: scale(1.05);
- }
- </style>
- </head>
- <body>
- <div class="game-container">
- <canvas id="gameCanvas" width="600" height="600"></canvas>
- <div class="controls">Use WASD or Arrow Keys to move</div>
- <div class="instructions">Navigate from the blue entrance to the red goal on the outer ring!</div>
- <div class="status" id="status"></div>
- <button onclick="generateNewMaze()">Generate New Maze</button>
- </div>
- <script>
- const canvas = document.getElementById('gameCanvas');
- const ctx = canvas.getContext('2d');
- const statusDiv = document.getElementById('status');
- const CANVAS_SIZE = 600;
- const CENTER = CANVAS_SIZE / 2;
- const OUTER_RADIUS = 280;
- const INNER_RADIUS = 40;
- const RINGS = 12;
- const SECTORS = 32;
- let maze = [];
- let player = { ring: 0, sector: 0 };
- let entrance = { ring: 0, sector: 0 };
- let goal = { ring: 0, sector: 0 };
- let gameWon = false;
- class MazeCell {
- constructor(ring, sector) {
- this.ring = ring;
- this.sector = sector;
- this.walls = {
- inner: true, // wall towards center
- outer: true, // wall towards outside
- clockwise: true, // wall in clockwise direction
- counterclockwise: true // wall in counter-clockwise direction
- };
- this.visited = false;
- }
- }
- function initializeMaze() {
- maze = [];
- for (let ring = 0; ring < RINGS; ring++) {
- maze[ring] = [];
- for (let sector = 0; sector < SECTORS; sector++) {
- maze[ring][sector] = new MazeCell(ring, sector);
- }
- }
- }
- function generateMaze() {
- initializeMaze();
- // Create multiple random paths to ensure multiple solutions
- const numPaths = 8;
- for (let pathNum = 0; pathNum < numPaths; pathNum++) {
- // Start from random position
- let currentRing = Math.floor(Math.random() * RINGS);
- let currentSector = Math.floor(Math.random() * SECTORS);
- const pathLength = 15 + Math.floor(Math.random() * 20);
- for (let step = 0; step < pathLength; step++) {
- maze[currentRing][currentSector].visited = true;
- // Randomly choose direction to carve
- const directions = [];
- // Can move inward
- if (currentRing > 0) directions.push('inner');
- // Can move outward
- if (currentRing < RINGS - 1) directions.push('outer');
- // Can move clockwise
- directions.push('clockwise');
- // Can move counter-clockwise
- directions.push('counterclockwise');
- if (directions.length === 0) break;
- const direction = directions[Math.floor(Math.random() * directions.length)];
- let nextRing = currentRing;
- let nextSector = currentSector;
- switch (direction) {
- case 'inner':
- maze[currentRing][currentSector].walls.inner = false;
- nextRing = currentRing - 1;
- maze[nextRing][nextSector].walls.outer = false;
- break;
- case 'outer':
- maze[currentRing][currentSector].walls.outer = false;
- nextRing = currentRing + 1;
- maze[nextRing][nextSector].walls.inner = false;
- break;
- case 'clockwise':
- maze[currentRing][currentSector].walls.clockwise = false;
- nextSector = (currentSector + 1) % SECTORS;
- maze[nextRing][nextSector].walls.counterclockwise = false;
- break;
- case 'counterclockwise':
- maze[currentRing][currentSector].walls.counterclockwise = false;
- nextSector = (currentSector - 1 + SECTORS) % SECTORS;
- maze[nextRing][nextSector].walls.clockwise = false;
- break;
- }
- currentRing = nextRing;
- currentSector = nextSector;
- }
- }
- // Add some random openings to increase solutions
- for (let i = 0; i < 50; i++) {
- const ring = Math.floor(Math.random() * RINGS);
- const sector = Math.floor(Math.random() * SECTORS);
- const wallType = ['inner', 'outer', 'clockwise', 'counterclockwise'][Math.floor(Math.random() * 4)];
- if (wallType === 'inner' && ring > 0) {
- maze[ring][sector].walls.inner = false;
- maze[ring - 1][sector].walls.outer = false;
- } else if (wallType === 'outer' && ring < RINGS - 1) {
- maze[ring][sector].walls.outer = false;
- maze[ring + 1][sector].walls.inner = false;
- } else if (wallType === 'clockwise') {
- maze[ring][sector].walls.clockwise = false;
- maze[ring][(sector + 1) % SECTORS].walls.counterclockwise = false;
- } else if (wallType === 'counterclockwise') {
- maze[ring][sector].walls.counterclockwise = false;
- maze[ring][(sector - 1 + SECTORS) % SECTORS].walls.clockwise = false;
- }
- }
- }
- function setupGame() {
- // Place entrance and goal on outer ring
- entrance.ring = RINGS - 1;
- entrance.sector = Math.floor(Math.random() * SECTORS);
- do {
- goal.ring = RINGS - 1;
- goal.sector = Math.floor(Math.random() * SECTORS);
- } while (goal.sector === entrance.sector);
- // Start player at entrance
- player.ring = entrance.ring;
- player.sector = entrance.sector;
- gameWon = false;
- statusDiv.textContent = '';
- }
- function drawMaze() {
- ctx.clearRect(0, 0, CANVAS_SIZE, CANVAS_SIZE);
- for (let ring = 0; ring < RINGS; ring++) {
- const innerR = INNER_RADIUS + (ring * (OUTER_RADIUS - INNER_RADIUS) / RINGS);
- const outerR = INNER_RADIUS + ((ring + 1) * (OUTER_RADIUS - INNER_RADIUS) / RINGS);
- for (let sector = 0; sector < SECTORS; sector++) {
- const startAngle = (sector * 2 * Math.PI) / SECTORS;
- const endAngle = ((sector + 1) * 2 * Math.PI) / SECTORS;
- const cell = maze[ring][sector];
- ctx.strokeStyle = '#ffffff';
- ctx.lineWidth = 2;
- // Draw radial walls (between sectors)
- if (cell.walls.clockwise) {
- ctx.beginPath();
- ctx.moveTo(CENTER + innerR * Math.cos(endAngle), CENTER + innerR * Math.sin(endAngle));
- ctx.lineTo(CENTER + outerR * Math.cos(endAngle), CENTER + outerR * Math.sin(endAngle));
- ctx.stroke();
- }
- // Draw circular walls (between rings)
- if (cell.walls.outer && ring < RINGS - 1) {
- ctx.beginPath();
- ctx.arc(CENTER, CENTER, outerR, startAngle, endAngle);
- ctx.stroke();
- }
- // Draw innermost circle
- if (ring === 0) {
- ctx.beginPath();
- ctx.arc(CENTER, CENTER, innerR, 0, 2 * Math.PI);
- ctx.stroke();
- }
- }
- }
- // Draw outer boundary
- ctx.beginPath();
- ctx.arc(CENTER, CENTER, OUTER_RADIUS, 0, 2 * Math.PI);
- ctx.stroke();
- }
- function drawPlayer() {
- const ring = player.ring;
- const sector = player.sector;
- const innerR = INNER_RADIUS + (ring * (OUTER_RADIUS - INNER_RADIUS) / RINGS);
- const outerR = INNER_RADIUS + ((ring + 1) * (OUTER_RADIUS - INNER_RADIUS) / RINGS);
- const midR = (innerR + outerR) / 2;
- const midAngle = ((sector + 0.5) * 2 * Math.PI) / SECTORS;
- const x = CENTER + midR * Math.cos(midAngle);
- const y = CENTER + midR * Math.sin(midAngle);
- // Player
- ctx.fillStyle = '#00FF00';
- ctx.beginPath();
- ctx.arc(x, y, 8, 0, 2 * Math.PI);
- ctx.fill();
- }
- function drawEntranceAndGoal() {
- // Entrance (blue)
- const entranceInnerR = INNER_RADIUS + (entrance.ring * (OUTER_RADIUS - INNER_RADIUS) / RINGS);
- const entranceOuterR = INNER_RADIUS + ((entrance.ring + 1) * (OUTER_RADIUS - INNER_RADIUS) / RINGS);
- const entranceMidR = (entranceInnerR + entranceOuterR) / 2;
- const entranceAngle = ((entrance.sector + 0.5) * 2 * Math.PI) / SECTORS;
- const entranceX = CENTER + entranceMidR * Math.cos(entranceAngle);
- const entranceY = CENTER + entranceMidR * Math.sin(entranceAngle);
- ctx.fillStyle = '#0066FF';
- ctx.beginPath();
- ctx.arc(entranceX, entranceY, 12, 0, 2 * Math.PI);
- ctx.fill();
- // Goal (red)
- const goalInnerR = INNER_RADIUS + (goal.ring * (OUTER_RADIUS - INNER_RADIUS) / RINGS);
- const goalOuterR = INNER_RADIUS + ((goal.ring + 1) * (OUTER_RADIUS - INNER_RADIUS) / RINGS);
- const goalMidR = (goalInnerR + goalOuterR) / 2;
- const goalAngle = ((goal.sector + 0.5) * 2 * Math.PI) / SECTORS;
- const goalX = CENTER + goalMidR * Math.cos(goalAngle);
- const goalY = CENTER + goalMidR * Math.sin(goalAngle);
- ctx.fillStyle = '#FF0000';
- ctx.beginPath();
- ctx.arc(goalX, goalY, 12, 0, 2 * Math.PI);
- ctx.fill();
- }
- function canMove(fromRing, fromSector, toRing, toSector) {
- if (toRing < 0 || toRing >= RINGS) return false;
- const normalizedToSector = (toSector + SECTORS) % SECTORS;
- if (fromRing === toRing) {
- // Moving within same ring
- if (Math.abs(fromSector - normalizedToSector) === 1 ||
- Math.abs(fromSector - normalizedToSector) === SECTORS - 1) {
- if (normalizedToSector === (fromSector + 1) % SECTORS) {
- // Moving clockwise
- return !maze[fromRing][fromSector].walls.clockwise;
- } else {
- // Moving counterclockwise
- return !maze[fromRing][fromSector].walls.counterclockwise;
- }
- }
- } else {
- // Moving between rings
- if (fromSector === normalizedToSector) {
- if (toRing === fromRing + 1) {
- // Moving outward
- return !maze[fromRing][fromSector].walls.outer;
- } else if (toRing === fromRing - 1) {
- // Moving inward
- return !maze[fromRing][fromSector].walls.inner;
- }
- }
- }
- return false;
- }
- function movePlayer(direction) {
- if (gameWon) return;
- let newRing = player.ring;
- let newSector = player.sector;
- switch (direction) {
- case 'up': // Move inward
- newRing = player.ring - 1;
- break;
- case 'down': // Move outward
- newRing = player.ring + 1;
- break;
- case 'left': // Move counter-clockwise
- newSector = player.sector - 1;
- break;
- case 'right': // Move clockwise
- newSector = player.sector + 1;
- break;
- }
- if (canMove(player.ring, player.sector, newRing, newSector)) {
- player.ring = newRing;
- player.sector = (newSector + SECTORS) % SECTORS;
- // Check if reached goal
- if (player.ring === goal.ring && player.sector === goal.sector) {
- gameWon = true;
- statusDiv.textContent = '🎉 Congratulations! You reached the goal! 🎉';
- }
- render();
- }
- }
- function render() {
- drawMaze();
- drawEntranceAndGoal();
- drawPlayer();
- }
- function generateNewMaze() {
- generateMaze();
- setupGame();
- render();
- }
- // Keyboard controls
- document.addEventListener('keydown', (e) => {
- switch (e.key.toLowerCase()) {
- case 'w':
- case 'arrowup':
- e.preventDefault();
- movePlayer('up');
- break;
- case 's':
- case 'arrowdown':
- e.preventDefault();
- movePlayer('down');
- break;
- case 'a':
- case 'arrowleft':
- e.preventDefault();
- movePlayer('left');
- break;
- case 'd':
- case 'arrowright':
- e.preventDefault();
- movePlayer('right');
- break;
- }
- });
- // Make canvas focusable for keyboard events
- canvas.setAttribute('tabindex', '0');
- canvas.focus();
- // Initialize the game
- generateNewMaze();
- </script>
- </body>
- </html>
Advertisement
Add Comment
Please, Sign In to add comment