Accueil

Traduction

Tutoriel Python - sommaire

Tutoriel Python - recherche

L'auteur : Patrick Darcheville

Vous pouvez me contacter via Facebook pour questions & suggestions : Page Facebook relative à mon site

Programmer des jeux en Python avec la librairie Pygame

Il s'agit du premier des chapitres sur la bibliothèque Pygame

La bibliothèque pygame

Présentation

Pygame est une bibliothèque libre multiplate-forme qui facilite le développement de jeux vidéo temps réel avec le langage de programmation Python.
Construite sur la bibliothèque SDL (Simple DirectMedia Layer), elle permet de programmer la partie multimédia (graphismes, son et entrées au clavier, à la souris ou avec joystick) sans se heurter aux difficultés des langages de bas niveaux comme le C.
Pygame est donc une couche logicielle entre le développeur et la bibliothèque SDL.

Installation de Pygame

Pour installer Pygame il suffit d'utiliser l'utilitaire pip.
La commande à partir de l'invite de commande windows :
pip install pygame

Pygame installée, tapez "import pygame" dans la console Python.

>>> import pygame
pygame 2.5.2 (SDL 2.28.3, Python 3.9.1)
Hello from the pygame community. https://www.pygame.org/contribute.html
>>>

J'ai donc installé la version 2.5 de pygame qui inclut la version 2.28 de SDL).

Premier jeu avec Pygame

Je vous invite à écrire le script ci-dessous puis de l'exécuter.

Il s'agit d'un jeu basique. Avec les touches de direction gauche et droite vous déplacer le carré vert pour éviter une collision avec le carré rouge qui balaie la fenêtre de jeu de gauche à droite. Dès qu'il y a collision entre les deux carrés, le jeu s'arrête. L'objectif est donc de tenir le plus longtemps.

Les carrés sont les "sprites" de ce jeu.

Le code du jeu

Créez un dossier à la racine de c: et nommez le "pygame_prog".
Enregistrez le programme sous le nom "premier_jeu.py".

Ne cherchez pas à comprendre ce code pour l'instant. C'est prématuré !
Je vous demande de vous imprégnier de la nouvelle syntaxe découlant de l'emploi de la bibliothèque pygame.

Notez que les couleurs sont exprimées selon le code RGB (Red Greeen Blue) sous forme d'un tuple de trois entiers compris chacuns entre 0 et 255.
Exemples de notation des couleurs :

rouge = (255, 0, 0)
vert = (0,255,0)
bleu = (0, 0, 255) 

Ces différentes couleurs sont utilisées pour remplir la fenêtre de jeu et les formes dessinées (des carrés ici).
Vous verrez dans un chapitre ultérieur que l'on peut utiliser aussi les noms (anglais bien sûr) des couleurs.

Le rendu

Exécutez le programme à partir de l'IDLE OU à partir de l'invite de commandes (après avoir sélectionné le bon répertoire).

Si vous trouvez que c'est trop lent/trop rapide il suffit de modifier l'instruction "vitesse =20" qui indique le nombre d'itérations de la boucle de jeu par seconde.

Attention je triche ! En effet le rendu ci-dessus ne correspond pas à un programme Pygame-Python mais à une page HTML (avec aussi du SVG & JS).
En effet un programme Python ne peut pas tourner dans un navigateur (pas encore ...)
Donc pour développer des jeux en ligne (exécutés par un navigateur) il faut mieux recourir à JavaScript.

Le système de coordonnées Pygame

La fenêtre de jeu est munie d’un système de coordonnées orthonormé.
L’origine du repère (le point 0, 0), est le coin supérieur gauche de la fenêtre.
L’axe des Y est l’axe vertical orienté vers le bas.
L’axe des X est l’axe horizontal orienté vers la droite.

Création de programme avec Pygame

Tous les programmes qui suivent seront stockés dans le dossier "pygame_prog" (à la racine de c:).

Premier programme : pygame_test0.py

Le code

Il faut bien sur importer la bibliothèque (tous les modules).

