Pygame: crea tu primer juego en Python
Crea tu primer videojuego en Python con Pygame: bucle de juego, sprites, colisiones, sonidos, texto y puntuación, con el código completo de un juego de atrapar objetos.
InSkillCoach
Pygame : Créer votre Premier Jeu en Python
Pygame es la biblioteca más accesible para crear juegos 2D en Python. Gestiona la pantalla, el sonido, el teclado, el ratón y las colisiones, y a la vez es lo bastante sencilla como para que un principiante construya un juego completo en unas pocas horas. En esta guía aprenderás los bloques fundamentales de Pygame y después los combinarás en un pequeño juego completo de atrapar objetos, cuyo código íntegro se proporciona y se comenta.
Instalación
Pygame se instala con pip:
pip install pygame
# Vérification : lance un jeu d'exemple fourni avec la bibliothèque
python -m pygame.examples.aliens
Si se abre la ventana del juego de ejemplo, todo está listo.
La ventana y el bucle de juego
Todo juego se basa en la misma estructura: un bucle infinito que, en cada vuelta, procesa los eventos (teclado, ratón, cierre), actualiza el estado del juego y vuelve a dibujar la pantalla.
import pygame
# Initialisation de tous les modules Pygame
pygame.init()
# Création de la fenêtre (largeur, hauteur)
ecran = pygame.display.set_mode((800, 600))
pygame.display.set_caption("Mon premier jeu")
# Horloge pour contrôler la vitesse du jeu
horloge = pygame.time.Clock()
en_cours = True
while en_cours:
# 1. ÉVÉNEMENTS : traiter les entrées de l'utilisateur
for event in pygame.event.get():
if event.type == pygame.QUIT: # clic sur la croix de la fenêtre
en_cours = False
# 2. UPDATE : mettre à jour la logique du jeu (positions, score...)
# 3. DRAW : tout redessiner
ecran.fill((30, 30, 60)) # fond bleu nuit (R, G, B)
pygame.display.flip() # afficher le résultat à l'écran
# 4. Limiter le jeu à 60 images par seconde
horloge.tick(60)
pygame.quit()
Dos puntos esenciales:
pygame.display.flip()muestra en pantalla todo lo que se ha dibujado durante la vuelta del bucle. Sin esta llamada, no se muestra nada.horloge.tick(60)espera justo lo necesario para que el bucle se ejecute 60 veces por segundo. Sin ella, el juego iría a una velocidad distinta en cada máquina.
Dibujar formas e imágenes
Pygame ofrece primitivas de dibujo y carga de imágenes:
# Formes géométriques
pygame.draw.rect(ecran, (255, 0, 0), (100, 100, 50, 80)) # rectangle rouge
pygame.draw.circle(ecran, (0, 255, 0), (400, 300), 40) # cercle vert
pygame.draw.line(ecran, (255, 255, 255), (0, 0), (800, 600), 3) # ligne blanche
# Chargement et affichage d'une image
# convert_alpha() accélère l'affichage et conserve la transparence PNG
joueur_img = pygame.image.load("joueur.png").convert_alpha()
ecran.blit(joueur_img, (200, 150)) # blit = copier l'image à une position
# Redimensionner une image
joueur_img = pygame.transform.scale(joueur_img, (64, 64))
El sistema de coordenadas parte de la esquina superior izquierda: x aumenta hacia la derecha e y aumenta hacia abajo.
Gestionar el teclado y el ratón
Existen dos enfoques complementarios:
# Approche 1 : les événements (parfaits pour les actions ponctuelles)
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
print("Saut !") # déclenché une seule fois par appui
if event.type == pygame.MOUSEBUTTONDOWN:
print(f"Clic en {event.pos}") # position (x, y) du clic
# Approche 2 : l'état des touches (parfait pour le déplacement continu)
touches = pygame.key.get_pressed()
if touches[pygame.K_LEFT]:
x -= 5 # tant que la flèche gauche est maintenue
if touches[pygame.K_RIGHT]:
x += 5
# Position actuelle de la souris
souris_x, souris_y = pygame.mouse.get_pos()
Recuerda la regla: evento para una acción instantánea (disparo, salto, pausa) y get_pressed() para un movimiento fluido.
Sprites y grupos
Un sprite es un objeto del juego que combina una imagen (self.image) y una posición (self.rect). Los grupos permiten actualizar y dibujar decenas de sprites en una sola línea:
import pygame
class Joueur(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
# Image : ici un simple carré bleu de 50x50 pixels
self.image = pygame.Surface((50, 50))
self.image.fill((50, 150, 255))
# Le rect stocke la position et sert aux collisions
self.rect = self.image.get_rect(center=(400, 550))
self.vitesse = 7
def update(self):
"""Appelée à chaque image : déplace le joueur au clavier."""
touches = pygame.key.get_pressed()
if touches[pygame.K_LEFT]:
self.rect.x -= self.vitesse
if touches[pygame.K_RIGHT]:
self.rect.x += self.vitesse
# Empêcher de sortir de l'écran
self.rect.clamp_ip(pygame.Rect(0, 0, 800, 600))
# Utilisation avec un groupe
tous_les_sprites = pygame.sprite.Group()
tous_les_sprites.add(Joueur())
# Dans la boucle de jeu :
tous_les_sprites.update() # appelle update() de chaque sprite
tous_les_sprites.draw(ecran) # dessine chaque sprite à son rect
Colisiones
Pygame ofrece varios niveles de detección:
# Entre deux rectangles
if joueur.rect.colliderect(ennemi.rect):
print("Touché !")
# Entre un sprite et un groupe
# dokill=True : les sprites touchés sont retirés du groupe
objets_touches = pygame.sprite.spritecollide(joueur, groupe_objets, dokill=True)
for objet in objets_touches:
score += 1
# Entre deux groupes (renvoie un dictionnaire)
collisions = pygame.sprite.groupcollide(groupe_tirs, groupe_ennemis, True, True)
Sonidos
# Le mixer doit être initialisé (pygame.init() le fait automatiquement)
son_bonus = pygame.mixer.Sound("bonus.wav") # effet court, chargé en mémoire
son_bonus.set_volume(0.5) # volume de 0.0 à 1.0
son_bonus.play()
# Musique de fond (lue en continu depuis le fichier)
pygame.mixer.music.load("musique.ogg")
pygame.mixer.music.play(-1) # -1 = boucle infinie
Texto y puntuación
El texto se dibuja en tres pasos: crear una fuente, generar una imagen del texto (render) y, por último, mostrarla (blit):
# None = police par défaut, 36 = taille en points
police = pygame.font.Font(None, 36)
score = 12
# render(texte, antialiasing, couleur)
texte_score = police.render(f"Score : {score}", True, (255, 255, 255))
ecran.blit(texte_score, (10, 10))
Un juego completo: el atrapa-objetos
Juntemos todo en un juego jugable: unas manzanas caen desde la parte superior de la pantalla y tú mueves una cesta con las flechas para atraparlas. Cada manzana atrapada suma un punto y cada manzana que se escapa cuesta una vida. El código es autónomo (ninguna imagen externa: todo se dibuja con formas).
import random
import pygame
# ---------- Étape 1 : constantes et initialisation ----------
LARGEUR, HAUTEUR = 800, 600
FPS = 60
pygame.init()
ecran = pygame.display.set_mode((LARGEUR, HAUTEUR))
pygame.display.set_caption("Attrape-Pommes")
horloge = pygame.time.Clock()
police = pygame.font.Font(None, 36)
# ---------- Étape 2 : les sprites ----------
class Panier(pygame.sprite.Sprite):
"""Le panier contrôlé par le joueur, en bas de l'écran."""
def __init__(self):
super().__init__()
self.image = pygame.Surface((100, 25))
self.image.fill((160, 100, 40)) # marron
self.rect = self.image.get_rect(midbottom=(LARGEUR // 2, HAUTEUR - 10))
self.vitesse = 9
def update(self):
touches = pygame.key.get_pressed()
if touches[pygame.K_LEFT]:
self.rect.x -= self.vitesse
if touches[pygame.K_RIGHT]:
self.rect.x += self.vitesse
self.rect.clamp_ip(ecran.get_rect()) # rester dans l'écran
class Pomme(pygame.sprite.Sprite):
"""Une pomme qui tombe du haut de l'écran à vitesse aléatoire."""
def __init__(self):
super().__init__()
self.image = pygame.Surface((28, 28), pygame.SRCALPHA)
pygame.draw.circle(self.image, (220, 40, 40), (14, 14), 14)
self.rect = self.image.get_rect(
midtop=(random.randint(20, LARGEUR - 20), -30)
)
self.vitesse = random.randint(3, 7)
def update(self):
self.rect.y += self.vitesse
# ---------- Étape 3 : état du jeu ----------
panier = Panier()
tous_les_sprites = pygame.sprite.Group(panier)
pommes = pygame.sprite.Group()
score = 0
vies = 3
# Événement personnalisé : faire apparaître une pomme toutes les 800 ms
APPARITION_POMME = pygame.USEREVENT + 1
pygame.time.set_timer(APPARITION_POMME, 800)
# ---------- Étape 4 : boucle de jeu ----------
en_cours = True
while en_cours:
# Événements
for event in pygame.event.get():
if event.type == pygame.QUIT:
en_cours = False
if event.type == APPARITION_POMME and vies > 0:
pomme = Pomme()
pommes.add(pomme)
tous_les_sprites.add(pomme)
if vies > 0:
# Update
tous_les_sprites.update()
# Pommes attrapées : +1 point chacune
attrapees = pygame.sprite.spritecollide(panier, pommes, dokill=True)
score += len(attrapees)
# Pommes manquées (sorties de l'écran) : -1 vie chacune
for pomme in list(pommes):
if pomme.rect.top > HAUTEUR:
pomme.kill() # retire le sprite de tous ses groupes
vies -= 1
# Draw
ecran.fill((25, 35, 55))
tous_les_sprites.draw(ecran)
texte = police.render(f"Score : {score} Vies : {vies}", True, (255, 255, 255))
ecran.blit(texte, (10, 10))
if vies <= 0:
fin = police.render("PARTIE TERMINÉE - Fermez la fenêtre", True, (255, 80, 80))
rect_fin = fin.get_rect(center=(LARGEUR // 2, HAUTEUR // 2))
ecran.blit(fin, rect_fin)
pygame.display.flip()
horloge.tick(FPS)
pygame.quit()
Guarda este código en attrape_pommes.py y ejecútalo: el juego es jugable de inmediato. Algunas ideas de mejora para practicar: acelerar las manzanas con el paso del tiempo, añadir un sonido cada vez que se atrapa una manzana, guardar la mejor puntuación en un archivo o sustituir las formas por imágenes de verdad.
Buenas prácticas
- Respeta la estructura eventos / update / draw: nunca dibujes en la fase de lógica ni modifiques el estado en la fase de dibujo.
- Usa siempre
clock.tick(FPS)para obtener la misma velocidad en todas las máquinas. - Llama a
convert()oconvert_alpha()después de cadapygame.image.load(): la visualización es notablemente más rápida. - Una clase de sprite por tipo de objeto: el código se mantiene legible y los grupos se encargan de las actualizaciones y del dibujo.
- Usa
sprite.kill()para retirar limpiamente un sprite de todos sus grupos, en lugar de gestionar listas a mano. - Agrupa las constantes (dimensiones, colores, velocidades) al principio del archivo: equilibrar el juego se vuelve trivial.
Conclusión
Ya conoces todos los mecanismos fundamentales de Pygame: el bucle de juego marcado por el reloj, el dibujo de formas e imágenes, la gestión del teclado, los sprites organizados en grupos, las colisiones, el sonido y la visualización de la puntuación. El juego de atrapar objetos reúne todos estos elementos en menos de 120 líneas y constituye una base sólida que puedes ampliar a tu gusto.
Para seguir avanzando, explora la documentación oficial de Pygame y lánzate un reto clásico: recrear Pong, Snake o un rompeladrillos. Es construyendo pequeños juegos completos como se progresa más rápido.
Acerca de InSkillCoach
Experto en formación y tecnologías
Coach especializado en tecnologías avanzadas e IA, impulsado por GNeurone Inc.
Certificaciones:
- AWS Certified Solutions Architect – Professional
- Certificaciones de Google Cloud
- Microsoft Certified: DevOps Engineer Expert
- Certified Kubernetes Administrator (CKA)
- CompTIA Security+
Comentarios
Los comentarios funcionan con GitHub Discussions
Inicia sesión con GitHub para participar en la discusión