Vous pouvez me contacter via Facebook pour questions & suggestions :
Page Facebook relative à mon site
Pygame est une bibliothèque libre multiplate-forme qui facilite le développement de jeux vidéo avec le langage
Python.
Pour installer Pygame il faut faire appel à l'utilitaire pip.
À partir de l'invite de commandes tapez : pip install pygame
Pygame installée, saisissez "import pygame" dans la console Python :
C:\Users\darch>pip install pygame Installing collected packages: pygame Successfully installed pygame-2.6.1 C:\Users\darch>py >>> import pygame pygame 2.6.1 (SDL 2.28.4, Python 3.13.2)
Tous les programmes de ce chapitre (et des suivants) seront stockés dans le dossier "c:\pygame_jeux"
Ce répertoire contiendra un sous-dossier nommé "images_sons" stockant les images et les fichiers audio dont vous
aurez besoin si vous souhaitez recréer certains scripts.
'Uploadez' la version compressée du fichier 'images_sons'
Ce script sera le squelette de tous les futurs.
En effet ce programme comprend une boucle de jeu et la possibilité pour l'utilisateur de quitter cette boucle.
# pygame_squelette.py
import pygame as pyg
pyg.init()
fenetre =pyg.display.set_mode((400,400))
pyg.display.set_caption('Ma fenêtre')
boucle_jeu = True
while boucle_jeu :
for event in pyg.event.get():
if event.type ==pyg.QUIT:
boucle_jeu =False
Avec la fonction display.set_caption() je personnalise le titre de la fenêtre de jeu.
while boucle_jeu : création d'une boucle de jeu tant que la variable "boucle_jeu" est à True.
La fonction event.get() permet d’intercepter tous les événements 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 ==pyg.QUIT est vérifié alors la valeur de la
variable boucle_jeu passe à False donc on sort de la boucle de jeu.
Attention, les événements sont des constantes qui doivent être écrites en majuscules.
Par défaut la fenêtre de jeu a un fond noir.
#pygame_images.py
import pygame as pyg
pyg.init()
fenetre = pyg.display.set_mode((600,600))
pyg.display.set_caption('Ma fenêtre')
couleur_fond = (255,255,255)
image1 = pyg.image.load("images_sons/planete.png").convert_alpha()
image2 = pyg.image.load("images_sons/fusee.png").convert_alpha()
compteur = 0
boucle_jeu = True
#-----------------
while boucle_jeu :
for event in pyg.event.get():
if event.type ==pyg.QUIT:
boucle_jeu =False
fenetre.fill(couleur_fond)
fenetre.blit(image1,(0,0))
fenetre.blit(image2,(250,250))
pyg.display.flip()
compteur+=1
#---------------
print("nombre itérations : ",compteur)
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.
Heureusement il est possible de gérer la FPS (Fréquence Par Seconde) c'est à dire nombre d'itérations par seconde de la boucle de jeu.
#pygame_frequence.py
import pygame
pygame.init()
largeur = 600
hauteur = 400
fenetre = pygame.display.set_mode((largeur, hauteur))
pygame.display.set_caption("gérer la fréquence")
frequence = pygame.time.Clock()
compteur =0
boucle_jeu = True
# -------------
while boucle_jeu :
frequence.tick(30)
compteur+=1
for event in pygame.event.get():
if event.type ==pygame.QUIT:
boucle_jeu = False
# -----------
print("nombre d'itérations", compteur)
frequence = pygame.time.Clock() : je crée donc un objet de type pygame.time.clock nommé "frequence".
Cet objet comprend plusieurs méthodes dont la méthode tick() pour gérer la FPS.
frequence.tick(30) : fixe à 30 la FPS (nombre d'itérations par seconde).
Laissez la fenêtre de jeu ouverte une dizaine de secondes avant de cliquer sur le bouton X de la fenêtre de jeu. Cette fois le compteur affiche un nombre autour de 300 , ce qui est logique : 10 *30 = 300.
Le fond de la fenêtre de jeu peut être une image.
Il faut bien sûr que ses dimensions coïncident avec celles de la fenêtre de jeu.
# pygame_image_fond.py
# image matricielle en guise de fond de fenêtre
import pygame
pygame.init()
largeur = 600
hauteur = 400
fenetre = pygame.display.set_mode((largeur, hauteur))
pygame.display.set_caption("Image en guise de fond")
frequence = pygame.time.Clock()
X = 300
Y= 150
fusee = pygame.image.load("images_sons/fusee.png").convert_alpha()
fond = pygame.image.load("images_sons/nuit_etoilee.jpg").convert()
fenetre.blit(fond, (0,0))
fenetre.blit(fusee, (X,Y))
pygame.display.update()
compteur =0
boucle_jeu = True
#---------------------------
while boucle_jeu :
frequence.tick(30)
compteur+=1
for event in pygame.event.get():
if event.type ==pygame.QUIT:
boucle_jeu = False
#------------------------
print("nombre d'itérations", compteur)
L'image "nuit_etoilee.jpg" a été récupérée sur la toile.
Avec Paint j'ai modifié ses dimensions pour qu'elles correspondent à celles de la fenêtre de jeu (600 par 400).
Un sprite est un élément graphique animé et partiellement transparent qui se déplace sur l'écran dans un jeu vidéo, superposé au décor de fond. Dans le programme ci-dessous je vous montre comment déplacer un sprite avec le clavier.
# pygame_deplacer_fusee.py
import pygame
pygame.init()
X =600
Y= 600
fenetre = pygame.display.set_mode((X,Y))
pygame.display.set_caption('Déplacement fusée par clavier')
couleur_fond = (255,255,255)
fusee = pygame.image.load("images_sons/fusee.png").convert_alpha()
XF = X/2
YF= Y/2
deltaF = 5
clock = pygame.time.Clock()
boucle_jeu = True
#----------------boucle de jeu -------------
while boucle_jeu :
for event in pygame.event.get():
if event.type ==pygame.QUIT:
boucle_jeu =False
# déplacer la fusée avec les touches de direction
if event.type == pygame.KEYDOWN :
if event.key == pygame.K_LEFT :
XF-=deltaF
if event.key == pygame.K_RIGHT :
XF+=deltaF
if event.key == pygame.K_UP :
YF-=deltaF
if event.key == pygame.K_DOWN :
YF+=deltaF
# affichage & dessins & actualisation
fenetre.fill(couleur_fond)
fenetre.blit(fusee,(XF,YF))
pygame.display.flip()
clock.tick(25)
#-------------fin boucle--------------
print("fin de déplacement")
Étudiez attentivement la syntaxe pour gérer le clavier et plus particulièrement
les touches de direction.
if event.type == pygame.KEYDOWN : si appui sur une touche du clavier
if event.key == pygame.K_LEFT : si la touche appuyée est la touche < du pavé directionnel
Problème : l'appui continu sur une touche directionnelle n'est pas opérant.
Il faut à chaque fois relacher la touche puis appuyer de nouveau.
Rassurez-vous ; il y a une solution ; je vous demande un peu de patience.
Dès que vous avez appuyé sur la touche X de la fenêtre de jeu, vous ne pouvez plus déplacer la fusée puisque vous êtes sorti de la boucle de jeu.
Il s'agit certes d'un jeu basique mais utile sur un plan pédagogique. Je vous propose deux versions.
Les collisions ne sont pas gérées, il n'y a pas de score, pas de son, les déplacements par clavier sont laborieux.
#pygame_jeu_basique.py
import pygame
from pygame.locals import *
pygame.init()
fenetre = pygame.display.set_mode((600,600))
pygame.display.set_caption('Ma fenêtre')
couleur_fond = (255,255,255)
planete = pygame.image.load("images_sons/planete.png").convert_alpha()
fusee = pygame.image.load("images_sons/fusee.png").convert_alpha()
# coordonnées fusée
XF = 250
YF= 450
# coordonnées planète
XP =100
YP=0
deltaP = 3 # déplacement par itération de la planète
limite = 500
clock = pygame.time.Clock()
boucle_jeu = True
#------------------------------
while boucle_jeu :
for event in pygame.event.get():
if event.type ==QUIT:
boucle_jeu =False
# déplacer la fusée avec les touches de direction
if event.type == KEYDOWN :
if event.key == K_LEFT :
XF-=5
if event.key == K_RIGHT :
XF+=5
if event.key == K_UP :
YF-=5
if event.key == K_DOWN :
YF+=5
# déplacement planète qui ne doit pas sortir de la fenêtre de jeu
if XP >= limite :
XP = limite
deltaP = -3
if XP <= 0:
XP = 0
deltaP = 3
if YP >=limite :
YP = limite
deltaP = -3
if YP <=0 :
YP = 0
deltaP = 3
XP+=deltaP
YP +=deltaP
# affichage & dessins & actualisation
fenetre.fill(couleur_fond)
fenetre.blit(planete,(XP,YP))
fenetre.blit(fusee,(XF,YF))
pygame.display.flip()
clock.tick(20)
#--------------------------------
pygame.quit()
from pygame.locals import * : le module "locals" permet de simplifier les instructions rélatives aux évènements : vous n'avez plus besoin de préfixer les constantes événementielles du terme "pygame".
Les deux "sprites" font un peu moins de 100px de côté ; c'est pour cette raison que la variable "limite" est fixée à 500 (X -100).
Le joueur doit déplacer la souris avec les touches de direction du clavier pour éviter une collision avec l'astéroïde.
Le déplacement de la fusée n'est pas du tout efficace ; un appui continu sur une ou plusieurs touches directionnelles n'est pas possible.
Il faut à chaque fois appuyer puis relacher la touche.
De plus la fusée peut sortir de la fenêtre de jeu ; donc on peut tricher ...
Ci-dessous une version nettement améliorée de ce jeu basique.
Ce jeu reste basique car il n'y a que deux sprites.
#pygame_jeu_basique_plus.py
import pygame
from pygame.locals import *
import time
pygame.init()
X, Y = 600, 600
fenetre = pygame.display.set_mode((X,Y))
pygame.display.set_caption('Jeu basique amélioré')
couleur_fond = 'blue'
planete = pygame.image.load("images_sons/planete.png").convert_alpha()
fusee = pygame.image.load("images_sons/fusee.png").convert_alpha()
#paramètres fusée
XF = X-100
YF= Y-100
deltaF = 5
#paramètres astéroïde
XP =0
YP=0
deltaP = 3
#paramètres généraux
limite = X -80
ecart =80
clock = pygame.time.Clock()
collisionsN = 0
boucle_jeu = True
#--------------boucle de jeu
while boucle_jeu :
for event in pygame.event.get():
if event.type ==QUIT:
boucle_jeu =False
# déplacer la fusée avec les touches de direction
touches = pygame.key.get_pressed()
if XF >0 :
if touches[pygame.K_LEFT]:
XF-=deltaF
if XF < limite:
if touches[pygame.K_RIGHT]:
XF+=deltaF
if YF > 0 :
if touches[pygame.K_UP]:
YF-=deltaF
if YF < limite:
if touches[pygame.K_DOWN]:
YF+=deltaF
# déplacement astéroïde
if XP >= limite :
XP = limite
deltaP = -3
if XP <= 0:
XP = 0
deltaP = 3
if YP >=limite :
YP = limite
deltaP = -3
if YP <=0 :
YP = 0
deltaP = 3
XP+=deltaP
YP +=deltaP
# affichage & dessins & actualisation
fenetre.fill(couleur_fond)
fenetre.blit(planete,(XP,YP))
fenetre.blit(fusee,(XF,YF))
pygame.display.flip()
clock.tick(20)
# gestion collision entre deux sprite
if (abs(XP-XF)< ecart) and (abs(YP-YF) < ecart) :
collisionsN +=1
print("collision")
if collisionsN >9 :
boucle_jeu =False
#------------fin boucle-----------
print("10 collisions ou plus ! Vous êtes éliminé")
time.sleep(5)
pygame.quit()
# déplacer la fusée avec les touches de direction
touches = pygame.key.get_pressed()
if XF >0 :
if touches[pygame.K_LEFT]:
XF-=deltaF
if XF < limite:
if touches[pygame.K_RIGHT]:
XF+=deltaF
if YF > 0 :
if touches[pygame.K_UP]:
YF-=deltaF
if YF < limite:
if touches[pygame.K_DOWN]:
YF+=deltaF
La fusée ne peut plus sortir de la fenêtre de jeu ; on ne peut déplacer à gauche que si XF > 0 ; on ne peut déplacer à droite que si XF < à 'limite'; on ne peut déplacer en bas que si YF < à 'limite', etc.
La fonction pygame.key.get_pressed() permet de détecter plusieurs touches en même temps sans problème.
Choisissez l'outil KEYDOWN pour un évènement unique et l'outil get_pressed() pour le déplacement continu
OU pour un contexte qui nécessite la connaissance de l’état de plusieurs touches.
Donc pour ce jeu le recours à l'outil pygame.key.get_pressed() est pertinent car on veut pouvoir utiliser, par exemple,
les touches 'up' et 'left' en même temps. De plus un appui continu sur une ou deux touches sera possible.
# gestion collision entre deux sprite
if (abs(XP-XF)< ecart) and (abs(YP-YF) < ecart) :
collisionsN +=1
print("collision")
if collisionsN >9 :
boucle_jeu =False
Il s'agit pour le moment d'une gestion des collisions empirique.
Si les différences absolues entre les abscisses et ordonnées des deux objets est inférieur à ecart (qui vaut 80)
cela signifie que les deux images commencent à se chevaucher puisque les dimensions des images tournent autour de 80.
Vous verrez dans le chapitre 29 (le jeu de casse briques) que le module pygame.sprite propose des fonctions très utiles pour gérer une collision en une seule fonction et sans que le développeur ait à faire des calculs savants.
Le déplacement par clavier de la fusée est beaucoup plus ergonomique.
Appuyez, par exemple, simultanément sur les touches "right" et "up" pour un déplacement en diagonale.
Si vous jugez que ça va trop vite / trop lentement, il suffit de modifier la FPS donc l'argument de clock.tick().
Télécharger un fichier ZIP
Après décompression vous obtiendrez les deux versions du jeu basique.
Vous pourrez ainsi comparer les deux techniques de gestion du clavier et apprécier la supériorité de la solution
pygame.key.get_pressed() dans le cadre de ce jeu.