Pygame.init() : initialise tous les modules de pygame.

Avec la troisième instruction on définit une fenêtre de jeu de 400 par 400.
Notez que la fonction display.set_mode() est argumentée avec un tuple (largeur, hauteur).

Le rendu

Exécutez ce programme à partir de l'invite de commandes (après avoir sélectionné le bon répertoire).

C:\Users\boulanger>cd c:\pygame_prog
c:\pygame_prog>py pygame_test0.py

La fenêtre de jeu s'affiche puis disparait aussitôt.
Un programme de jeu doit comporter obligatoirement une boucle de jeu !

Deuxième programme

Le code

Le programme comporte une boucle de jeu sous forme d'une boucle infinie.

Le rendu

Exécutez ce programme à partir de l'invite de commandes.
Une fenêtre de jeu (avec un fond noir) s'affiche.
Problème : on n'arrive pas à la fermer même en cliquant sur le bouton de fermeture ...
La fenêtre a pour titre "pygame window" ; c'est la légende par défaut de la barre de titre de la fenêtre.

Vous pouvez aussi exécuter un programme Python à partir de l'explorateur de fichiers. Il suffit de double-cliquer sur le fichier d'extension .py.

Troisième programme

J'introduis maintenant la gestion des évènements avec Pygame.

Le code

Avec la fonction display.set_caption() je personnalise la légende de la fenêtre de jeu.

La fonction pygame.event.get() permet d’intercepter tous les événements entrants notamment depuis le clavier, la souris, etc.
Ici on quitte la boucle de jeu si on clique sur le bouton X de la fenêtre de jeu.
En effet si le test (if event.type ==pygame.QUIT ) retourne VRAI alors la valeur de la variable boucle_jeu passe à False donc on sort de la boucle infinie.
Attention, les événements sont des constantes qui doivent être écrites en majuscules.

Le rendu

La fenêtre s'affiche avec le texte "Ma fenêtre" dans la barre de titre.
Cliquez sur X ; la fenêtre se ferme.

Ce programme sera le squelette de tous les programmes futurs.
En effet ce script comprend une boucle de jeu et la possibilité pour l'utilisateur de la quitter.

Quatrième programme

Le code

Avant d'insérer des images, redéfinissez éventuellement leurs dimensions afin qu'elles ne fassent que quelques dizaines de pixels tant en hauteur qu'en largeur (utilisez à cette fin le logiciel Paint).
Je rappelle que pour lancer ce logiciel il suffit de tapez "paint" dans la zone "rechercher" de la barre d'état.

Le rendu

Laissez ouvert la fenêtre de jeu une dizaine de secondes. Le compteur affiche plusieurs milliers ... Donc le nombre d'itérations de la boucle de jeu par seconde est énorme ; alors que 24 images à la seconde suffisent pour donner de la fluidité. 24 est d'ailleurs le nombre d'images à la seconde d'un film.

La solution

Mais il est possible de gérer la FPS (Fréquence Par Seconde) : nombre d'itérations par seconde de la boucle de jeu.

Je vais désormais gérer le nombre d'itérations par seconde de la boucle de jeu.
Je crée donc un objet de type pygame.time.clock que je nomme frequence

La méthode tick(frame) d'un objet pygame.time.Clock se place dans la boucle et prend en argument le nombre d'itérations par seconde de la boucle de jeu.

Le rendu :
Laissez la fenêtre de jeu ouverte une dizaine de secondes ; le compteur affiche autour de 300 (30 par 10).

Une image en guise de fond

Le fond peut être une image.

Le code

L'image "nuit_etoilee.jpg" a été récupérée sur la toile. Avec Paint j'ai modifié les dimensions pour qu'elles correspondent à celles fenêtre (600 par 400).

Le rendu

initiation à pygame

Pour que l'animation devienne un jeu basique

Cependant c'est vraiment un jeu basique car les collisions ne sont pas gérées, il n'y a pas de score, pas de son, etc.

Le code du jeu basique

