sun-runner / index.html
lucks17's picture
Add 2 files
198aef4 verified
<!DOCTYPE html>
<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>