Spaces:
Running
Running
<html lang="es"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>Sun Runner - Escape del Sol</title> | |
<script src="https://cdn.tailwindcss.com"></script> | |
<style> | |
#gameCanvas { | |
background-color: #87CEEB; | |
border: 4px solid #1E3A8A; | |
border-radius: 8px; | |
box-shadow: 0 0 20px rgba(0, 0, 0, 0.3); | |
} | |
.sun { | |
background: radial-gradient(circle at 30% 30%, #FDB813, #FDB813 30%, #FCAF17 40%, #F6961E 60%, #E46B2C); | |
box-shadow: 0 0 100px #FDB813; | |
} | |
.jump-animation { | |
animation: jump 0.5s ease-out; | |
} | |
@keyframes jump { | |
0% { transform: translateY(0); } | |
50% { transform: translateY(-100px); } | |
100% { transform: translateY(0); } | |
} | |
.game-over { | |
animation: shake 0.5s cubic-bezier(.36,.07,.19,.97) both; | |
} | |
@keyframes shake { | |
10%, 90% { transform: translate3d(-1px, 0, 0); } | |
20%, 80% { transform: translate3d(2px, 0, 0); } | |
30%, 50%, 70% { transform: translate3d(-4px, 0, 0); } | |
40%, 60% { transform: translate3d(4px, 0, 0); } | |
} | |
.cloud { | |
background: radial-gradient(circle at 30% 30%, white, white 80%, rgba(255,255,255,0.8) 100%); | |
border-radius: 50%; | |
} | |
.parallax { | |
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="100" height="20" viewBox="0 0 100 20"><path d="M0,10 C20,15 30,5 50,10 S80,5 100,10" fill="none" stroke="%23FFFFFF" stroke-width="1"/></svg>'); | |
opacity: 0.3; | |
} | |
</style> | |
</head> | |
<body class="bg-gray-900 h-screen flex flex-col items-center justify-center font-mono overflow-hidden"> | |
<div class="absolute top-0 w-full h-16 bg-gradient-to-b from-gray-900 to-transparent z-10"></div> | |
<h1 class="text-4xl font-bold mb-4 text-white tracking-wider">SUN RUNNER</h1> | |
<h2 class="text-xl text-yellow-200 mb-4">Escapa del sol poniente</h2> | |
<div class="relative"> | |
<div id="sun" class="sun absolute rounded-full w-24 h-24 -top-12 -right-12 z-20"></div> | |
<!-- Menú principal --> | |
<div id="mainMenu" class="absolute inset-0 flex flex-col items-center justify-center bg-black bg-opacity-70 z-30 transition-opacity duration-500"> | |
<div class="bg-gray-800 p-8 rounded-lg max-w-md w-full text-center"> | |
<h3 class="text-2xl text-yellow-300 font-bold mb-4">Instrucciones</h3> | |
<p class="text-gray-200 mb-6">¡El sol se está poniendo y te está alcanzando! Corre hacia la derecha evitando los obstáculos.</p> | |
<p class="text-gray-300 mb-6"><span class="font-bold text-yellow-300">Controles:</span><br>SPACE para saltar<br>También puedes hacer click/tocar la pantalla</p> | |
<p class="text-sm text-gray-400 mb-6"> | |
<span id="highScoreDisplay" class="block text-yellow-200">Mejor puntuación: 0</span> | |
</p> | |
<button id="startButton" class="bg-yellow-500 hover:bg-yellow-400 text-gray-900 font-bold py-3 px-6 rounded-full transition-all transform hover:scale-105 focus:outline-none"> | |
¡Comenzar! | |
</button> | |
</div> | |
</div> | |
<!-- Pantalla de Game Over --> | |
<div id="gameOverMenu" class="absolute inset-0 flex flex-col items-center justify-center bg-black bg-opacity-70 z-30 hidden"> | |
<div class="bg-gray-800 p-8 rounded-lg max-w-md w-full text-center"> | |
<h3 class="text-2xl text-red-400 font-bold mb-4">¡Has sido alcanzado!</h3> | |
<p class="text-4xl text-yellow-200 font-bold mb-6" id="scoreDisplay">0</p> | |
<p class="text-gray-300 mb-6">¡Inténtalo de nuevo para mejorar tu puntuación!</p> | |
<button id="restartButton" class="bg-yellow-500 hover:bg-yellow-400 text-gray-900 font-bold py-3 px-6 rounded-full transition-all transform hover:scale-105 focus:outline-none"> | |
Reintentar | |
</button> | |
</div> | |
</div> | |
<canvas id="gameCanvas" width="800" height="400" class="relative z-10"></canvas> | |
<!-- Nubes de fondo --> | |
<div class="absolute top-20 left-20 cloud w-32 h-16 opacity-70"></div> | |
<div class="absolute top-40 right-40 cloud w-24 h-12 opacity-60"></div> | |
<div class="absolute top-80 left-40 cloud w-20 h-10 opacity-50"></div> | |
</div> | |
<div class="absolute bottom-0 w-full h-16 bg-gradient-to-t from-gray-900 to-transparent z-10"></div> | |
<script> | |
document.addEventListener('DOMContentLoaded', () => { | |
const canvas = document.getElementById('gameCanvas'); | |
const ctx = canvas.getContext('2d'); | |
const startButton = document.getElementById('startButton'); | |
const restartButton = document.getElementById('restartButton'); | |
const mainMenu = document.getElementById('mainMenu'); | |
const gameOverMenu = document.getElementById('gameOverMenu'); | |
const scoreDisplay = document.getElementById('scoreDisplay'); | |
const highScoreDisplay = document.getElementById('highScoreDisplay'); | |
const sunElement = document.getElementById('sun'); | |
// Variables del juego | |
let gameRunning = false; | |
let score = 0; | |
let highScore = localStorage.getItem('highScore') || 0; | |
let animationFrameId; | |
let gameSpeed = 5; | |
let sunSpeed = 2; | |
let obstacles = []; | |
let clouds = []; | |
let groundHeight = 50; | |
let parallaxOffset = 0; | |
// Posición del personaje | |
const player = { | |
x: 100, | |
y: canvas.height - groundHeight - 50, | |
width: 40, | |
height: 50, | |
velocityY: 0, | |
jumping: false, | |
jumpPower: 15, | |
gravity: 0.7 | |
}; | |
// Actualizar la mejor puntuación mostrada | |
highScoreDisplay.textContent = `Mejor puntuación: ${highScore}`; | |
// Configurar el personaje del juego | |
function drawPlayer() { | |
ctx.fillStyle = '#4B5563'; | |
ctx.fillRect(player.x, player.y - 30, player.width, 10); // Sombrero | |
ctx.fillStyle = '#1E40AF'; | |
ctx.fillRect(player.x, player.y - 20, player.width, player.height); // Cuerpo | |
ctx.fillStyle = '#9CA3AF'; | |
ctx.fillRect(player.x + 10, player.y, 5, 10); // Pierna izquierda | |
ctx.fillRect(player.x + 25, player.y, 5, 10); // Pierna derecha | |
ctx.fillStyle = '#F59E0B'; | |
ctx.fillRect(player.x + 15, player.y + 10, 10, 5); // Cinturón | |
} | |
// Dibujar el terreno | |
function drawGround() { | |
// Suelo principal | |
ctx.fillStyle = '#374151'; | |
ctx.fillRect(0, canvas.height - groundHeight, canvas.width, groundHeight); | |
// Detalles del terreno | |
ctx.fillStyle = '#1F2937'; | |
for (let i = 0; i < canvas.width; i += 50) { | |
ctx.fillRect(i, canvas.height - groundHeight, 30, 5); | |
} | |
// Efecto parallax | |
ctx.save(); | |
ctx.translate(-parallaxOffset % 100, 0); | |
for (let i = -100; i < canvas.width + 100; i += 100) { | |
ctx.fillStyle = '#1E293B'; | |
ctx.beginPath(); | |
ctx.moveTo(i, canvas.height - groundHeight); | |
ctx.bezierCurveTo(i + 25, canvas.height - groundHeight - 10, | |
i + 75, canvas.height - groundHeight + 5, | |
i + 100, canvas.height - groundHeight); | |
ctx.fill(); | |
} | |
ctx.restore(); | |
} | |
// Generar obstáculos | |
function generateObstacle() { | |
if (Math.random() < 0.02 && obstacles.length < 3) { | |
const types = ['rock', 'cactus']; | |
const type = types[Math.floor(Math.random() * types.length)]; | |
const height = type === 'rock' ? 30 : 50; | |
obstacles.push({ | |
x: canvas.width, | |
y: canvas.height - groundHeight - height, | |
width: type === 'rock' ? 50 : 30, | |
height: height, | |
type: type | |
}); | |
} | |
} | |
// Dibujar obstáculos | |
function drawObstacles() { | |
obstacles.forEach(obstacle => { | |
if (obstacle.type === 'rock') { | |
ctx.fillStyle = '#6B7280'; | |
ctx.beginPath(); | |
ctx.arc(obstacle.x + 25, obstacle.y + 25, 25, 0, Math.PI * 2); | |
ctx.fill(); | |
} else { // cactus | |
ctx.fillStyle = '#10B981'; | |
ctx.fillRect(obstacle.x, obstacle.y, obstacle.width, obstacle.height); | |
ctx.fillRect(obstacle.x - 5, obstacle.y, 10, obstacle.height * 0.7); | |
ctx.fillRect(obstacle.x + obstacle.width - 5, obstacle.y, 10, obstacle.height * 0.5); | |
} | |
}); | |
} | |
// Mover y eliminar obstáculos | |
function updateObstacles() { | |
for (let i = obstacles.length - 1; i >= 0; i--) { | |
obstacles[i].x -= gameSpeed; | |
// Eliminar obstáculos fuera de la pantalla | |
if (obstacles[i].x + obstacles[i].width < 0) { | |
obstacles.splice(i, 1); | |
score += 10; | |
} | |
// Detección de colisiones | |
if (player.x < obstacles[i].x + obstacles[i].width && | |
player.x + player.width > obstacles[i].x && | |
player.y < obstacles[i].y + obstacles[i].height && | |
player.y + player.height > obstacles[i].y) { | |
gameOver(); | |
} | |
} | |
} | |
// Generar nubes de fondo | |
function generateClouds() { | |
if (Math.random() < 0.01 && clouds.length < 5) { | |
clouds.push({ | |
x: canvas.width, | |
y: Math.random() * (canvas.height / 3), | |
width: 60 + Math.random() * 60, | |
speed: 1 + Math.random() * 2 | |
}); | |
} | |
} | |
// Dibujar nubes | |
function drawClouds() { | |
clouds.forEach(cloud => { | |
ctx.fillStyle = 'rgba(255, 255, 255, 0.7)'; | |
ctx.beginPath(); | |
ctx.arc(cloud.x + cloud.width * 0.3, cloud.y + cloud.width * 0.1, cloud.width * 0.2, 0, Math.PI * 2); | |
ctx.arc(cloud.x + cloud.width * 0.6, cloud.y + cloud.width * 0.1, cloud.width * 0.3, 0, Math.PI * 2); | |
ctx.arc(cloud.x + cloud.width * 0.2, cloud.y + cloud.width * 0.2, cloud.width * 0.2, 0, Math.PI * 2); | |
ctx.fill(); | |
}); | |
} | |
// Mover y eliminar nubes | |
function updateClouds() { | |
for (let i = clouds.length - 1; i >= 0; i--) { | |
clouds[i].x -= clouds[i].speed; | |
if (clouds[i].x + clouds[i].width * 1.5 < 0) { | |
clouds.splice(i, 1); | |
} | |
} | |
} | |
// Actualizar posición del jugador y gravedad | |
function updatePlayer() { | |
// Gravedad | |
player.velocityY += player.gravity; | |
player.y += player.velocityY; | |
// Limitar al suelo | |
if (player.y >= canvas.height - groundHeight - player.height) { | |
player.y = canvas.height - groundHeight - player.height; | |
player.velocityY = 0; | |
player.jumping = false; | |
} | |
} | |
// Hacer que el jugador salte | |
function jump() { | |
if (!player.jumping) { | |
player.velocityY = -player.jumpPower; | |
player.jumping = true; | |
document.getElementById('gameCanvas').classList.add('jump-animation'); | |
setTimeout(() => { | |
document.getElementById('gameCanvas').classList.remove('jump-animation'); | |
}, 500); | |
} | |
} | |
// Actualizar la posición del sol | |
function updateSunPosition() { | |
const sunX = -30 + (canvas.width - player.x) * 0.3; | |
const sunY = -30 + (canvas.height - player.y) * 0.1; | |
sunElement.style.transform = `translate(${sunX}px, ${sunY}px)`; | |
// Comprobar si el sol alcanzó al jugador | |
if (player.x < 50) { | |
gameOver(); | |
} | |
} | |
// Actualizar la velocidad del sol (dificultad progresiva) | |
function updateSunSpeed() { | |
sunSpeed = 2 + Math.floor(score / 500); | |
gameSpeed = 5 + Math.floor(score / 300); | |
} | |
// Función de Game Over | |
function gameOver() { | |
gameRunning = false; | |
cancelAnimationFrame(animationFrameId); | |
// Actualizar mejor puntuación | |
if (score > highScore) { | |
highScore = score; | |
localStorage.setItem('highScore', highScore); | |
highScoreDisplay.textContent = `Mejor puntuación: ${highScore}`; | |
} | |
scoreDisplay.textContent = score; | |
gameOverMenu.classList.remove('hidden'); | |
document.getElementById('gameCanvas').classList.add('game-over'); | |
} | |
// Reiniciar el juego | |
function resetGame() { | |
score = 0; | |
gameSpeed = 5; | |
sunSpeed = 2; | |
obstacles = []; | |
clouds = []; | |
player.y = canvas.height - groundHeight - player.height; | |
player.velocityY = 0; | |
player.jumping = false; | |
document.getElementById('gameCanvas').classList.remove('game-over'); | |
gameOverMenu.classList.add('hidden'); | |
} | |
// Bucle principal del juego | |
function gameLoop() { | |
// Limpiar el canvas | |
ctx.clearRect(0, 0, canvas.width, canvas.height); | |
// Fondo gradiente | |
const gradient = ctx.createLinearGradient(0, 0, 0, canvas.height); | |
gradient.addColorStop(0, '#1E3A8A'); | |
gradient.addColorStop(0.4, '#2563EB'); | |
gradient.addColorStop(1, '#7DD3FC'); | |
ctx.fillStyle = gradient; | |
ctx.fillRect(0, 0, canvas.width, canvas.height); | |
// Dibujar elementos del juego | |
drawClouds(); | |
drawGround(); | |
drawObstacles(); | |
drawPlayer(); | |
// Actualizar lógica del juego | |
updatePlayer(); | |
updateObstacles(); | |
updateClouds(); | |
updateSunPosition(); | |
updateSunSpeed(); | |
// Generar nuevos elementos | |
generateObstacle(); | |
generateClouds(); | |
// Actualizar posición parallax | |
parallaxOffset += gameSpeed * 0.5; | |
// Continuar el bucle si el juego está en marcha | |
if (gameRunning) { | |
animationFrameId = requestAnimationFrame(gameLoop); | |
} | |
} | |
// Event listeners | |
startButton.addEventListener('click', () => { | |
resetGame(); | |
mainMenu.classList.add('opacity-0'); | |
setTimeout(() => { | |
mainMenu.classList.add('hidden'); | |
gameRunning = true; | |
gameLoop(); | |
}, 500); | |
}); | |
restartButton.addEventListener('click', () => { | |
resetGame(); | |
gameOverMenu.classList.add('hidden'); | |
gameRunning = true; | |
gameLoop(); | |
}); | |
// Controles del juego | |
document.addEventListener('keydown', (e) => { | |
if (e.code === 'Space' && gameRunning) { | |
e.preventDefault(); | |
jump(); | |
} | |
}); | |
canvas.addEventListener('click', () => { | |
if (gameRunning) { | |
jump(); | |
} | |
}); | |
// Efecto de movimiento inicial del sol | |
setTimeout(() => { | |
sunElement.style.transition = 'transform 0.5s ease-out'; | |
}, 1000); | |
}); | |
</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=lucks17/sun-runner" style="color: #fff;text-decoration: underline;" target="_blank" >🧬 Remix</a></p></body> | |
</html> |