Il faut déterminer la position initiale de chaque sprite.
La planète se déplace automatiquement dans la fenêtre de jeu selon un delta de 3 tantôt positif (si gauche vers droite OU si haut vers bas) et tantôt négatif (si droite vers gauche OU bas vers haut).
Le taux de rafraichissement (FPS) est de 24 images à la seconde (comme un film).

Les deux "sprites" font environ 100 par 100 pixels ; c'est pour cette raison que "limite" est fixée à 500 (600 -100).

Le rendu

initiation à pygame

Jeu : déplacez avec les touches de direction la fusée pour éviter une collision avec la planète.
Si vous jugez que ça va trop vite, vous pouvez modifier la FPS.
Problème : la fusée peut sortir de la fenêtre ...

Simplifier le code

Rajoutez en début de programme l'instruction from pygame.locals import * Vous pouvez alors simplifier les instructions relatives aux évènements.

if event.type ==QUIT:
	boucle_jeu =False
	if event.type == KEYDOWN :
		if event.key == K_LEFT : 
                           ...
        if event.key == K_RIGHT : 
                           ...
        if event.key == K_UP :
                             ...
        if event.key == K_DOWN :
...                  ...

Donc vous n'avez plus besoin de préfixer les constantes événementielles du terme "pygame."

Les surfaces

Jusqu'à présent le fond de la fenêtre était une couleur unie. Mais vous pouvez dessiner des rectangles dans la fenêtre de jeu.
On dit que l'on définit des surfaces.

Un programme avec des surfaces simples

Le code

Analyse du script

Remaarque : la commande pygame.quit() est conseillée en fin de script ; c'est l'invers de pygame.init().
Cette instruction ne doit être exécutée qu'une fois et doit donc être située après la boucle de jeu.

Dans le script ci-dessus j'ai utilisé pygame.Surface() pour crée des rectangles remplis d'une couleur unie qui seront positionnés dans la fenêtre de jeu et qu'on appelle surfaces.
Mais attention la notion de surface est beaucoup plus large : la fenêtre de jeu est une surface, un texte est une surface, une image chargée est une surface.

Pour positionner une surface "fille" dans une surface "mère" il faut utiliser la commande surface_Mère.blit(surfaceFille, (x,y)).
En général on positionne la surface "fille" dans la fenêtre de jeu , qui se nomme toujours "fenetre" dans mes scripts. Donc l'instruction devient alors : fenetre.blit(nomSurface, (x,y))

Pour remplir une surface de type rectangle avec une couleur il faut utiliser la commande nomSurface.fill(couleur).
L'argument "couleur" correspond en général à une variable stockant un tuple (code RGB de la couleur).

Le rendu

initiation à pygame

La fenêtre d'exécution (de l'IDLE) retourne :
type de surface1 : class 'pygame.surface.Surface'
Donc on a créé des instances de la classe pygame.surface.Surface

Exercice

Seriez vous capable de concevoir une fenêtre de jeu correspondant au drapeau tricolore ?

La notation RGB offre 256 * 256 * 256 couleurs possibles ; c'est énorme !

Des liens utiles :
La notation RGB des 16 couleurs de base
Une application en ligne pour avoir le code RGB d'une couleur composée via trois curseurs

La module draw

Le module draw permet de créer des formes géométriques.

Le script

Dans tous les cas ces paramètres de position et de taille sont précisés sous forme d'un tuple.
Avant ce tuple, il faut préciser la surface cible et la couleur de remplissage de la forme.

Le rendu

initiation à pygame

Info affichée dans le shell :
type de polygone : class 'pygame.rect.Rect'
Via la commande draw on crée des objets de type rect ...
Je n'en dis pas plus pour le moment ; j'aurais l'occasion de revenir sur cette notion d'objet de type rect.

Forme dans une surface

Plutôt que d'être dessinée directement dans la fenêtre de jeu, une forme peut être dessinée dans une surface.

Le programme

Le rendu

pygame - les surfaces et les formes

