Meta Description" name="description" />
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>Kirby Scroll Vertical</title>
<style>
body { margin: 0; overflow: hidden; background: #87CEEB; font-family: sans-serif; touch-action: none; }
canvas { display: block; }
.ui {
position: fixed; bottom: 40px; left: 0; right: 0;
display: flex; justify-content: space-between; padding: 0 30px;
pointer-events: none; z-index: 100;
}
.btn {
width: 80px; height: 80px; background: rgba(255, 255, 255, 0.5);
border: 5px solid #fff; border-radius: 50%;
display: flex; align-items: center; justify-content: center;
font-size: 30px; color: #333; pointer-events: auto;
user-select: none; -webkit-tap-highlight-color: transparent;
}
#jumpBtn { background: rgba(255, 105, 180, 0.8); color: white; width: 100px; height: 100px; }
.btn:active { transform: scale(1.1); background: white; }
</style>
</head>
<body>
<canvas id="gameCanvas"></canvas>
<div class="ui">
<div style="display:flex; gap: 20px;">
<div class="btn" id="lBtn">◀</div>
<div class="btn" id="rBtn">▶</div>
</div>
<div class="btn" id="jumpBtn">↑</div>
</div>
<script>
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
function resize() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
}
window.addEventListener('resize', resize);
resize();
// --- ESTADO DEL JUEGO ---
const player = {
x: canvas.width / 2,
y: canvas.height - 150,
radius: 25,
vx: 0,
vy: 0,
isJumping: false,
color: "#ffb6c1"
};
// Generamos muchas plataformas hacia arriba
const platforms = [];
for(let i = 0; i < 20; i++) {
platforms.push({
x: Math.random() * (canvas.width - 150),
y: (canvas.height - 100) - (i * 180),
w: 120 + Math.random() * 50,
h: 35
});
}
const input = { left: false, right: false, jump: false };
let cameraY = 0; // Posición de la cámara
// --- CONTROLES ---
function bind(id, key) {
const el = document.getElementById(id);
const start = (e) => { e.preventDefault(); input[key] = true; };
const end = (e) => { e.preventDefault(); input[key] = false; };
el.addEventListener('touchstart', start);
el.addEventListener('touchend', end);
}
bind('lBtn', 'left');
bind('rBtn', 'right');
bind('jumpBtn', 'jump');
function update() {
// Movimiento
if (input.left) player.vx = -7;
else if (input.right) player.vx = 7;
else player.vx *= 0.85;
if (input.jump && !player.isJumping) {
player.vy = -18;
player.isJumping = true;
}
player.vy += 0.8;
player.x += player.vx;
player.y += player.vy;
// Colisiones
platforms.forEach(p => {
if (player.vy > 0 &&
player.x + 15 > p.x && player.x - 15 < p.x + p.w &&
player.y + 25 > p.y && player.y + 25 < p.y + p.h) {
player.isJumping = false;
player.vy = 0;
player.y = p.y - 25;
}
});
// --- LÓGICA DE LA CÁMARA ---
// La cámara sigue a Kirby para que siempre esté en el centro de la pantalla
let targetCameraY = player.y - canvas.height / 2;
// Suavizado de cámara (Interpolación lineal)
cameraY += (targetCameraY - cameraY) * 0.1;
// Límites de pantalla laterales
if (player.x < 25) player.x = 25;
if (player.x > canvas.width - 25) player.x = canvas.width - 25;
// Reset si cae mucho más abajo de la cámara
if (player.y > cameraY + canvas.height + 100) {
player.y = canvas.height - 150;
player.x = canvas.width / 2;
player.vy = 0;
cameraY = player.y - canvas.height / 2;
}
draw();
requestAnimationFrame(update);
}
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Guardamos el estado, movemos la cámara y dibujamos
ctx.save();
ctx.translate(0, -cameraY); // <--- AQUÍ OCURRE EL MOVIMIENTO DE CÁMARA
// Fondo Dinámico (Nubes que se repiten)
ctx.fillStyle = "white";
for(let i = 0; i < 10; i++) {
ctx.beginPath();
ctx.arc(100, i * -400, 40, 0, Math.PI*2);
ctx.arc(canvas.width - 100, i * -400 - 200, 50, 0, Math.PI*2);
ctx.fill();
}
// Dibujar Plataformas
platforms.forEach(p => {
ctx.fillStyle = "#7cfc00";
ctx.fillRect(p.x, p.y, p.w, p.h);
ctx.fillStyle = "#228b22";
ctx.fillRect(p.x, p.y + p.h - 10, p.w, 10);
});
// Dibujar Kirby
const px = player.x;
const py = player.y;
ctx.fillStyle = player.color;
ctx.beginPath();
ctx.arc(px, py, player.radius, 0, Math.PI * 2);
ctx.fill();
ctx.strokeStyle = "#ff69b4";
ctx.lineWidth = 3;
ctx.stroke();
// Ojos y detalles
ctx.fillStyle = "black";
ctx.beginPath();
ctx.ellipse(px - 7, py - 5, 3, 6, 0, 0, Math.PI*2);
ctx.ellipse(px + 7, py - 5, 3, 6, 0, 0, Math.PI*2);
ctx.fill();
ctx.fillStyle = "#ffc0cb";
ctx.beginPath();
ctx.arc(px - 15, py + 5, 5, 0, Math.PI*2);
ctx.arc(px + 15, py + 5, 5, 0, Math.PI*2);
ctx.fill();
ctx.restore(); // Restauramos para que la UI no se mueva
}
update();
</script>
</body>
</html>
1
1
6KB
6KB
190.0ms
204.0ms
190.0ms