HTML, CSS y Javascript proveen herramientas para un sin fin de posibilidades a la hora de crear interfaces y juegos. Mi propósito es mostraros cómo realizar un popular juego: buscando la salida en el laberinto. Os compartiré el código fuente para que podáis incluirlo en vuestros propios proyectos personales o profesionales.
Mostrando el código HTML del juego buscando la salida en laberinto
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Laberinto Profesional</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div class="container" id="maze"></div>
<script src="script.js"></script>
</body>
</html>
Código CSS
body {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background: linear-gradient(45deg, #0f0c29, #302b63, #24243e);
margin: 0;
overflow: hidden;
font-family: 'Arial', sans-serif;
color: white;
}
.container {
position: relative;
width: 600px;
height: 600px;
background: #111;
display: grid;
grid-template-columns: repeat(20, 1fr);
grid-template-rows: repeat(20, 1fr);
gap: 2px;
padding: 10px;
border: 5px solid #fff;
border-radius: 15px;
box-shadow: 0 0 30px rgba(255, 255, 255, 0.6);
}
.cell {
width: 100%;
height: 100%;
background: #444;
transition: background 0.3s ease;
}
.wall {
background: #222;
box-shadow: inset 0 0 10px rgba(0, 0, 0, 0.9);
}
.player {
background: radial-gradient(circle, #00ffcc, #008080);
border-radius: 50%;
box-shadow: 0 0 15px #00ffcc;
}
.exit {
background: radial-gradient(circle, #ffcc00, #ff6600);
border-radius: 50%;
box-shadow: 0 0 15px #ffcc00;
}
Javascript: buscando la salida en el laberinto
const mazeData = [
"####################",
"#P # # # ##",
"### # ### # # ######",
"# # # # #",
"# ##### #### #######",
"# # # #",
"##### ####### ### ##",
"# # # # #",
"# # # ### ### ### ##",
"# # # # # # #",
"# # ##### ### #####",
"# # # # #",
"##### ### # ##### #",
"# # # # #",
"# ### ### ### # ###",
"# # # # #",
"### ####### ##### #",
"# # # #",
"##################E",
];
const container = document.getElementById("maze");
let playerPos = { x: 1, y: 1 };
function createMaze() {
container.innerHTML = "";
mazeData.forEach((row, y) => {
row.split('').forEach((cell, x) => {
const div = document.createElement("div");
div.classList.add("cell");
if (cell === "#") div.classList.add("wall");
if (cell === "P") {
div.classList.add("player");
playerPos = { x, y };
}
if (cell === "E") div.classList.add("exit");
container.appendChild(div);
});
});
}
function movePlayer(dx, dy) {
const newX = playerPos.x + dx;
const newY = playerPos.y + dy;
if (mazeData[newY][newX] !== "#") {
if (mazeData[newY][newX] === "E") {
alert("¡Felicidades! Has escapado del laberinto.");
return;
}
mazeData[playerPos.y] = mazeData[playerPos.y].replace("P", " ");
mazeData[newY] = mazeData[newY].substring(0, newX) + "P" + mazeData[newY].substring(newX + 1);
playerPos = { x: newX, y: newY };
createMaze();
}
}
document.addEventListener("keydown", (e) => {
if (e.key === "ArrowUp" || e.key === "w") movePlayer(0, -1);
if (e.key === "ArrowDown" || e.key === "s") movePlayer(0, 1);
if (e.key === "ArrowLeft" || e.key === "a") movePlayer(-1, 0);
if (e.key === "ArrowRight" || e.key === "d") movePlayer(1, 0);
});
createMaze();
Explicando el código Javascript del juego
En esta sección os explicaré, de manera detallada qué significa cada una de las líneas del código Javascript:
const mazeData = [
"####################",
"#P # # # ##",
"### # ### # # ######",
"# # # # #",
"# ##### #### #######",
"# # # #",
"##### ####### ### ##",
"# # # # #",
"# # # ### ### ### ##",
"# # # # # # #",
"# # ##### ### #####",
"# # # # #",
"##### ### # ##### #",
"# # # # #",
"# ### ### ### # ###",
"# # # # #",
"### ####### ##### #",´
"# # # #",
"##################E",
];
Aquí se define el mapa del laberinto.
– #
representa una pared.
– P
representa la posición inicial del jugador.
– E
representa la salida.
– Los espacios en blanco (" "
) son caminos transitables.
const container = document.getElementById("maze");
Obtiene el elemento HTML con el ID "maze"
donde se dibujará el laberinto.
let playerPos = { x: 1, y: 1 };
Define un objeto playerPos
para almacenar la posición actual del jugador dentro del laberinto.
Aquí empieza en { x: 1, y: 1 }
, que es donde está la "P"
en mazeData
.
function createMaze() {
container.innerHTML = "";
Esta función dibuja el laberinto en el contenedor container
.
La línea container.innerHTML = "";
limpia el laberinto antes de volver a generarlo.
mazeData.forEach((row, y) => {
En esta línea se itera sobre cada fila (row
) del laberinto.
La variable y
representa la fila actual dentro del mazeData
.
row.split('').forEach((cell, x) => {
Cada fila (row
) es una cadena de texto, por lo que split('')
convierte cada carácter en un array de caracteres individuales.
La variable x
representa la columna actual dentro de la fila.
const div = document.createElement("div");
div.classList.add("cell");
Crea un nuevo elemento <div>
para representar una celda del laberinto.
Le agrega la clase "cell"
para que tenga los estilos CSS correspondientes.
if (cell === "#") div.classList.add("wall");
Si la celda contiene "#"
, entonces es una pared y se le añade la clase "wall"
.
if (cell === "P") {
div.classList.add("player");
playerPos = { x, y };
}
Si la celda contiene "P"
(jugador), entonces:
1. Se le agrega la clase "player"
para que se vea diferente.
2. Se actualiza playerPos
con la posición { x, y }
.
if (cell === "E") div.classList.add("exit");
Si la celda contiene "E"
(salida), se le agrega la clase "exit"
.
container.appendChild(div);
});
});
}
Cada celda (div
) generada se agrega al contenedor "maze"
, fila por fila, para formar el laberinto en la interfaz.
Función movePlayer(dx, dy)
Esta función mueve al jugador en el laberinto según los valores dx
y dy
.
– dx
: Indica el movimiento en el eje horizontal (-1
izquierda, +1
derecha).
– dy
: Indica el movimiento en el eje vertical (-1
arriba, +1
abajo).
const newX = playerPos.x + dx;
const newY = playerPos.y + dy;
Calcula la nueva posición candidata para el jugador.
Ejemplo: Si dx = 1
, el jugador se movería una celda a la derecha.
if (mazeData[newY][newX] !== "#") {
Verifica si la nueva posición es válida.
Si la celda en mazeData[newY][newX]
NO es una pared ("#"
), el jugador puede moverse.
if (mazeData[newY][newX] === "E") {
alert("¡Felicidades! Has escapado del laberinto.");
return;
}
Si el jugador llega a la salida ("E"
), muestra un mensaje y finaliza la función.
mazeData[playerPos.y] = mazeData[playerPos.y].replace("P", " ");
mazeData[newY] = mazeData[newY].substring(0, newX) + "P" + mazeData[newY].substring(newX + 1);
Elimina la "P"
de la posición anterior (reemplazándola con un espacio " "
). Coloca la "P"
en la nueva posición (newX, newY
).
– Usa substring()
para reconstruir la cadena, reemplazando solo el carácter en la nueva posición.
playerPos = { x: newX, y: newY };
createMaze();
}
}
Actualiza la posición del jugador (playerPos
).
Redibuja el laberinto llamando a createMaze()
para reflejar el cambio.
Evento para capturar teclas
document.addEventListener("keydown", (e) => {
if (e.key === "ArrowUp" || e.key === "w") movePlayer(0, -1);
if (e.key === "ArrowDown" || e.key === "s") movePlayer(0, 1);
if (e.key === "ArrowLeft" || e.key === "a") movePlayer(-1, 0);
if (e.key === "ArrowRight" || e.key === "d") movePlayer(1, 0);
});
Dependiendo de la tecla presionada:
– ArrowUp
o w
→ Mueve el jugador hacia arriba (dy = -1
).
– ArrowDown
o s
→ Mueve el jugador hacia abajo (dy = +1
).
– ArrowLeft
o a
→ Mueve el jugador a la izquierda (dx = -1
).
– ArrowRight
o d
→ Mueve el jugador a la derecha (dx = +1
).