On voit bien que les formes de fond rouge et noir sont incluses dans des rectangles de fond blanc.
Bien évidemment dans le cadre d'un jeu il faudrait que les surfaces soient remplies de vert comme la couleur de fond de la fenêtre de jeu.

Infos affichées dans le shell :

type de surface3 : class 'pygame.surface.Surface'
type de forme3 : class 'pygame.surface.Surface'

Une forme dessinée dans une surface est confondue avec la surface qui l'accueille.

En guise de conclusion

Retour sur le jeu

Vous disposez maintenant de toutes les connaissances pour comprendre le premier script de ce chapitre (premier_jeu.py).
Ainsi vous savez dessiner des rectangles et les animer automatiquement (avec gestion du rebondi) ou déplacer via le clavier.

Coordonnées x,y des carrés

XR = 200  # abscisse  du carré rouge
YR = 200  # ordonnée  du carré rouge
XV = 175  # abscisse du carré vert
YV = 400  # ordonnée  du carré vert

R comme rouge et V comme vert

Gestion des collisions

# gestion collision entre deux carrés
   if (abs(XV-XR) < cote) and (abs(YV-YR) < cote) :
      boucle_jeu = False

En fait c'est très simple ; si l'écart absolu entre les abscisses ET les ordonnées des carrés est inférieur au côté du carré cela signifie qu'il y a chevauchement des deux carrés donc collision.

Gestion du rebondi du carré rouge

La variable delta doit alternativement être égal à 3 ou -3.

#gestion rebondissement du carré rouge
   if XR >= limite : 
       XR = limite
       delta = -3 
   elif XR <= 0: 
       XR = 0 
       delta = 3

Gestion du carré vert

Déplacement du carré vert par clavier :

     if event.type == pygame.KEYDOWN :
            if event.key == pygame.K_RIGHT :
                XV+=ecart # déplacement à droite
            if event.key ==pygame.K_LEFT:
                XV-=ecart   # déplacement à gauche
   XR += delta
   YV -= remontee 

Pour que le carré vert reste dans la fenêtre de jeu :

   if YV <=0 : 
         YV = 400
         XV = 175
   if XV <=0 :
         XV = 0
   if XV >= limite:
         XV = limite

Testez vos connaissances

Le meilleur moyen de vérifier si vous avez assimilé et de réaliser une animation pygame : "la boule rouge rebondissante".
La fenêtre représente en effet un billard et le cercle rouge est une boule. initiation à pygame

Je vous communique un extrait du programme. À vous de compléter.

# pygame_test9.py
# la boule rebondissante
import pygame
from pygame.locals import *
pygame.init()
dimensions =(400,600)
rouge = ...
vert = ...
rayon = 30
limiteX = ...
limiteY = ...
vitesse = 20
deltaX= 4
deltaY = 6
boucle_jeu = True
fenetre = pygame.display.set_mode (...)
pygame.display.set_caption(...)
clock = ...

# coordonnées du centre de la boule en début de jeu
CX = 200  
CY = 300  

#  début boucle de jeu
while boucle_jeu :
      clock.tick(vitesse)
      for event in pygame.event.get():
      # boucle de gestion d'évènements
            if event.type == pygame.QUIT: 
                  boucle_jeu = False
      
      CX+=...
      CY+=...
	  
	  #gestion rebondi de la boule rouge
      if CX >= limiteX: 
            CX = limiteX
            deltaX = -deltaX
      if CX <= ... 
            ...
            ...
      if CY >= ...
            ...
            ...
      if CY <= ...
            ...
            ...
    
      fenetre.fill(vert)          
      pygame.draw.circle(...)
      pygame.display. ...
# fin boucle de jeu
pygame.quit()

À chaque itération la boule se déplace de 4 pixels sur l'axe X et de 6 pixels sur l'axe Y (deltaX & deltaY)/
La boule ne doit pas sortir de la fenêtre donc CX, CY ne doivent pas être inférieurs à rayon ; CX ne doit pas être supérieur à limiteX (largeur - rayon) et CY ne doit dépasser limiteY (hauteur - rayon).

Récupération des images et scripts

Programmes et images