| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <title>Super Mario Lite</title> |
| <script src="https://cdn.tailwindcss.com"></script> |
| <style> |
| @import url('https://fonts.googleapis.com/css2?family=Press+Start+2P&display=swap'); |
| |
| body { |
| margin: 0; |
| padding: 0; |
| overflow: hidden; |
| font-family: 'Press Start 2P', cursive; |
| background-color: #6be0fd; |
| touch-action: manipulation; |
| } |
| |
| #game-container { |
| position: relative; |
| width: 100vw; |
| height: 100vh; |
| overflow: hidden; |
| } |
| |
| #game-canvas { |
| position: absolute; |
| top: 0; |
| left: 0; |
| } |
| |
| #start-screen, #game-over-screen, #win-screen { |
| position: absolute; |
| top: 0; |
| left: 0; |
| width: 100%; |
| height: 100%; |
| display: flex; |
| flex-direction: column; |
| justify-content: center; |
| align-items: center; |
| background-color: rgba(0, 0, 0, 0.7); |
| z-index: 10; |
| } |
| |
| #game-over-screen, #win-screen { |
| display: none; |
| } |
| |
| .btn { |
| background-color: #e52521; |
| color: white; |
| border: none; |
| padding: 15px 30px; |
| font-size: 16px; |
| font-family: 'Press Start 2P', cursive; |
| cursor: pointer; |
| border-radius: 10px; |
| box-shadow: 0 5px 0 #81261f; |
| transition: all 0.1s; |
| margin-top: 20px; |
| letter-spacing: 1px; |
| } |
| |
| .btn:active { |
| transform: translateY(5px); |
| box-shadow: 0 0 0 #81261f; |
| } |
| |
| .title { |
| color: white; |
| font-size: 36px; |
| text-align: center; |
| text-shadow: 4px 4px 0 #e52521; |
| margin-bottom: 30px; |
| } |
| |
| .score-display { |
| position: absolute; |
| top: 20px; |
| left: 20px; |
| color: white; |
| font-size: 18px; |
| text-shadow: 2px 2px 0 #000; |
| z-index: 5; |
| } |
| |
| .time-display { |
| position: absolute; |
| top: 20px; |
| right: 20px; |
| color: white; |
| font-size: 18px; |
| text-shadow: 2px 2px 0 #000; |
| z-index: 5; |
| } |
| |
| .ground { |
| position: absolute; |
| bottom: 0; |
| width: 300%; |
| height: 60px; |
| background-color: #56b949; |
| z-index: 2; |
| background-image: |
| linear-gradient(transparent 95%, #3a7d33 95%), |
| linear-gradient(90deg, transparent 50%, #3a7d33 50%); |
| background-size: 20px 20px; |
| } |
| |
| .brick { |
| position: absolute; |
| width: 40px; |
| height: 40px; |
| background-color: #b85a20; |
| border-radius: 3px; |
| border: 3px solid #8c3f10; |
| box-shadow: inset -3px -3px 0 rgba(0,0,0,0.2); |
| z-index: 2; |
| } |
| |
| .coin { |
| position: absolute; |
| width: 20px; |
| height: 20px; |
| background-color: #f9d423; |
| border-radius: 50%; |
| border: 2px solid #e2b007; |
| box-shadow: 0 0 5px gold; |
| z-index: 2; |
| animation: coinSpin 1.5s infinite linear; |
| } |
| |
| @keyframes coinSpin { |
| 0% { transform: rotateY(0); } |
| 100% { transform: rotateY(360deg); } |
| } |
| |
| .mario { |
| position: absolute; |
| width: 40px; |
| height: 60px; |
| background-color: #e52521; |
| border-radius: 10px 10px 0 0; |
| z-index: 3; |
| transition: transform 0.1s; |
| } |
| |
| .mario::before { |
| content: ""; |
| position: absolute; |
| top: -10px; |
| left: 5px; |
| width: 30px; |
| height: 15px; |
| background-color: #e52521; |
| border-radius: 50% 50% 0 0; |
| } |
| |
| .mario::after { |
| content: ""; |
| position: absolute; |
| top: -5px; |
| left: 10px; |
| width: 20px; |
| height: 10px; |
| background-color: #f3b9b8; |
| border-radius: 10px 10px 0 0; |
| } |
| |
| .mario .cap { |
| position: absolute; |
| top: -15px; |
| left: 5px; |
| width: 30px; |
| height: 10px; |
| background-color: #1144ee; |
| border-radius: 5px 0 0 5px; |
| } |
| |
| .mario .cap::before { |
| content: ""; |
| position: absolute; |
| top: -5px; |
| left: 0; |
| width: 30px; |
| height: 5px; |
| background-color: #1144ee; |
| border-radius: 5px 5px 0 0; |
| } |
| |
| .mario .eyes { |
| position: absolute; |
| top: 0; |
| left: 10px; |
| width: 20px; |
| height: 5px; |
| } |
| |
| .mario .eyes::before, |
| .mario .eyes::after { |
| content: ""; |
| position: absolute; |
| width: 5px; |
| height: 5px; |
| background-color: #000; |
| border-radius: 50%; |
| } |
| |
| .mario .eyes::before { |
| left: 0; |
| } |
| |
| .mario .eyes::after { |
| right: 0; |
| } |
| |
| .mario .mustache { |
| position: absolute; |
| top: 5px; |
| left: 5px; |
| width: 30px; |
| height: 5px; |
| background-color: #4d2a1e; |
| border-radius: 5px; |
| } |
| |
| .mario .mustache::before, |
| .mario .mustache::after { |
| content: ""; |
| position: absolute; |
| width: 5px; |
| height: 3px; |
| background-color: #4d2a1e; |
| border-radius: 50%; |
| } |
| |
| .mario .mustache::before { |
| left: 0; |
| top: 2px; |
| } |
| |
| .mario .mustache::after { |
| right: 0; |
| top: 2px; |
| } |
| |
| .mario .torso { |
| position: absolute; |
| top: 20px; |
| left: 5px; |
| width: 30px; |
| height: 25px; |
| background-color: #e52521; |
| } |
| |
| .mario .overalls { |
| position: absolute; |
| top: 25px; |
| left: 0; |
| width: 40px; |
| height: 25px; |
| background-color: #1144ee; |
| border-radius: 0 0 5px 5px; |
| } |
| |
| .mario .overalls::before { |
| content: ""; |
| position: absolute; |
| top: 0; |
| left: 15px; |
| width: 10px; |
| height: 10px; |
| background-color: #f3b9b8; |
| border-radius: 2px; |
| } |
| |
| .mario .buttons { |
| position: absolute; |
| top: 30px; |
| left: 15px; |
| width: 10px; |
| height: 10px; |
| } |
| |
| .mario .buttons::before, |
| .mario .buttons::after { |
| content: ""; |
| position: absolute; |
| width: 10px; |
| height: 2px; |
| background-color: gold; |
| border-radius: 2px; |
| } |
| |
| .mario .buttons::before { |
| top: 0; |
| } |
| |
| .mario .buttons::after { |
| top: 5px; |
| } |
| |
| .mario .arms { |
| position: absolute; |
| top: 25px; |
| left: 0; |
| width: 40px; |
| height: 10px; |
| } |
| |
| .mario .arms::before, |
| .mario .arms::after { |
| content: ""; |
| position: absolute; |
| width: 5px; |
| height: 15px; |
| background-color: #e52521; |
| border-radius: 2px; |
| } |
| |
| .mario .arms::before { |
| left: 0; |
| } |
| |
| .mario .arms::after { |
| right: 0; |
| } |
| |
| .mario .legs { |
| position: absolute; |
| bottom: 0; |
| left: 5px; |
| width: 30px; |
| height: 15px; |
| } |
| |
| .mario .legs::before, |
| .mario .legs::after { |
| content: ""; |
| position: absolute; |
| width: 10px; |
| height: 15px; |
| background-color: #1144ee; |
| border-radius: 0 0 2px 2px; |
| } |
| |
| .mario .legs::before { |
| left: 0; |
| } |
| |
| .mario .legs::after { |
| right: 0; |
| } |
| |
| .enemy { |
| position: absolute; |
| width: 40px; |
| height: 40px; |
| background-color: #6abe30; |
| border-radius: 50%; |
| z-index: 2; |
| } |
| |
| .enemy::before { |
| content: ""; |
| position: absolute; |
| top: 0; |
| left: 0; |
| width: 40px; |
| height: 20px; |
| background-color: #6abe30; |
| border-radius: 20px 20px 0 0; |
| } |
| |
| .enemy::after { |
| content: ""; |
| position: absolute; |
| top: -3px; |
| left: 5px; |
| width: 30px; |
| height: 15px; |
| background-color: #8dce68; |
| border-radius: 15px 15px 0 0; |
| } |
| |
| .enemy .eyes { |
| position: absolute; |
| top: 5px; |
| left: 10px; |
| width: 20px; |
| height: 5px; |
| } |
| |
| .enemy .eyes::before, |
| .enemy .eyes::after { |
| content: ""; |
| position: absolute; |
| width: 5px; |
| height: 5px; |
| background-color: #000; |
| border-radius: 50%; |
| } |
| |
| .enemy .eyes::before { |
| left: 0; |
| } |
| |
| .enemy .eyes::after { |
| right: 0; |
| } |
| |
| .castle { |
| position: absolute; |
| width: 80px; |
| height: 120px; |
| background-color: #853a11; |
| z-index: 2; |
| border-radius: 10px 10px 0 0; |
| } |
| |
| .castle::before { |
| content: ""; |
| position: absolute; |
| top: -20px; |
| left: 10px; |
| width: 60px; |
| height: 20px; |
| background-color: #853a11; |
| clip-path: polygon(0% 100%, 10% 0%, 20% 100%, 30% 0%, 40% 100%, 50% 0%, 60% 100%, 70% 0%, 80% 100%, 90% 0%, 100% 100%); |
| } |
| |
| .castle .door { |
| position: absolute; |
| bottom: 0; |
| left: 20px; |
| width: 40px; |
| height: 60px; |
| background-color: #5a2a0c; |
| border-radius: 5px 5px 0 0; |
| } |
| |
| .castle .flag-pole { |
| position: absolute; |
| top: -40px; |
| left: 5px; |
| width: 3px; |
| height: 80px; |
| background-color: #fff; |
| } |
| |
| .castle .flag { |
| position: absolute; |
| top: -40px; |
| left: 8px; |
| width: 30px; |
| height: 20px; |
| background-color: #e52521; |
| clip-path: polygon(0% 0%, 80% 0%, 100% 50%, 80% 100%, 0% 100%); |
| } |
| |
| .pipe { |
| position: absolute; |
| width: 60px; |
| height: 80px; |
| background-color: #379937; |
| z-index: 2; |
| border-radius: 5px 5px 0 0; |
| border: 4px solid #266926; |
| } |
| |
| .cloud { |
| position: absolute; |
| background-color: white; |
| border-radius: 50%; |
| opacity: 0.9; |
| z-index: 0; |
| } |
| |
| @keyframes jump { |
| 0%, 100% { transform: translateY(0); } |
| 50% { transform: translateY(-20px); } |
| } |
| |
| .jumping { |
| animation: jump 0.5s ease; |
| } |
| |
| .crouching { |
| transform: scaleY(0.9) translateY(10px); |
| } |
| |
| .sliding { |
| transform: translateX(-10px); |
| } |
| |
| .small { |
| transform: scale(0.7); |
| height: 40px !important; |
| } |
| </style> |
| </head> |
| <body> |
| <div id="game-container"> |
| <div class="score-display" id="score">SCORE: 0</div> |
| <div class="time-display" id="time">TIME: 300</div> |
| |
| <div id="start-screen"> |
| <h1 class="title">SUPER MARIO LITE</h1> |
| <button class="btn" id="start-btn">START GAME</button> |
| <div class="mt-8 text-white text-center text-sm"> |
| <p>Arrow Keys to Move</p> |
| <p>Space to Jump</p> |
| <p>Collect Coins, Avoid Enemies</p> |
| </div> |
| </div> |
| |
| <div id="game-over-screen"> |
| <h1 class="title">GAME OVER</h1> |
| <div class="text-white text-center mb-6"> |
| <p>SCORE: <span id="final-score">0</span></p> |
| <p>HIGH SCORE: <span id="high-score">0</span></p> |
| </div> |
| <button class="btn" id="restart-btn">PLAY AGAIN</button> |
| </div> |
| |
| <div id="win-screen"> |
| <h1 class="title">YOU WIN!</h1> |
| <div class="text-white text-center mb-6"> |
| <p>SCORE: <span id="win-score">0</span></p> |
| <p>HIGH SCORE: <span id="win-high-score">0</span></p> |
| </div> |
| <button class="btn" id="win-restart-btn">PLAY AGAIN</button> |
| </div> |
| |
| <div class="ground"></div> |
| </div> |
|
|
| <script> |
| document.addEventListener('DOMContentLoaded', () => { |
| const gameContainer = document.getElementById('game-container'); |
| const startScreen = document.getElementById('start-screen'); |
| const gameOverScreen = document.getElementById('game-over-screen'); |
| const winScreen = document.getElementById('win-screen'); |
| const startBtn = document.getElementById('start-btn'); |
| const restartBtn = document.getElementById('restart-btn'); |
| const winRestartBtn = document.getElementById('win-restart-btn'); |
| const scoreDisplay = document.getElementById('score'); |
| const timeDisplay = document.getElementById('time'); |
| const finalScoreDisplay = document.getElementById('final-score'); |
| const highScoreDisplay = document.getElementById('high-score'); |
| const winScoreDisplay = document.getElementById('win-score'); |
| const winHighScoreDisplay = document.getElementById('win-high-score'); |
| |
| let gameRunning = false; |
| let score = 0; |
| let highScore = localStorage.getItem('marioHighScore') || 0; |
| let time = 300; |
| let mario; |
| let ground; |
| let enemies = []; |
| let coins = []; |
| let bricks = []; |
| let pipes = []; |
| let clouds = []; |
| let castle = null; |
| let gravity = 0.5; |
| let jumpForce = -12; |
| let marioVelocityY = 0; |
| let marioPositionX = 100; |
| let marioPositionY = 300; |
| let marioDirection = 'right'; |
| let isJumping = false; |
| let isCrouching = false; |
| let isSliding = false; |
| let isInvincible = false; |
| let gameSpeed = 3; |
| let cameraOffset = 0; |
| let lastTime = 0; |
| let gameLoopId; |
| let timeInterval; |
| let isAlive = true; |
| let levelComplete = false; |
| |
| highScoreDisplay.textContent = highScore; |
| winHighScoreDisplay.textContent = highScore; |
| |
| |
| function createMario() { |
| mario = document.createElement('div'); |
| mario.className = 'mario'; |
| mario.innerHTML = ` |
| <div class="cap"></div> |
| <div class="eyes"></div> |
| <div class="mustache"></div> |
| <div class="torso"></div> |
| <div class="overalls"></div> |
| <div class="buttons"></div> |
| <div class="arms"></div> |
| <div class="legs"></div> |
| `; |
| mario.style.left = marioPositionX + 'px'; |
| mario.style.bottom = marioPositionY + 'px'; |
| gameContainer.appendChild(mario); |
| } |
| |
| |
| function createGround() { |
| ground = document.querySelector('.ground'); |
| } |
| |
| |
| function createEnemy(x, y) { |
| const enemy = document.createElement('div'); |
| enemy.className = 'enemy'; |
| enemy.innerHTML = `<div class="eyes"></div>`; |
| enemy.style.left = x + 'px'; |
| enemy.style.bottom = y + 'px'; |
| gameContainer.appendChild(enemy); |
| |
| enemies.push({ |
| element: enemy, |
| x: x, |
| y: y, |
| direction: -1, |
| speed: Math.random() * 1 + 1 |
| }); |
| } |
| |
| |
| function createCoin(x, y) { |
| const coin = document.createElement('div'); |
| coin.className = 'coin'; |
| coin.style.left = x + 'px'; |
| coin.style.bottom = y + 'px'; |
| gameContainer.appendChild(coin); |
| |
| coins.push({ |
| element: coin, |
| x: x, |
| y: y, |
| collected: false |
| }); |
| } |
| |
| |
| function createBrick(x, y, hasCoin = false) { |
| const brick = document.createElement('div'); |
| brick.className = 'brick'; |
| brick.style.left = x + 'px'; |
| brick.style.bottom = y + 'px'; |
| gameContainer.appendChild(brick); |
| |
| bricks.push({ |
| element: brick, |
| x: x, |
| y: y, |
| hasCoin: hasCoin, |
| hit: false |
| }); |
| |
| if (hasCoin) { |
| createCoin(x + 10, y + 45); |
| } |
| } |
| |
| |
| function createPipe(x, y, height = 80) { |
| const pipe = document.createElement('div'); |
| pipe.className = 'pipe'; |
| pipe.style.left = x + 'px'; |
| pipe.style.bottom = y + 'px'; |
| pipe.style.height = height + 'px'; |
| gameContainer.appendChild(pipe); |
| |
| pipes.push({ |
| element: pipe, |
| x: x, |
| y: y, |
| height: height |
| }); |
| } |
| |
| |
| function createCloud(x, y, size) { |
| const cloud = document.createElement('div'); |
| cloud.className = 'cloud'; |
| cloud.style.left = x + 'px'; |
| cloud.style.bottom = y + 'px'; |
| cloud.style.width = size + 'px'; |
| cloud.style.height = size / 2 + 'px'; |
| gameContainer.appendChild(cloud); |
| |
| clouds.push({ |
| element: cloud, |
| x: x, |
| y: y, |
| size: size |
| }); |
| } |
| |
| |
| function createCastle(x) { |
| castle = document.createElement('div'); |
| castle.className = 'castle'; |
| castle.innerHTML = ` |
| <div class="door"></div> |
| <div class="flag-pole"></div> |
| <div class="flag"></div> |
| `; |
| castle.style.left = x + 'px'; |
| castle.style.bottom = '60px'; |
| gameContainer.appendChild(castle); |
| |
| return { |
| element: castle, |
| x: x |
| }; |
| } |
| |
| |
| function setupLevel() { |
| |
| const existingEnemies = document.querySelectorAll('.enemy'); |
| const existingCoins = document.querySelectorAll('.coin'); |
| const existingBricks = document.querySelectorAll('.brick'); |
| const existingPipes = document.querySelectorAll('.pipe'); |
| const existingClouds = document.querySelectorAll('.cloud'); |
| const existingCastle = document.querySelector('.castle'); |
| |
| existingEnemies.forEach(enemy => enemy.remove()); |
| existingCoins.forEach(coin => coin.remove()); |
| existingBricks.forEach(brick => brick.remove()); |
| existingPipes.forEach(pipe => pipe.remove()); |
| existingClouds.forEach(cloud => cloud.remove()); |
| if (existingCastle) existingCastle.remove(); |
| |
| |
| enemies = []; |
| coins = []; |
| bricks = []; |
| pipes = []; |
| clouds = []; |
| castle = null; |
| |
| |
| |
| |
| |
| createCloud(200, 400, 80); |
| createCloud(500, 350, 100); |
| createCloud(800, 450, 60); |
| |
| |
| for (let i = 0; i < 5; i++) { |
| createBrick(300 + i * 50, 100, i % 2 === 0); |
| } |
| |
| |
| createCoin(200, 150); |
| createCoin(250, 200); |
| createCoin(700, 150); |
| |
| |
| createPipe(400, 60, 100); |
| createPipe(600, 60, 80); |
| |
| |
| createEnemy(500, 60); |
| createEnemy(800, 60); |
| |
| |
| castle = createCastle(1200); |
| } |
| |
| |
| function jump() { |
| if (!isJumping && gameRunning && isAlive && !levelComplete) { |
| isJumping = true; |
| marioVelocityY = jumpForce; |
| mario.classList.add('jumping'); |
| |
| |
| setTimeout(() => { |
| mario.classList.remove('jumping'); |
| }, 500); |
| } |
| } |
| |
| |
| function crouch() { |
| if (!isJumping && gameRunning && isAlive && !levelComplete) { |
| isCrouching = true; |
| mario.classList.add('crouching'); |
| } |
| } |
| |
| |
| function stopCrouch() { |
| if (isCrouching) { |
| isCrouching = false; |
| mario.classList.remove('crouching'); |
| } |
| } |
| |
| |
| function slide() { |
| if (!isSliding && gameRunning && isAlive && !levelComplete) { |
| isSliding = true; |
| mario.classList.add('sliding'); |
| |
| setTimeout(() => { |
| isSliding = false; |
| mario.classList.remove('sliding'); |
| }, 200); |
| } |
| } |
| |
| |
| function checkCollisions() { |
| |
| const marioLeft = marioPositionX + 5; |
| const marioRight = marioPositionX + 35; |
| const marioTop = marioPositionY + 50; |
| const marioBottom = marioPositionY + 10; |
| |
| |
| if (marioPositionY <= 60) { |
| marioPositionY = 60; |
| marioVelocityY = 0; |
| isJumping = false; |
| } |
| |
| |
| for (const brick of bricks) { |
| const brickLeft = brick.x; |
| const brickRight = brick.x + 40; |
| const brickTop = brick.y + 40; |
| const brickBottom = brick.y; |
| |
| |
| if (marioRight > brickLeft && |
| marioLeft < brickRight && |
| marioBottom < brickTop && |
| marioTop > brickBottom && |
| marioVelocityY > 0) { |
| |
| marioPositionY = brickBottom - 60; |
| marioVelocityY = 0; |
| isJumping = false; |
| |
| if (!brick.hit && brick.hasCoin) { |
| |
| score += 100; |
| scoreDisplay.textContent = `SCORE: ${score}`; |
| brick.hit = true; |
| brick.element.classList.add('hit'); |
| |
| |
| for (const coin of coins) { |
| if (coin.x === brick.x + 10 && coin.y === brick.y + 45 && !coin.collected) { |
| coin.collected = true; |
| coin.element.style.display = 'none'; |
| |
| |
| const effect = document.createElement('div'); |
| effect.className = 'coin'; |
| effect.style.left = (brick.x + 10) + 'px'; |
| effect.style.bottom = (brick.y + 45) + 'px'; |
| gameContainer.appendChild(effect); |
| |
| |
| let effectY = brick.y + 45; |
| let effectVelocity = -10; |
| |
| const animateCoin = () => { |
| effectY += effectVelocity; |
| effectVelocity += 0.5; |
| effect.style.bottom = effectY + 'px'; |
| |
| if (effectY < brick.y + 45 - 100 || effectY > brick.y + 45) { |
| effect.remove(); |
| } else { |
| requestAnimationFrame(animateCoin); |
| } |
| }; |
| |
| animateCoin(); |
| } |
| } |
| } |
| } |
| } |
| |
| |
| for (const pipe of pipes) { |
| const pipeLeft = pipe.x; |
| const pipeRight = pipe.x + 60; |
| const pipeHeight = pipe.height; |
| |
| if (marioRight > pipeLeft && |
| marioLeft < pipeRight && |
| marioPositionY < pipeHeight) { |
| |
| |
| if (marioDirection === 'right') { |
| marioPositionX = pipeLeft - 40; |
| } else { |
| marioPositionX = pipeRight + 5; |
| } |
| } |
| } |
| |
| |
| if (!isInvincible) { |
| for (const enemy of enemies) { |
| const enemyLeft = enemy.x; |
| const enemyRight = enemy.x + 40; |
| const enemyTop = enemy.y + 40; |
| const enemyBottom = enemy.y; |
| |
| |
| if (marioRight > enemyLeft && |
| marioLeft < enemyRight && |
| marioBottom < enemyTop && |
| marioTop > enemyBottom) { |
| |
| |
| if (marioVelocityY > 0 && marioBottom < enemyTop + 20) { |
| enemy.element.remove(); |
| enemies = enemies.filter(e => e !== enemy); |
| score += 200; |
| scoreDisplay.textContent = `SCORE: ${score}`; |
| |
| |
| marioVelocityY = jumpForce / 2; |
| isJumping = true; |
| } else { |
| |
| getHurt(); |
| } |
| } |
| } |
| } |
| |
| |
| for (const coin of coins) { |
| if (!coin.collected) { |
| const coinLeft = coin.x; |
| const coinRight = coin.x + 20; |
| const coinTop = coin.y + 20; |
| const coinBottom = coin.y; |
| |
| if (marioRight > coinLeft && |
| marioLeft < coinRight && |
| marioBottom < coinTop && |
| marioTop > coinBottom) { |
| |
| coin.collected = true; |
| coin.element.remove(); |
| score += 100; |
| scoreDisplay.textContent = `SCORE: ${score}`; |
| } |
| } |
| } |
| |
| |
| if (castle) { |
| const castleLeft = castle.x; |
| const castleRight = castle.x + 80; |
| |
| if (marioRight > castleLeft && marioLeft < castleRight) { |
| completeLevel(); |
| } |
| } |
| } |
| |
| |
| function getHurt() { |
| if (!isInvincible) { |
| isInvincible = true; |
| isAlive = false; |
| |
| |
| marioVelocityY = -10; |
| |
| |
| mario.classList.add('small'); |
| |
| setTimeout(() => { |
| gameOver(); |
| }, 1000); |
| } |
| } |
| |
| |
| function completeLevel() { |
| levelComplete = true; |
| gameRunning = false; |
| |
| |
| clearInterval(timeInterval); |
| cancelAnimationFrame(gameLoopId); |
| |
| |
| const timeBonus = Math.floor(time / 10) * 50; |
| score += timeBonus; |
| |
| |
| if (score > highScore) { |
| highScore = score; |
| localStorage.setItem('marioHighScore', highScore); |
| } |
| |
| winScoreDisplay.textContent = score; |
| winHighScoreDisplay.textContent = highScore; |
| |
| |
| winScreen.style.display = 'flex'; |
| |
| |
| createFireworks(); |
| } |
| |
| |
| function createFireworks() { |
| const colors = ['#ff0000', '#ff9900', '#ffff00', '#33cc33', '#3399ff', '#cc66ff']; |
| |
| for (let i = 0; i < 10; i++) { |
| setTimeout(() => { |
| const x = Math.random() * window.innerWidth; |
| const y = Math.random() * window.innerHeight / 2; |
| const color = colors[Math.floor(Math.random() * colors.length)]; |
| |
| const firework = document.createElement('div'); |
| firework.style.position = 'absolute'; |
| firework.style.left = x + 'px'; |
| firework.style.top = y + 'px'; |
| firework.style.width = '5px'; |
| firework.style.height = '5px'; |
| firework.style.backgroundColor = color; |
| firework.style.borderRadius = '50%'; |
| firework.style.zIndex = '5'; |
| gameContainer.appendChild(firework); |
| |
| |
| let particles = []; |
| for (let j = 0; j < 20; j++) { |
| const particle = document.createElement('div'); |
| particle.style.position = 'absolute'; |
| particle.style.left = x + 'px'; |
| particle.style.top = y + 'px'; |
| particle.style.width = '3px'; |
| particle.style.height = '3px'; |
| particle.style.backgroundColor = color; |
| particle.style.borderRadius = '50%'; |
| particle.style.zIndex = '5'; |
| gameContainer.appendChild(particle); |
| |
| particles.push({ |
| element: particle, |
| velocityX: (Math.random() - 0.5) * 8, |
| velocityY: (Math.random() - 0.5) * 8 |
| }); |
| } |
| |
| |
| const animateParticles = () => { |
| let allOut = true; |
| |
| for (const particle of particles) { |
| const rect = particle.element.getBoundingClientRect(); |
| |
| |
| const currentLeft = parseFloat(particle.element.style.left); |
| const currentTop = parseFloat(particle.element.style.top); |
| |
| particle.element.style.left = (currentLeft + particle.velocityX) + 'px'; |
| particle.element.style.top = (currentTop + particle.velocityY) + 'px'; |
| |
| |
| particle.velocityY += 0.2; |
| |
| |
| const currentOpacity = parseFloat(particle.element.style.opacity || 1); |
| particle.element.style.opacity = (currentOpacity - 0.03) + ''; |
| |
| |
| if (currentOpacity > 0 && |
| currentTop < window.innerHeight && |
| currentLeft < window.innerWidth && |
| currentLeft > 0) { |
| allOut = false; |
| } |
| } |
| |
| if (!allOut) { |
| requestAnimationFrame(animateParticles); |
| } else { |
| |
| firework.remove(); |
| for (const particle of particles) { |
| particle.element.remove(); |
| } |
| } |
| }; |
| |
| animateParticles(); |
| |
| }, i * 300); |
| } |
| } |
| |
| |
| function gameOver() { |
| gameRunning = false; |
| isAlive = false; |
| |
| |
| clearInterval(timeInterval); |
| cancelAnimationFrame(gameLoopId); |
| |
| |
| if (score > highScore) { |
| highScore = score; |
| localStorage.setItem('marioHighScore', highScore); |
| highScoreDisplay.textContent = highScore; |
| } |
| |
| finalScoreDisplay.textContent = score; |
| |
| |
| gameOverScreen.style.display = 'flex'; |
| } |
| |
| |
| function startTimer() { |
| time = 300; |
| timeDisplay.textContent = `TIME: ${time}`; |
| |
| timeInterval = setInterval(() => { |
| if (gameRunning) { |
| time--; |
| timeDisplay.textContent = `TIME: ${time}`; |
| |
| if (time <= 0) { |
| gameOver(); |
| } |
| } |
| }, 1000); |
| } |
| |
| |
| function gameLoop(timestamp) { |
| if (!gameRunning || !isAlive || levelComplete) return; |
| |
| |
| const deltaTime = timestamp - lastTime; |
| lastTime = timestamp; |
| |
| |
| if (rightPressed && !levelComplete) { |
| marioDirection = 'right'; |
| marioPositionX += gameSpeed; |
| |
| |
| if (marioPositionX > window.innerWidth / 3) { |
| cameraOffset = marioPositionX - window.innerWidth / 3; |
| } |
| } else if (leftPressed && marioPositionX > 0 && !levelComplete) { |
| marioDirection = 'left'; |
| marioPositionX -= gameSpeed; |
| |
| |
| if (marioPositionX < cameraOffset) { |
| marioPositionX = cameraOffset; |
| } |
| } |
| |
| |
| marioVelocityY += gravity; |
| marioPositionY += marioVelocityY; |
| |
| |
| mario.style.left = (marioPositionX - cameraOffset) + 'px'; |
| mario.style.bottom = marioPositionY + 'px'; |
| |
| |
| if (marioDirection === 'left') { |
| mario.style.transform = 'scaleX(-1)'; |
| } else { |
| mario.style.transform = 'scaleX(1)'; |
| } |
| |
| |
| for (const enemy of enemies) { |
| enemy.x += enemy.speed * enemy.direction; |
| enemy.element.style.left = (enemy.x - cameraOffset) + 'px'; |
| |
| |
| if (enemy.x - cameraOffset < 0 || enemy.x - cameraOffset > window.innerWidth - 40) { |
| enemy.direction *= -1; |
| } |
| |
| |
| let hasGround = false; |
| |
| |
| if (enemy.y === 60) { |
| hasGround = true; |
| } else { |
| |
| for (const brick of bricks) { |
| const brickLeft = brick.x; |
| const brickRight = brick.x + 40; |
| const brickTop = brick.y + 40; |
| |
| if (enemy.x + 20 > brickLeft && |
| enemy.x + 20 < brickRight && |
| enemy.y + 40 >= brickTop && |
| enemy.y + 40 <= brickTop + 20) { |
| hasGround = true; |
| break; |
| } |
| } |
| } |
| |
| if (!hasGround) { |
| enemy.direction *= -1; |
| } |
| } |
| |
| |
| for (const cloud of clouds) { |
| cloud.x -= 0.5; |
| cloud.element.style.left = (cloud.x - cameraOffset) + 'px'; |
| |
| |
| if (cloud.x - cameraOffset < -cloud.size) { |
| cloud.x = window.innerWidth + cameraOffset; |
| } |
| } |
| |
| |
| ground.style.transform = `translateX(-${cameraOffset * 0.7}px)`; |
| |
| |
| checkCollisions(); |
| |
| |
| gameLoopId = requestAnimationFrame(gameLoop); |
| } |
| |
| |
| let rightPressed = false; |
| let leftPressed = false; |
| let downPressed = false; |
| |
| document.addEventListener('keydown', (e) => { |
| if (!gameRunning) return; |
| |
| switch (e.key) { |
| case 'ArrowRight': |
| rightPressed = true; |
| break; |
| case 'ArrowLeft': |
| leftPressed = true; |
| break; |
| case 'ArrowDown': |
| downPressed = true; |
| crouch(); |
| break; |
| case ' ': |
| jump(); |
| break; |
| } |
| }); |
| |
| document.addEventListener('keyup', (e) => { |
| switch (e.key) { |
| case 'ArrowRight': |
| rightPressed = false; |
| break; |
| case 'ArrowLeft': |
| leftPressed = false; |
| break; |
| case 'ArrowDown': |
| downPressed = false; |
| stopCrouch(); |
| break; |
| case ' ': |
| |
| break; |
| } |
| }); |
| |
| |
| let touchStartX = 0; |
| |
| document.addEventListener('touchstart', (e) => { |
| if (!gameRunning) return; |
| |
| touchStartX = e.touches[0].clientX; |
| |
| |
| if (e.touches[0].clientY > window.innerHeight / 2) { |
| jump(); |
| } |
| }); |
| |
| document.addEventListener('touchmove', (e) => { |
| if (!gameRunning) return; |
| |
| const touchX = e.touches[0].clientX; |
| const diff = touchX - touchStartX; |
| |
| if (Math.abs(diff) > 10) { |
| if (diff > 0) { |
| |
| rightPressed = true; |
| leftPressed = false; |
| } else { |
| |
| leftPressed = true; |
| rightPressed = false; |
| } |
| } |
| }); |
| |
| document.addEventListener('touchend', () => { |
| rightPressed = false; |
| leftPressed = false; |
| }); |
| |
| |
| document.addEventListener('click', (e) => { |
| if (!gameRunning && (e.target === startBtn || e.target === restartBtn || e.target === winRestartBtn)) { |
| return; |
| } |
| |
| if (gameRunning && isAlive && !levelComplete && e.clientY > window.innerHeight / 2) { |
| jump(); |
| } |
| }); |
| |
| |
| startBtn.addEventListener('click', () => { |
| startScreen.style.display = 'none'; |
| startGame(); |
| }); |
| |
| restartBtn.addEventListener('click', startGame); |
| winRestartBtn.addEventListener('click', startGame); |
| |
| |
| function startGame() { |
| |
| gameRunning = true; |
| isAlive = true; |
| levelComplete = false; |
| score = 0; |
| time = 300; |
| marioPositionX = 100; |
| marioPositionY = 300; |
| marioVelocityY = 0; |
| cameraOffset = 0; |
| rightPressed = false; |
| leftPressed = false; |
| downPressed = false; |
| |
| |
| scoreDisplay.textContent = `SCORE: ${score}`; |
| timeDisplay.textContent = `TIME: ${time}`; |
| |
| |
| startScreen.style.display = 'none'; |
| gameOverScreen.style.display = 'none'; |
| winScreen.style.display = 'none'; |
| |
| |
| const existingMario = document.querySelector('.mario'); |
| if (existingMario) existingMario.remove(); |
| |
| |
| createMario(); |
| createGround(); |
| setupLevel(); |
| |
| |
| clearInterval(timeInterval); |
| startTimer(); |
| |
| |
| lastTime = performance.now(); |
| gameLoopId = requestAnimationFrame(gameLoop); |
| } |
| |
| |
| startScreen.style.display = 'flex'; |
| }); |
| </script> |
| <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - <a href="https://enzostvs-deepsite.hf.space?remix=Assad3l/alda" style="color: #fff;text-decoration: underline;" target="_blank" >🧬 Remix</a></p></body> |
| </html> |