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.
InSkillCoach
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()ouconvert_alpha()après chaquepygame.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.
À 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+
Commentaires
Les commentaires sont alimentés par GitHub Discussions
Connectez-vous avec GitHub pour participer à la discussion