0%
Pygame: crea tu primer juego en Python

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.

I

InSkillCoach

· min

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() o convert_alpha() después de cada pygame.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.

InSkillCoach

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+
844
148

Comentarios

Los comentarios funcionan con GitHub Discussions

Inicia sesión con GitHub para participar en la discusión

¡Enlace copiado!