alda / index.html
Assad3l's picture
Add 2 files
f4912e5 verified
<!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;
// Create Mario
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);
}
// Create ground
function createGround() {
ground = document.querySelector('.ground');
}
// Create enemies
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
});
}
// Create coins
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
});
}
// Create bricks
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);
}
}
// Create pipes
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
});
}
// Create clouds
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
});
}
// Create castle
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
};
}
// Setup level
function setupLevel() {
// Clear existing elements
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();
// Reset arrays
enemies = [];
coins = [];
bricks = [];
pipes = [];
clouds = [];
castle = null;
// Create game objects
// Ground is already created in HTML
// Clouds
createCloud(200, 400, 80);
createCloud(500, 350, 100);
createCloud(800, 450, 60);
// Bricks and coins
for (let i = 0; i < 5; i++) {
createBrick(300 + i * 50, 100, i % 2 === 0);
}
// Some standalone coins
createCoin(200, 150);
createCoin(250, 200);
createCoin(700, 150);
// Pipes
createPipe(400, 60, 100);
createPipe(600, 60, 80);
// Enemies
createEnemy(500, 60);
createEnemy(800, 60);
// Castle at the end
castle = createCastle(1200);
}
// Jump function
function jump() {
if (!isJumping && gameRunning && isAlive && !levelComplete) {
isJumping = true;
marioVelocityY = jumpForce;
mario.classList.add('jumping');
// Remove jumping class after animation
setTimeout(() => {
mario.classList.remove('jumping');
}, 500);
}
}
// Crouch function
function crouch() {
if (!isJumping && gameRunning && isAlive && !levelComplete) {
isCrouching = true;
mario.classList.add('crouching');
}
}
// Stop crouching
function stopCrouch() {
if (isCrouching) {
isCrouching = false;
mario.classList.remove('crouching');
}
}
// Slide function
function slide() {
if (!isSliding && gameRunning && isAlive && !levelComplete) {
isSliding = true;
mario.classList.add('sliding');
setTimeout(() => {
isSliding = false;
mario.classList.remove('sliding');
}, 200);
}
}
// Check collisions
function checkCollisions() {
// Mario's hitbox
const marioLeft = marioPositionX + 5;
const marioRight = marioPositionX + 35;
const marioTop = marioPositionY + 50;
const marioBottom = marioPositionY + 10;
// Ground collision
if (marioPositionY <= 60) {
marioPositionY = 60;
marioVelocityY = 0;
isJumping = false;
}
// Brick collisions
for (const brick of bricks) {
const brickLeft = brick.x;
const brickRight = brick.x + 40;
const brickTop = brick.y + 40;
const brickBottom = brick.y;
// Check if Mario is hitting the brick from below
if (marioRight > brickLeft &&
marioLeft < brickRight &&
marioBottom < brickTop &&
marioTop > brickBottom &&
marioVelocityY > 0) {
marioPositionY = brickBottom - 60;
marioVelocityY = 0;
isJumping = false;
if (!brick.hit && brick.hasCoin) {
// Hit a brick with coin
score += 100;
scoreDisplay.textContent = `SCORE: ${score}`;
brick.hit = true;
brick.element.classList.add('hit');
// Make coin jump out
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';
// Show collected effect
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);
// Animate coin
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();
}
}
}
}
}
// Pipe collisions (stop walking through pipes)
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) {
// Stop Mario from moving left/right through pipe
if (marioDirection === 'right') {
marioPositionX = pipeLeft - 40;
} else {
marioPositionX = pipeRight + 5;
}
}
}
// Enemy collisions
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;
// Check if Mario is landing on enemy
if (marioRight > enemyLeft &&
marioLeft < enemyRight &&
marioBottom < enemyTop &&
marioTop > enemyBottom) {
// If Mario is falling onto enemy from above
if (marioVelocityY > 0 && marioBottom < enemyTop + 20) {
enemy.element.remove();
enemies = enemies.filter(e => e !== enemy);
score += 200;
scoreDisplay.textContent = `SCORE: ${score}`;
// Bounce after stomping
marioVelocityY = jumpForce / 2;
isJumping = true;
} else {
// Mario gets hit by enemy
getHurt();
}
}
}
}
// Coin collection
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}`;
}
}
}
// Castle collision (level complete)
if (castle) {
const castleLeft = castle.x;
const castleRight = castle.x + 80;
if (marioRight > castleLeft && marioLeft < castleRight) {
completeLevel();
}
}
}
// Get hurt function
function getHurt() {
if (!isInvincible) {
isInvincible = true;
isAlive = false;
// Make Mario jump back
marioVelocityY = -10;
// Show hurt animation
mario.classList.add('small');
setTimeout(() => {
gameOver();
}, 1000);
}
}
// Complete level function
function completeLevel() {
levelComplete = true;
gameRunning = false;
// Stop timers
clearInterval(timeInterval);
cancelAnimationFrame(gameLoopId);
// Calculate final score (bonus for time remaining)
const timeBonus = Math.floor(time / 10) * 50;
score += timeBonus;
// Update high score
if (score > highScore) {
highScore = score;
localStorage.setItem('marioHighScore', highScore);
}
winScoreDisplay.textContent = score;
winHighScoreDisplay.textContent = highScore;
// Show win screen
winScreen.style.display = 'flex';
// Fireworks celebration
createFireworks();
}
// Create fireworks effect
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);
// Animate 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
});
}
// Animate particles
const animateParticles = () => {
let allOut = true;
for (const particle of particles) {
const rect = particle.element.getBoundingClientRect();
// Update position
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';
// Add gravity
particle.velocityY += 0.2;
// Fade out
const currentOpacity = parseFloat(particle.element.style.opacity || 1);
particle.element.style.opacity = (currentOpacity - 0.03) + '';
// Check if still visible
if (currentOpacity > 0 &&
currentTop < window.innerHeight &&
currentLeft < window.innerWidth &&
currentLeft > 0) {
allOut = false;
}
}
if (!allOut) {
requestAnimationFrame(animateParticles);
} else {
// Remove particles
firework.remove();
for (const particle of particles) {
particle.element.remove();
}
}
};
animateParticles();
}, i * 300);
}
}
// Game over function
function gameOver() {
gameRunning = false;
isAlive = false;
// Stop timers
clearInterval(timeInterval);
cancelAnimationFrame(gameLoopId);
// Update high score
if (score > highScore) {
highScore = score;
localStorage.setItem('marioHighScore', highScore);
highScoreDisplay.textContent = highScore;
}
finalScoreDisplay.textContent = score;
// Show game over screen
gameOverScreen.style.display = 'flex';
}
// Timer countdown
function startTimer() {
time = 300;
timeDisplay.textContent = `TIME: ${time}`;
timeInterval = setInterval(() => {
if (gameRunning) {
time--;
timeDisplay.textContent = `TIME: ${time}`;
if (time <= 0) {
gameOver();
}
}
}, 1000);
}
// Game loop
function gameLoop(timestamp) {
if (!gameRunning || !isAlive || levelComplete) return;
// Calculate delta time for smooth movement
const deltaTime = timestamp - lastTime;
lastTime = timestamp;
// Move Mario horizontally if arrow keys are pressed
if (rightPressed && !levelComplete) {
marioDirection = 'right';
marioPositionX += gameSpeed;
// Camera follows Mario
if (marioPositionX > window.innerWidth / 3) {
cameraOffset = marioPositionX - window.innerWidth / 3;
}
} else if (leftPressed && marioPositionX > 0 && !levelComplete) {
marioDirection = 'left';
marioPositionX -= gameSpeed;
// Don't let Mario go back beyond camera
if (marioPositionX < cameraOffset) {
marioPositionX = cameraOffset;
}
}
// Apply gravity
marioVelocityY += gravity;
marioPositionY += marioVelocityY;
// Update Mario's position
mario.style.left = (marioPositionX - cameraOffset) + 'px';
mario.style.bottom = marioPositionY + 'px';
// Flip Mario based on direction
if (marioDirection === 'left') {
mario.style.transform = 'scaleX(-1)';
} else {
mario.style.transform = 'scaleX(1)';
}
// Move enemies
for (const enemy of enemies) {
enemy.x += enemy.speed * enemy.direction;
enemy.element.style.left = (enemy.x - cameraOffset) + 'px';
// Simple AI - turn around at edges or when hitting another enemy
if (enemy.x - cameraOffset < 0 || enemy.x - cameraOffset > window.innerWidth - 40) {
enemy.direction *= -1;
}
// Check if enemy falls off platform
let hasGround = false;
// Check if there's ground below
if (enemy.y === 60) {
hasGround = true;
} else {
// Check if standing on brick
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;
}
}
// Move clouds
for (const cloud of clouds) {
cloud.x -= 0.5;
cloud.element.style.left = (cloud.x - cameraOffset) + 'px';
// Reset cloud when off screen
if (cloud.x - cameraOffset < -cloud.size) {
cloud.x = window.innerWidth + cameraOffset;
}
}
// Move ground (parallax effect)
ground.style.transform = `translateX(-${cameraOffset * 0.7}px)`;
// Check collisions
checkCollisions();
// Continue loop
gameLoopId = requestAnimationFrame(gameLoop);
}
// Event listeners
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 ' ':
// Space key release - nothing needed
break;
}
});
// Touch controls for mobile
let touchStartX = 0;
document.addEventListener('touchstart', (e) => {
if (!gameRunning) return;
touchStartX = e.touches[0].clientX;
// If touch is in lower half of screen, treat as jump
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) {
// Swipe right
rightPressed = true;
leftPressed = false;
} else {
// Swipe left
leftPressed = true;
rightPressed = false;
}
}
});
document.addEventListener('touchend', () => {
rightPressed = false;
leftPressed = false;
});
// Click/tap to jump on mobile
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();
}
});
// Start game buttons
startBtn.addEventListener('click', () => {
startScreen.style.display = 'none';
startGame();
});
restartBtn.addEventListener('click', startGame);
winRestartBtn.addEventListener('click', startGame);
// Start game function
function startGame() {
// Reset game state
gameRunning = true;
isAlive = true;
levelComplete = false;
score = 0;
time = 300;
marioPositionX = 100;
marioPositionY = 300;
marioVelocityY = 0;
cameraOffset = 0;
rightPressed = false;
leftPressed = false;
downPressed = false;
// Update displays
scoreDisplay.textContent = `SCORE: ${score}`;
timeDisplay.textContent = `TIME: ${time}`;
// Hide screens
startScreen.style.display = 'none';
gameOverScreen.style.display = 'none';
winScreen.style.display = 'none';
// Clear existing Mario
const existingMario = document.querySelector('.mario');
if (existingMario) existingMario.remove();
// Create game elements
createMario();
createGround();
setupLevel();
// Start timer
clearInterval(timeInterval);
startTimer();
// Start game loop
lastTime = performance.now();
gameLoopId = requestAnimationFrame(gameLoop);
}
// Initialize game
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>