Snake es el juego perfecto para aprender las mecánicas básicas de HTML5 Canvas: bucle de juego, movimiento en grid, detección de colisiones y gestión del estado. Con Cerewro puedes obtener el juego completo en segundos y personalizarlo a tu gusto.
Crea el juego Snake completo en un único archivo HTML5. Requisitos:
- Canvas 600x600 con grid de 20x20 celdas
- Serpiente que crece al comer
- Comida en posición aleatoria (evitando el cuerpo)
- Controles: flechas del teclado y WASD
- Puntuación +10 por comida
- Velocidad aumenta cada 5 puntos
- 3 vidas (la serpiente reaparece al chocar con paredes)
- Al chocar con su propio cuerpo: game over
- Pantalla de inicio, juego y game over
- Guardar récord en localStorage
- Diseño: fondo negro, serpiente verde neón, comida roja, UI con fuente monospace
- Efectos: flash al comer, sonido 8-bit con Web Audio API
const GRID = 20, CELL = 30; // grid 20x20, celda 30px
const canvas = document.getElementById('c');
const ctx = canvas.getContext('2d');
canvas.width = canvas.height = GRID * CELL;
let snake, food, dir, nextDir, score, lives, speed, intervalId;
function init() {
snake = [{x:10, y:10}, {x:9, y:10}, {x:8, y:10}];
dir = {x:1, y:0};
nextDir = {x:1, y:0};
score = 0;
lives = 3;
speed = 150; // ms entre updates
spawnFood();
clearInterval(intervalId);
intervalId = setInterval(update, speed);
}
function spawnFood() {
do {
food = {
x: Math.floor(Math.random() * GRID),
y: Math.floor(Math.random() * GRID)
};
} while (snake.some(s => s.x === food.x && s.y === food.y));
}
function update() {
dir = nextDir;
const head = { x: snake[0].x + dir.x, y: snake[0].y + dir.y };
// Wrap around (atravesar paredes)
head.x = (head.x + GRID) % GRID;
head.y = (head.y + GRID) % GRID;
// Colisión consigo misma
if (snake.some(s => s.x === head.x && s.y === head.y)) {
lives--;
if (lives <= 0) { clearInterval(intervalId); showGameOver(); return; }
init();
return;
}
snake.unshift(head);
if (head.x === food.x && head.y === food.y) {
score += 10;
spawnFood();
if (score % 50 === 0) { // cada 50 puntos, aumentar velocidad
speed = Math.max(60, speed - 10);
clearInterval(intervalId);
intervalId = setInterval(update, speed);
}
} else {
snake.pop();
}
render();
}
function render() {
// Fondo
ctx.fillStyle = '#0a0a0a';
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Grid sutil
ctx.strokeStyle = '#111';
for (let i = 0; i <= GRID; i++) {
ctx.beginPath(); ctx.moveTo(i*CELL, 0); ctx.lineTo(i*CELL, canvas.height); ctx.stroke();
ctx.beginPath(); ctx.moveTo(0, i*CELL); ctx.lineTo(canvas.width, i*CELL); ctx.stroke();
}
// Serpiente
snake.forEach((s, i) => {
const alpha = 1 - i / snake.length * 0.5;
ctx.fillStyle = `rgba(0,255,100,${alpha})`;
ctx.fillRect(s.x*CELL+1, s.y*CELL+1, CELL-2, CELL-2);
});
// Cabeza con brillo
ctx.fillStyle = '#00ff64';
ctx.shadowColor = '#00ff64';
ctx.shadowBlur = 10;
ctx.fillRect(snake[0].x*CELL+1, snake[0].y*CELL+1, CELL-2, CELL-2);
ctx.shadowBlur = 0;
// Comida
ctx.fillStyle = '#ff3333';
ctx.shadowColor = '#ff0000';
ctx.shadowBlur = 8;
ctx.beginPath();
ctx.arc(food.x*CELL+CELL/2, food.y*CELL+CELL/2, CELL/2-2, 0, Math.PI*2);
ctx.fill();
ctx.shadowBlur = 0;
}
// Controles
document.addEventListener('keydown', e => {
const map = {
ArrowUp: {x:0,y:-1}, ArrowDown: {x:0,y:1},
ArrowLeft: {x:-1,y:0}, ArrowRight: {x:1,y:0},
KeyW: {x:0,y:-1}, KeyS: {x:0,y:1},
KeyA: {x:-1,y:0}, KeyD: {x:1,y:0}
};
const d = map[e.code];
if (d && !(d.x === -dir.x && d.y === -dir.y)) nextDir = d;
});
init();