Introducción
En este proyecto, crearemos un juego de laberinto utilizando la librería Pygame en Python. El juego consiste en guiar a un jugador a través de un laberinto para recoger elementos de comida mientras evita los muros. Dividiremos el proceso de desarrollo en múltiples pasos para hacerlo más fácil de entender y seguir.
👀 Vista previa

🎯 Tareas
En este proyecto, aprenderá:
- Cómo configurar el entorno del juego utilizando Pygame
- Cómo crear el laberinto utilizando celdas y muros
- Cómo agregar elementos de comida para que el jugador los recoja
- Cómo implementar el movimiento del jugador y la detección de colisiones
- Cómo manejar la lógica del juego, incluyendo la puntuación y las condiciones de fin de juego
- Cómo llevar un registro del récord del jugador
- Cómo mostrar estadísticas del juego como el tiempo, la puntuación y el récord en la pantalla
🏆 Logros
Después de completar este proyecto, podrá:
- Utilizar la librería Pygame para el desarrollo de juegos
- Aplicar conceptos de programación orientada a objetos para crear elementos de juego
- Demostrar pensamiento algorítmico y habilidades de resolución de problemas para la generación de laberintos
- Manejar el procesamiento de eventos y la entrada del jugador
- Implementar la detección de colisiones y la mecánica de movimiento en un entorno de juego
- Administrar el manejo de archivos para almacenar y recuperar registros de juego
- Mostrar estadísticas e información del juego en la pantalla
Configurar el entorno
Primero, crearemos los archivos del proyecto para el juego de Laberinto.
cd ~/proyecto
touch laberinto.py
sudo pip install pygame
En este paso, configuraremos el entorno de Pygame y definiremos constantes.
import pygame
from random import choice, randrange
## Constantes para las dimensiones de la pantalla y el tamaño de las baldosas
RES = ANCHO, ALTO = 1202, 902
TILE = 100
columnas, filas = ANCHO // TILE, ALTO // TILE
## El resto de su código irá aquí...
En este paso:
- Importamos las bibliotecas necesarias (Pygame y random).
- Definimos constantes para las dimensiones de la pantalla y el tamaño de las baldosas.
- Inicializamos Pygame y configuramos la ventana del juego.
- Cargamos las imágenes de fondo para el juego.
Creando la clase Celda
En este paso, definiremos la clase Celda para representar las celdas del laberinto.
## Define una clase para representar celdas en el laberinto
class Celda:
def __init__(self, x, y):
self.x, self.y = x, y
## Las paredes representan los límites de la celda
self.paredes = {"arriba": True, "derecha": True, "abajo": True, "izquierda": True}
self.visitada = False
self.grosor = 4
## Dibuja las paredes de la celda
def dibujar(self, sc):
x, y = self.x * TILE, self.y * TILE
if self.paredes["arriba"]:
pygame.draw.line(
sc, pygame.Color("naranja oscuro"), (x, y), (x + TILE, y), self.grosor
)
if self.paredes["derecha"]:
pygame.draw.line(
sc,
pygame.Color("naranja oscuro"),
(x + TILE, y),
(x + TILE, y + TILE),
self.grosor,
)
if self.paredes["abajo"]:
pygame.draw.line(
sc,
pygame.Color("naranja oscuro"),
(x + TILE, y + TILE),
(x, y + TILE),
self.grosor,
)
if self.paredes["izquierda"]:
pygame.draw.line(
sc, pygame.Color("naranja oscuro"), (x, y + TILE), (x, y), self.grosor
)
## Obtiene los rectángulos que representan cada pared de la celda
def obtener_rectangulos(self):
rectangulos = []
x, y = self.x * TILE, self.y * TILE
if self.paredes["arriba"]:
rectangulos.append(pygame.Rect((x, y), (TILE, self.grosor)))
if self.paredes["derecha"]:
rectangulos.append(pygame.Rect((x + TILE, y), (self.grosor, TILE)))
if self.paredes["abajo"]:
rectangulos.append(pygame.Rect((x, y + TILE), (TILE, self.grosor)))
if self.paredes["izquierda"]:
rectangulos.append(pygame.Rect((x, y), (self.grosor, TILE)))
return rectangulos
## Verifica si existe una celda vecina
def verificar_celda(self, x, y):
encontrar_indice = lambda x, y: x + y * columnas
if x < 0 or x > columnas - 1 or y < 0 or y > filas - 1:
return False
return self.celdas_grid[encontrar_indice(x, y)]
## Obtiene las celdas vecinas que no han sido visitadas
def verificar_vecinos(self, celdas_grid):
self.celdas_grid = celdas_grid
vecinos = []
arriba = self.verificar_celda(self.x, self.y - 1)
derecha = self.verificar_celda(self.x + 1, self.y)
abajo = self.verificar_celda(self.x, self.y + 1)
izquierda = self.verificar_celda(self.x - 1, self.y)
if arriba and not arriba.visitada:
vecinos.append(arriba)
if derecha and not derecha.visitada:
vecinos.append(derecha)
if abajo and not abajo.visitada:
vecinos.append(abajo)
if izquierda and not izquierda.visitada:
vecinos.append(izquierda)
return choice(vecinos) if vecinos else False
## El resto de su código irá aquí...
En este paso:
- Definimos la clase
Celdacon sus propiedades y métodos para dibujar paredes y verificar vecinos.
Eliminando paredes y generando el laberinto
En este paso, crearemos funciones para eliminar paredes y generar el laberinto.
## Función para eliminar las paredes entre dos celdas adyacentes
def eliminar_paredes(actual, siguiente):
dx = actual.x - siguiente.x
if dx == 1:
actual.paredes["izquierda"] = False
siguiente.paredes["derecha"] = False
elif dx == -1:
actual.paredes["derecha"] = False
siguiente.paredes["izquierda"] = False
dy = actual.y - siguiente.y
if dy == 1:
actual.paredes["arriba"] = False
siguiente.paredes["abajo"] = False
elif dy == -1:
actual.paredes["abajo"] = False
siguiente.paredes["arriba"] = False
## Función para generar el laberinto
def generar_laberinto():
celdas_grid = [Celda(col, fila) for fila in range(filas) for col in range(columnas)]
celda_actual = celdas_grid[0]
array = []
contador_rompimiento = 1
while contador_rompimiento!= len(celdas_grid):
celda_actual.visitada = True
siguiente_celda = celda_actual.verificar_vecinos(celdas_grid)
if siguiente_celda:
siguiente_celda.visitada = True
contador_rompimiento += 1
array.append(celda_actual)
eliminar_paredes(celda_actual, siguiente_celda)
celda_actual = siguiente_celda
elif array:
celda_actual = array.pop()
return celdas_grid
## El resto de su código irá aquí...
En este paso:
- Definimos la función
eliminar_paredespara eliminar las paredes entre celdas adyacentes. - Creamos la función
generar_laberintopara generar el laberinto utilizando un algoritmo de búsqueda en profundidad.
Agregando comida al juego
En este paso, crearemos una clase Comida para agregar elementos de comida al juego.
## Clase para representar la comida en el juego
class Comida:
def __init__(self):
## Cargar la imagen de la comida
self.img = pygame.image.load("img/comida.png").convert_alpha()
self.img = pygame.transform.scale(self.img, (TILE - 10, TILE - 10))
self.rect = self.img.get_rect()
self.set_pos()
## Establecer la posición de la comida de forma aleatoria
def set_pos(self):
self.rect.topleft = randrange(columnas) * TILE + 5, randrange(filas) * TILE + 5
## Dibujar la comida en la pantalla
def dibujar(self):
superficie_juego.blit(self.img, self.rect)
## El resto de su código irá aquí...
En este paso:
- Definimos la clase
Comidacon métodos para establecer la posición y dibujar los elementos de comida.
Movimiento del jugador y detección de colisiones
En este paso, configuraremos los controles del jugador, su movimiento y la detección de colisiones.
## Verifica si el jugador choca con las paredes
def es_colision(x, y):
rect_tmp = rect_jugador.move(x, y)
if rect_tmp.collidelist(lista_colisiones_paredes) == -1:
return False
return True
## El resto de su código irá aquí...
En este paso:
- Definimos la función
es_colisionpara verificar si el jugador choca con las paredes.
Juego y Puntuación
En este paso, implementaremos la lógica del juego, incluyendo comer comida y puntuar.
## Verifica si el jugador ha comido alguna comida
def comer_comida():
for comida in lista_comida:
if rect_jugador.collidepoint(comida.rect.center):
comida.set_pos()
return True
return False
## Verifica si el juego ha terminado (se agota el tiempo)
def esta_terminado_el_juego():
global tiempo, puntuacion, record, FPS
if tiempo < 0:
pygame.time.wait(700)
rect_jugador.center = TILE // 2, TILE // 2
[comida.set_pos() for comida in lista_comida]
establecer_record(record, puntuacion)
record = obtener_record()
tiempo, puntuacion, FPS = 60, 0, 60
## El resto de su código irá aquí...
En este paso:
- Definimos la función
comer_comidapara verificar si el jugador ha comido alguna comida. - Creamos la función
esta_terminado_el_juegopara verificar si el juego ha terminado cuando se agota el tiempo.
Manejo de registros
En este paso, implementaremos la conservación de registros para el juego.
## Función para obtener el registro actual de un archivo
def obtener_registro():
try:
with open("registro") as f:
return f.readline()
except FileNotFoundError:
with open("registro", "w") as f:
f.write("0")
return "0"
## Función para establecer y actualizar el registro en un archivo
def establecer_registro(registro, puntuación):
rec = max(int(registro), puntuación)
with open("registro", "w") as f:
f.write(str(rec))
## El resto de su código irá aquí...
En este paso:
- Definimos funciones para recuperar el registro actual de un archivo y actualizarlo.
Inicialización del juego
En este paso, realizaremos las tareas de inicialización del juego.
## Inicializar Pygame y configurar la ventana del juego
FPS = 60
pygame.init()
superficie_juego = pygame.Surface(RES)
superficie = pygame.display.set_mode((ANCHO + 300, ALTO))
reloj = pygame.time.Clock()
## Cargar las imágenes de fondo
fondo_juego = pygame.image.load("img/fondo_1.jpg").convert()
fondo = pygame.image.load("img/fondo_principal.jpg").convert()
## Generar el laberinto
laberinto = generar_laberinto()
## Configuración del jugador
velocidad_jugador = 5
imagen_jugador = pygame.image.load("img/0.png").convert_alpha()
imagen_jugador = pygame.transform.scale(
imagen_jugador, (TILE - 2 * laberinto[0].grosor, TILE - 2 * laberinto[0].grosor)
)
rect_jugador = imagen_jugador.get_rect()
rect_jugador.center = TILE // 2, TILE // 2
direcciones = {
"a": (-velocidad_jugador, 0),
"d": (velocidad_jugador, 0),
"w": (0, -velocidad_jugador),
"s": (0, velocidad_jugador),
}
teclas = {"a": pygame.K_LEFT, "d": pygame.K_RIGHT, "w": pygame.K_UP, "s": pygame.K_DOWN}
direccion = (0, 0)
## Configuración de la comida
lista_comida = [Comida() for i in range(3)]
## Crear una lista de rectángulos que representan las paredes para la detección de colisiones
lista_colisiones_paredes = sum([celda.get_rects() for celda in laberinto], [])
## Temporizador, puntuación y récord
pygame.time.set_timer(pygame.USEREVENT, 1000)
tiempo = 60
puntuacion = 0
record = obtener_record()
## Fuentes
fuente = pygame.font.SysFont("Impact", 150)
fuente_texto = pygame.font.SysFont("Impact", 80)
## El resto de su código irá aquí...
En este paso:
- Realizamos varias tareas de inicialización, incluyendo configurar Pygame, cargar imágenes, generar el laberinto e inicializar variables relacionadas con el jugador y la comida.
Bucle principal del juego
En este paso, configuraremos el bucle principal del juego y mostraremos los elementos del juego.
## Bucle principal del juego
while True:
## Dibuja las imágenes de fondo
superficie.blit(fondo, (ANCHO, 0))
superficie.blit(superficie_juego, (0, 0))
superficie_juego.blit(fondo_juego, (0, 0))
for evento in pygame.event.get():
if evento.type == pygame.QUIT:
exit()
if evento.type == pygame.USEREVENT:
tiempo -= 1
## Maneja los controles y el movimiento del jugador
tecla_presionada = pygame.key.get_pressed()
for tecla, valor_tecla in teclas.items():
if tecla_presionada[valor_tecla] and not es_colision(*direcciones[tecla]):
direccion = direcciones[tecla]
break
if not es_colision(*direccion):
rect_jugador.move_ip(direccion)
## Dibuja el laberinto
[celda.dibujar(superficie_juego) for celda in laberinto]
## Juego: Verifica si el jugador ha comido comida y si el juego ha terminado
if comer_comida():
FPS += 10
puntuacion += 1
esta_terminado_el_juego()
## Dibuja al jugador
superficie_juego.blit(imagen_jugador, rect_jugador)
## Dibuja los elementos de comida
[comida.dibujar() for comida in lista_comida]
## El resto de su código irá aquí...
En este paso:
- Configuramos el bucle principal del juego que maneja los eventos, el movimiento del jugador y la representación gráfica del juego.
Mostrando Estadísticas del Juego
En este paso, mostraremos las estadísticas del juego en la pantalla.
## Dibuja las estadísticas del juego
superficie.blit(
fuente_texto.render("TIEMPO", True, pygame.Color("cian"), True), (ANCHO + 70, 30)
)
superficie.blit(fuente.render(f"{tiempo}", True, pygame.Color("cian")), (ANCHO + 70, 130))
superficie.blit(
fuente_texto.render("puntuación:", True, pygame.Color("verde bosque"), True),
(ANCHO + 50, 350),
)
superficie.blit(
fuente.render(f"{puntuacion}", True, pygame.Color("verde bosque")), (ANCHO + 70, 430)
)
superficie.blit(
fuente_texto.render("récord:", True, pygame.Color("magenta"), True),
(ANCHO + 30, 620),
)
superficie.blit(
fuente.render(f"{record}", True, pygame.Color("magenta")), (ANCHO + 70, 700)
)
pygame.display.flip()
reloj.tick(FPS)
En este paso:
- Utilizamos fuentes para mostrar información relacionada con el juego, como el tiempo, la puntuación y el récord.
- Utilizamos el método
blit()para dibujar el texto en la pantalla. - Utilizamos el método
flip()para actualizar la pantalla.
Ejecutar el juego
Ahora que hemos completado todos los pasos, podemos ejecutar el juego del laberinto con el siguiente comando:
cd ~/proyecto
python laberinto.py

Resumen
En este proyecto, hemos dividido el proceso de construir un juego de laberinto utilizando Pygame en diez pasos claros y manejables. Aprenderás cómo configurar el entorno del juego, crear las celdas del laberinto, generar el laberinto, manejar el movimiento del jugador y la detección de colisiones, implementar la dinámica del juego y la puntuación, gestionar los registros y mucho más. Siguiendo estos pasos, podrás crear un juego de laberinto completamente funcional en Python.



