0%
Pygame : Créer votre Premier Jeu en Python

Pygame : Créer votre Premier Jeu en Python

Créez votre premier jeu vidéo en Python avec Pygame : boucle de jeu, sprites, collisions, sons, texte et score, avec le code complet d'un jeu d'attrape-objets.

I

InSkillCoach

· min

Pygame : Créer votre Premier Jeu en Python

Pygame est la bibliothèque la plus accessible pour créer des jeux 2D en Python. Elle gère l’affichage, le son, le clavier, la souris et les collisions, tout en restant assez simple pour qu’un débutant construise un jeu complet en quelques heures. Dans ce guide, vous apprendrez les briques fondamentales de Pygame, puis vous les assemblerez dans un petit jeu complet d’attrape-objets dont le code intégral est fourni et commenté.

Installation

Pygame s’installe avec pip :

pip install pygame

# Vérification : lance un jeu d'exemple fourni avec la bibliothèque
python -m pygame.examples.aliens

Si la fenêtre du jeu d’exemple s’ouvre, tout est prêt.

La fenêtre et la boucle de jeu

Tout jeu repose sur la même structure : une boucle infinie qui, à chaque tour, traite les événements (clavier, souris, fermeture), met à jour l’état du jeu, puis redessine l’écran.

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()

Deux points essentiels :

  • pygame.display.flip() bascule à l’écran tout ce qui a été dessiné pendant le tour de boucle. Sans cet appel, rien ne s’affiche.
  • horloge.tick(60) fait attendre juste ce qu’il faut pour que la boucle tourne 60 fois par seconde. Sans lui, le jeu tournerait à une vitesse différente sur chaque machine.

Dessiner des formes et des images

Pygame fournit des primitives de dessin et le chargement d’images :

# 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))

Le système de coordonnées part du coin supérieur gauche : x augmente vers la droite, y augmente vers le bas.

Gérer le clavier et la souris

Deux approches complémentaires existent :

# 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()

Retenez la règle : événement pour une action instantanée (tir, saut, pause), get_pressed() pour un mouvement fluide.

Sprites et groupes

Un sprite est un objet du jeu qui combine une image (self.image) et une position (self.rect). Les groupes permettent de mettre à jour et dessiner des dizaines de sprites en une ligne :

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

Collisions

Pygame propose plusieurs niveaux de détection :

# 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)

Sons

# 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

Texte et score

Le texte se dessine en trois étapes : créer une police, générer une image du texte (render), puis l’afficher (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 jeu complet : l’attrape-objets

Assemblons tout dans un jeu jouable : des pommes tombent du haut de l’écran, vous déplacez un panier avec les flèches pour les attraper. Chaque pomme attrapée rapporte un point, chaque pomme manquée coûte une vie. Le code est autonome (aucune image externe : tout est dessiné avec des formes).

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()

Enregistrez ce code dans attrape_pommes.py et lancez-le : le jeu est immédiatement jouable. Quelques pistes d’amélioration pour vous exercer : accélérer les pommes au fil du temps, ajouter un son à chaque pomme attrapée, afficher le meilleur score dans un fichier, ou remplacer les formes par de vraies images.

Bonnes pratiques

  • Respectez la structure événements / update / draw : ne dessinez jamais dans la phase de logique, ne modifiez pas l’état dans la phase de dessin.
  • Utilisez toujours clock.tick(FPS) pour une vitesse identique sur toutes les machines.
  • Appelez convert() ou convert_alpha() après chaque pygame.image.load() : l’affichage est nettement plus rapide.
  • Une classe de sprite par type d’objet : le code reste lisible et les groupes gèrent les mises à jour et le dessin.
  • Utilisez sprite.kill() pour retirer proprement un sprite de tous ses groupes, plutôt que de gérer des listes à la main.
  • Regroupez les constantes (dimensions, couleurs, vitesses) en haut du fichier : équilibrer le jeu devient trivial.

Conclusion

Vous connaissez maintenant tous les mécanismes fondamentaux de Pygame : la boucle de jeu cadencée par l’horloge, le dessin de formes et d’images, la gestion du clavier, les sprites organisés en groupes, les collisions, le son et l’affichage du score. Le jeu d’attrape-objets rassemble tous ces éléments en moins de 120 lignes ; il constitue une base solide que vous pouvez enrichir à volonté.

Pour continuer, explorez la documentation officielle de Pygame et lancez-vous un défi classique : recréer Pong, Snake ou un casse-briques. C’est en construisant de petits jeux complets que l’on progresse le plus vite.

InSkillCoach

À propos de InSkillCoach

Expert en formation et technologies

Coach spécialisé dans les technologies avancées et l'IA, porté par GNeurone Inc.

Certifications:

  • AWS Certified Solutions Architect – Professional
  • Certifications Google Cloud
  • Microsoft Certified: DevOps Engineer Expert
  • Certified Kubernetes Administrator (CKA)
  • CompTIA Security+
1.8k
122

Commentaires

Les commentaires sont alimentés par GitHub Discussions

Connectez-vous avec GitHub pour participer à la discussion

Lien copié !