// TODO: if there are no more levels show a "game win" message // Game constants const canvas = document.getElementById('gameCanvas'); const ctx = canvas.getContext('2d'); canvas.width = 800; canvas.height = 600; const GRAVITY = 4; const JUMP_STRENGTH = -33; const MOVE_SPEED = 7; let keys = { left: false, right: false, up: false, down: false, space: false }; let levels = [ [ // Next level example [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] ], [ [4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], [1, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], [1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], [1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1], [1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], [1, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] ] // Add more levels as needed ]; let currentLevel = 0; class Player { constructor(x, y) { this.x = x; this.y = y; this.width = 30; this.height = 30; this.velocityX = 0; this.velocityY = 0; this.jumping = false; this.doubleJumping = false; } update() { if (keys.left) this.velocityX = -MOVE_SPEED; if (keys.right) this.velocityX = MOVE_SPEED; if (!keys.left && !keys.right) this.velocityX = 0; this.velocityY += GRAVITY; this.x += this.velocityX; this.y += this.velocityY; // Collision detection this.checkCollision(); // Limit falling speed if (this.velocityY > 10) this.velocityY = 10; } jump() { if (!this.jumping) { this.velocityY = JUMP_STRENGTH; this.jumping = true; } else if (!this.doubleJumping) { this.velocityY = JUMP_STRENGTH; this.doubleJumping = true; } } checkCollision() { let row, col, belowRow, aboveRow, leftCol, rightCol; // Check collision with ground from below row = Math.floor(this.y / 30); col = Math.floor(this.x / 30); belowRow = Math.floor((this.y + this.height) / 30); if (levels[currentLevel][belowRow] && levels[currentLevel][belowRow][col] === 1) { if (this.velocityY > 0) { this.y = belowRow * 30 - this.height; this.velocityY = 0; this.jumping = false; this.doubleJumping = false; } } // Check collision with ground from above aboveRow = Math.floor((this.y - 1) / 30); if (levels[currentLevel][aboveRow] && levels[currentLevel][aboveRow][col] === 1) { if (this.velocityY < 0) { this.y = (aboveRow + 1) * 30; this.velocityY = 0; } } // Check collision with ground from the left leftCol = Math.floor(this.x / 30); if (levels[currentLevel][row] && levels[currentLevel][row][leftCol] === 1) { if (this.velocityX < 0) { this.x = (leftCol + 1) * 30; this.velocityX = 0; } } // Check collision with ground from the right rightCol = Math.floor((this.x + this.width) / 30); if (levels[currentLevel][row] && levels[currentLevel][row][rightCol] === 1) { if (this.velocityX > 0) { this.x = rightCol * 30 - this.width; this.velocityX = 0; } } // Collision with lava if (levels[currentLevel][row] && levels[currentLevel][row][col] === 2) { this.reset(); } // Collision with save point if (levels[currentLevel][row] && levels[currentLevel][row][col] === 3) { localStorage.setItem('savePoint', JSON.stringify({ x: this.x, y: this.y, level: currentLevel })); } // Collision with goal if (levels[currentLevel][row] && levels[currentLevel][row][col] === 5) { alert('Level Complete!'); loadNextLevel(); } } reset() { let savePoint = JSON.parse(localStorage.getItem('savePoint')) || { x: 30, y: 30, level: 0 }; this.x = savePoint.x; this.y = savePoint.y; currentLevel = savePoint.level; this.velocityY = 0; } render() { ctx.fillStyle = 'blue'; ctx.fillRect(this.x, this.y, this.width, this.height); } } function findPlayerStartPosition(level) { for (let row = 0; row < levels[level].length; row++) { for (let col = 0; col < levels[level][row].length; col++) { if (levels[level][row][col] === 4) { return { x: col * 30, y: row * 30 }; } } } // Default position if no start point found return { x: 30, y: 570 }; } function renderLevel() { for (let row = 0; row < levels[currentLevel].length; row++) { for (let col = 0; col < levels[currentLevel][row].length; col++) { if (levels[currentLevel][row][col] === 1) { ctx.fillStyle = 'brown'; ctx.fillRect(col * 30, row * 30, 30, 30); } else if (levels[currentLevel][row][col] === 2) { ctx.fillStyle = 'red'; ctx.fillRect(col * 30, row * 30, 30, 30); } else if (levels[currentLevel][row][col] === 3) { ctx.fillStyle = 'green'; ctx.fillRect(col * 30, row * 30, 30, 30); } else if (levels[currentLevel][row][col] === 5) { ctx.fillStyle = 'gold'; ctx.fillRect(col * 30, row * 30, 30, 30); } } } } function loadNextLevel() { currentLevel++; if (currentLevel >= levels.length) { alert("You've completed all levels!"); currentLevel = 0; } let startPosition = findPlayerStartPosition(currentLevel); player.x = startPosition.x; player.y = startPosition.y; player.velocityY = 0; localStorage.setItem('savePoint', JSON.stringify({ x: player.x, y: player.y, level: currentLevel })); } let startPosition = findPlayerStartPosition(currentLevel); let player = new Player(startPosition.x, startPosition.y); function gameLoop() { ctx.clearRect(0, 0, canvas.width, canvas.height); renderLevel(); player.update(); player.render(); requestAnimationFrame(gameLoop); } document.addEventListener('keydown', (e) => { if (e.code === 'ArrowLeft') keys.left = true; if (e.code === 'ArrowRight') keys.right = true; if (e.code === 'ArrowUp') keys.up = true; if (e.code === 'ArrowDown') keys.down = true; if (e.code === 'Space') player.jump(); }); document.addEventListener('keyup', (e) => { if (e.code === 'ArrowLeft') keys.left = false; if (e.code === 'ArrowRight') keys.right = false; if (e.code === 'ArrowUp') keys.up = false; if (e.code === 'ArrowDown') keys.down = false; }); gameLoop();