Vous êtes sur la page 1sur 18

Spécialité NSI Projet n° 3 – Recherche les paires 14/12/2023

Nous allons dans ce projet, nous intéresser à une version personnelle du jeu « Recherche les paires ».

Principe du jeu
On souhaite réaliser le jeu « Recherche les paires » qui est un jeu de mémoire dans lequel un certain nombre
d’images sont montrées au joueur pendant quelques secondes. Toutes les images sont par paires, et une fois que
les cartes sont retournées, le joueur doit cliquer sur le dos de celles-ci pour les retourner et retrouver les paires :

Fig. 1 – Affichage de la fenêtre au début du jeu Fig. 2 – Cas 1 : Cartes par paires + 1 carte

Avec les règles que nous adopterons, les trois cas suivants peuvent se produire :

▪ Cas 1 : Lorsqu’après plusieurs coups les cartes retournées par le joueur forment des paires, elles restent
retournées lorsque le joueur retourne ensuite une première carte (Figure 2 : Carte entourée d’un cercle) ;

▪ Cas 2 : Lorsque deux cartes retournées successivement par le joueur sont identiques (figure 3 : Cartes
entourées d’un cercle), ces cartes s’ajoutent aux cartes retournées constituant des paires (figure 4).
Lorsque le joueur retourne ensuite une carte supplémentaire, il se retrouve alors dans le premier cas ;

Fig. 3 – Cas 2 : Cartes par paires + 2 cartes identiques Fig. 4 – Deux cartes identiques s’ajoutent au paires

1
Spécialité NSI Projet n° 3 – Recherche les paires 14/12/2023

▪ Cas 3 : Lorsque deux cartes retournées successivement par le joueur sont différentes (Figure 5 : Cartes
entourées d’un cercle), ces cartes ne peuvent pas être ajoutées aux cartes retournées précédemment et
constituant des paires. Ces deux cartes restent alors toutes les deux affichées jusqu’à ce que le joueur
clique sur une troisième carte. Dès que la troisième carte est affichée, la deuxième est masquée car elle
ne constitue pas une paire avec la première carte. (fig. 6 : troisième carte entourée d’un cercle et
deuxième carte masquée et recouverte d’une croix). Le joueur se retrouve alors soit dans le cas 2 si les
deux cartes récemment retournées sont identiques, ou dans ce même cas 3 si les deux cartes récemment
retournées sont différentes.

3 4

5 2

8
6 7

Fig. 5 – Cas 3 : Cartes par paires + 2 cartes différentes Fig. 6 – Cas 3 : 2-ième masquée et 3-ième affichée

Structures de données
Les images
Les cartes du jeu pouvant être masquées (de dos) ou affichées, on pourra les représentera par une liste du type :

𝒔𝒖𝒓𝒇𝒂𝒄𝒆_𝒊𝒎𝒂𝒈𝒆 : Objet du type pygame.Surface représentant une image ;


[𝒔𝒖𝒓𝒇𝒂𝒄𝒆_𝒊𝒎𝒂𝒈𝒆, 𝒗𝒊𝒔𝒊𝒃𝒍𝒆]
𝒗𝒊𝒔𝒊𝒃𝒍𝒆 : Variable booléenne prenant la valeur False si la carte est masquée,
True si elle est affichée.

Si la carte est masquée ou de dos, 𝒗𝒊𝒔𝒊𝒃𝒍𝒆 aura la valeur 𝑭𝒂𝒍𝒔𝒆 et l’image Dos.jpg du dos des cartes devra être
affichée.

Le premier élément de cette liste associée à une image, 𝒔𝒖𝒓𝒇𝒂𝒄𝒆_𝒊𝒎𝒂𝒈𝒆, référencera l’une des images parmi
Chien_1.jpg, Chien_2.jpg, …, Chien_20.jpg. Par ailleurs, chacune de ces images aura une largeur de 144 pixels et
une hauteur de 144 pixels.

Le jeu dispose donc de 20 images de chiens différentes, mais seulement 10 images parmi les 20 seront choisies
de façon aléatoire. Par ailleurs, les images étant en double dans le jeu afin de pouvoir constituer les paires, il y
aura 20 cartes affichées au début du jeu (10 paires). Nous choisirons d’afficher ces 20 images selon 4 lignes et 5
colonnes. Par ailleurs, la durée d’observation des cartes par le joueur au début du jeu sera de 5 secondes.

2
Spécialité NSI Projet n° 3 – Recherche les paires 14/12/2023

La grille du jeu
Compte tenu de la nature du jeu dans lequel on a un tableau ou une grille d’images, il paraît naturel de placer les
éléments dans une liste à au moins deux dimensions que nous nommerons 𝒈𝒓𝒊𝒍𝒍𝒆_𝒋𝒆𝒖. Cette variable sera une
variable globale et sera conçue comme une liste de listes, chaque sous-liste correspondant à une ligne de la
grille. Une ligne de la grille sera donc une liste dont chaque élément correspond à une image représentée elle-
même par une liste du type [𝒔𝒖𝒓𝒇𝒂𝒄𝒆_𝒊𝒎𝒂𝒈𝒆, 𝒗𝒊𝒔𝒊𝒃𝒍𝒆]. La variable 𝒈𝒓𝒊𝒍𝒍𝒆_𝒋𝒆𝒖 référencera donc une liste non
pas à deux dimensions, mais une liste à trois dimensions :
▪ Première dimension : l’index 𝒊 de la ligne ;
▪ Deuxième dimension : L’index 𝒋 de la colonne ;
▪ Troisième dimension ; Index pouvant prendre la valeur 0 pour référencer l’objet pygame.Surface
représentant une image, ou la valeur 1 pour référencer la variable booléenne 𝒗𝒊𝒔𝒊𝒃𝒍𝒆.

Ainsi, pour récupérer dans une variable 𝒊𝒎𝒈 l’objet du


𝑗
type pygame.Surface associé à l’image située à la ligne 𝒊
et à la colonne 𝒋 dans la grille du jeu, on pourra écrire :

𝒊𝒎𝒈 = 𝒈𝒓𝒊𝒍𝒍𝒆_𝒋𝒆𝒖[𝒊][𝒋][𝟎]

Pour récupérer la valeur booléenne indiquant si l’image


est visible (retournée) ou masquée (de dos) dans une 𝑖
variable nommée 𝒗𝒊𝒔𝒊𝒃𝒍𝒆, on pourra écrire l’instruction :

𝒗𝒊𝒔𝒊𝒃𝒍𝒆 = 𝒈𝒓𝒊𝒍𝒍𝒆_𝒋𝒆𝒖[𝒊][𝒋][𝟏]

Pour indiquer que cette image doit être masquée (de dos),
on écrira l’instruction :

𝒈𝒓𝒊𝒍𝒍𝒆_𝒋𝒆𝒖[𝒊][𝒋][𝟏] = 𝑭𝒂𝒍𝒔𝒆

Les variables du jeu


Constantes du jeu
Pour enregistrer les données constantes du jeu que nous avons exposées précédemment, nous définirons un
certain nombre de constantes énumérées ci-dessous. Parmi celles-ci, pour effacer le contenu de la fenêtre
pygame au début de chaque itération dans la boucle principale du jeu, nous définirons une constante BLANC que
nous utiliserons pour remplir la fenêtre de la couleur blanche. De plus, pour imposer le nombre d’images par
secondes affichées à l’écran, nous définirons une constante IPS (Images Par Secondes). Finalement, voici les
constantes que vous pouvez définir dans ce jeu :

▪ WHITE = (255, 255, 255) # Couleur blanche


▪ BLACK = (0, 0, 0) # Couleur noire
▪ GREY = (127, 127, 127) # Couleur grise
▪ BLUE = (0, 0, 255) # Couleur bleue
▪ GREEN = (0, 255, 0) # Couleur verte
▪ RED = (255, 0, 0) # Couleur rouge
▪ IPS = 50 # Nombre d'images par secondes
▪ LARGEUR_IMAGE = 144 # Largeur des images
▪ HAUTEUR_IMAGE = 144 # Hauteur des images
▪ NB_COLONNES = 5 # Nombre de colonnes de la grille

3
Spécialité NSI Projet n° 3 – Recherche les paires 14/12/2023

▪ NB_LIGNES = 4 # Nombre de lignes de la grille


▪ LARGEUR = NB_COLONNES * LARGEUR_IMAGE # Largeur de la fenêtre pygame en pixels
▪ HAUTEUR = NB_LIGNES * HAUTEUR_IMAGE # Hauteur de la fenêtre pygame en pixels
▪ TEMPS_OBSERVATION = 5 # Temps d’observation accordé au joueur au début du jeu

Variables globales du jeu


En plus de la variable globales 𝒈𝒓𝒊𝒍𝒍𝒆_𝒋𝒆𝒖 que nous avons présentée précédemment, et qui pourra être créée par
une fonction 𝒄𝒓𝒆𝒆𝒓_𝒈𝒓𝒊𝒍𝒍𝒆_𝒗𝒊𝒅𝒆(𝒏𝒃_𝒍𝒊𝒈𝒏𝒆𝒔, 𝒏𝒃_𝒄𝒐𝒍𝒐𝒏𝒏𝒆𝒔) dont nous reparlerons ultérieurement, vous
pourrez définir les variables globales suivantes :

▪ 𝒍_𝒊𝒎𝒂𝒈𝒆𝒔 ;
▪ 𝒊𝒎𝒂𝒈𝒆𝒔_𝒓𝒆𝒕𝒐𝒖𝒓𝒏𝒆𝒆𝒔 ;
▪ 𝒍_𝒄𝒐𝒐𝒓𝒅_𝒊𝒎𝒂𝒈𝒆𝒔_𝒓𝒆𝒕𝒐𝒖𝒓𝒏𝒆𝒆𝒔 ;
▪ 𝒇𝒆𝒏 ;
▪ 𝒊𝒑𝒔𝑯𝒐𝒓𝒍𝒐𝒈𝒆 ;
▪ 𝒄𝒂𝒓𝒕𝒆_𝒅𝒐𝒔 ;
▪ 𝒕𝟏 ;
▪ 𝒕𝟐 ;
▪ 𝒈𝒂𝒈𝒏𝒆 ;
▪ 𝒓𝒆𝒋𝒐𝒖𝒆𝒓 ;
▪ 𝒏𝒃_𝒄𝒍𝒊𝒄𝒔

𝒍_𝒊𝒎𝒂𝒈𝒆𝒔 est une liste qui contiendra l’ensemble des références vers les 20 images Chien_1.jpg, Chien_2.jpg, …,
Chien_20.jpg. Cette liste est initialisée comme une liste vide au début du programme.

𝒊𝒎𝒂𝒈𝒆𝒔_𝒓𝒆𝒕𝒐𝒖𝒓𝒏𝒆𝒆𝒔 est un entier qui enregistre le nombre de cartes récemment retournées, c’est-à-dire les
cartes retournées pas encore identifiées comme faisant parties des paires d’images identiques. Dans l’exemple
de la figure 5, sachant que les numéros dans les cercles indiquent l’ordre dans lequel les images ont été
retournées, la valeur de la variable 𝒊𝒎𝒂𝒈𝒆𝒔_𝒓𝒆𝒕𝒐𝒖𝒓𝒏𝒆𝒆𝒔 est 2 et correspond aux images numérotées 7 et 8.
Cette variable est initialisée avec la valeur 0 au début du programme.

𝒍_𝒄𝒐𝒐𝒓𝒅_𝒊𝒎𝒂𝒈𝒆𝒔_𝒓𝒆𝒕𝒐𝒖𝒓𝒏𝒆𝒆𝒔 est une liste de tuples du type (𝒊, 𝒋) où les tuples du type (𝒊, 𝒋) sont les
coordonnées de grille des images récemment retournées, c’est-à-dire des images pas encore identifiées comme
faisant partie des paires d’images identiques. Par exemple, lorsque le jeu est à l’étape de la figure 5, sachant que
les numéros dans les cercles indiquent l’ordre dans lequel les images ont été retournées, le contenu de la variable
𝒍_𝒄𝒐𝒐𝒓𝒅_𝒊𝒎𝒂𝒈𝒆𝒔_𝒓𝒆𝒕𝒐𝒖𝒓𝒏𝒆𝒆𝒔 est alors [(𝟑, 𝟒), (𝟑, 𝟑)]. Au début du programme, cette variable est initialisée
par une liste vide [].

𝒇𝒆𝒏 est une référence vers la fenêtre pygame de notre jeu. Nous verrons comment on peut créer une fenêtre
dans pygame ultérieurement.

𝒊𝒑𝒔𝑯𝒐𝒓𝒍𝒐𝒈𝒆 est une référence vers un objet du type pygame.time.Clock. Cet objet permet, à l’aide de la
constante IPS et de la méthode tick() des objets du type Clock, de fixer le nombre d’images par secondes
affichées dans notre jeu.

𝒄𝒂𝒓𝒕𝒆_𝒅𝒐𝒔 est une référence vers l’image Dos.jpg représentant le dos des cartes, cette image étant affichée
lorsque les cartes sont masquées (de dos).

4
Spécialité NSI Projet n° 3 – Recherche les paires 14/12/2023

𝒕𝟏 et 𝒕𝟐 sont des variables globales permettant de mesurer le temps écoulé depuis le début de l’exécution du
jeu, de sorte à pouvoir afficher les images dans la fenêtre durant le temps d’observation défini précédemment. t1
sera initialisé en appelant la fonction perf_counter() du module time intégrée au langage Python, juste avant de
rentrer dans la boucle principale du jeu. t2 sera déterminé aussi en utilisant la fonction perf_counter(), mais à
chaque itération dans la boucle principale du jeu, et lorsque (𝒕𝟐 − 𝒕𝟏) sera supérieur à TEMPS_OBSERVATION,
toutes les cartes seront masquées, et le joueur pourra commencer à cliquer sur les images pour retrouver les
paires. De plus, cette durée (𝒕𝟐 − 𝒕𝟏) pourra aussi être utilisée pour calculer le score du joueur.

𝒈𝒂𝒈𝒏𝒆 est une variable qui mémorise le fait que le joueur a gagné ou pas. Cette variable vaut 𝑭𝒂𝒍𝒔𝒆
initialement ;

𝒏𝒃_𝒄𝒍𝒊𝒄𝒔 est un compteur qui enregistre le nombre de clics effectués par le joueur au cours d’une partie, ce
nombre de clics pouvant être utilisé pour calculer le score du joueur.

Les fonctions du jeu


Afin de réaliser un programme lisible, il est nécessaire de décomposer celui-ci en fonctions. Les fonctions que je
vous suggère de créer sont énumérées ci-dessous :

▪ Charger_image() : Fonction qui charge les références des images Chien_1.jpg, Chien_2.jpg, …,
Chien_20.jpg dans une liste, et qui charge l’image du dos des cartes, Dos.jpg, dans une autre variable.
Cette fonction devra renvoyer un tuple du type (carte_dos, l_img) où carte_dos référence l’image Dos.jpg,
et où l_img est la liste de 20 références vers les 20 images des cartes du jeu ;

▪ creer_grille_vide(nb_lignes, nb_colonnes) : Fonction qui créé la grille de début du jeu représentée par une
liste à 3 dimensions, et qui renvoie cette grille. La grille vide est une liste de 𝒏𝒃_𝒍𝒊𝒈𝒏𝒆𝒔 listes, chaque sous-
liste correspondant à une ligne du tableau. Chaque sous liste contiendra 𝒏𝒃_𝒄𝒐𝒍𝒐𝒏𝒏𝒆𝒔 éléments associés
à une carte, ces éléments étant du type [𝑵𝒐𝒏𝒆, 𝒗𝒊𝒔𝒊𝒃𝒍𝒆], l’emplacement des cartes n’étant pas encore
déterminé. Le premier élément de la liste associé à une carte vaut 𝑵𝒐𝒏𝒆, car on ne sait pas encore quelle
image doit être référencée à ce stade dans le jeu ;

▪ alea_grille(grille, nb_lignes, nb_colonnes) : Fonction qui remplit de façon aléatoire la grille avec les
références vers les images carte_1.jpg, carte_2.jpg, ... carte_20.jpg. Le premier élément de la liste
[𝒔𝒖𝒓𝒇𝒂𝒄𝒆_𝒊𝒎𝒂𝒈𝒆, 𝒗𝒊𝒔𝒊𝒃𝒍𝒆] associée à une carte, qui valait 𝑵𝒐𝒏𝒆 avant l’appel de cette fonction, devra
après l’appel de cette fonction référencer une image parmi les vingt images disponibles, l’image référencée
devant être déterminée de façon aléatoire. Il faut bien entendu que chaque image sélectionnée se
retrouve deux fois dans la grille, pour que le joueur puisse retrouver des paires de cartes ;

▪ coord_pixel(i, j, largeur_image, hauteur_image) : Fonction qui renvoie les coordonnées (x, y) du pixel du
point supérieur gauche de l'image à la ligne 𝒊 et à la colonne 𝒋 dans la grille, sachant que les images font
144 X 144 pixels ;

▪ afficher_grille(f, grille, l_img, h_img, nb_lignes, nb_colonnes, surf_img_dos) : Fonction qui affiche les
images des cartes ou du dos des cartes sur la surface d’affichage 𝒇 de pygame, selon que celles-ci sont
retournées ou non ;

▪ afficher_grile_complete(f, grille, l_img, h_img, nb_lignes, nb_colonnes) : Fonction qui affiche toutes les
images des cartes de la grille, que les images soient visibles ou non. Cette fonction permet de montrer au
joueur où se situent les images au début du jeu, pendant une durée limitée ;

5
Spécialité NSI Projet n° 3 – Recherche les paires 14/12/2023

▪ coord_pixels_to_coord_grille(xs, ys, largeur_image, hauteur_image) : Fonction qui reçoit les coordonnées


(xs, ys) du clic de la souris dans la fenêtre pygame, et qui renvoie les coordonnées de grille (i, j) de la carte
correspondante ;

▪ montrer_image(grille, i, j) : Fonction qui rend visible l'image à la ligne 𝒊 et à la colonne 𝒋 dans la grille, en
affectant la valeur True au deuxième élément de la liste [image, visible] associée à cette image ;

▪ cacher_image(grille, i, j) : Fonction qui cache l'image à la ligne 𝒊 et à la colonne 𝒋, en affectant la valeur


False au deuxième élément de la liste [image, visible] ;

▪ grille_résolue(grille) : Fonction qui renvoie True si la grille est complètement résolue, False dans le cas
contraire ;

▪ est_retournee(grille, i, j) : Fonction qui renvoie True si l'image aux coordonnées de grille (𝒊, 𝒋) est
retournée, False dans le cas contraire ;

▪ est_dans_rect(xs, ys, rect) : Fonction qui renvoie True si le point de coordonnées (xs, ys) est dans le
rectangle rect ;

▪ calculer_score(temps, nb_clics) : Fonction qui calcule le score en fonction du temps de jeu écoulé et du
nombre de clics ;

▪ encadrer_image(fenetre, i, j, largeur_image, hauteur_image, couleur) : Fonction qui dessine un rectangle


d'une certaine couleur autour d'une carte pour indiquer qu’elle est sélectionnée. Il s’agit de la carte dont le
joueur cherche la paire. Le fait que cette carte soit encadrée permet au joueur de retrouver rapidement
quelle carte il doit trouver pour former une paire.

6
Spécialité NSI Projet n° 3 – Recherche les paires 14/12/2023

Utilisation du module pygame

I- Installation du module pygame

La façon la plus simple d’installer pygame est d’exécuter la commande suivante dans le PowerShell :

pip install pygame

Si vous avez un message d’erreur vous indiquant que vous devez être administrateur, essayez d’exécuter
l’instruction suivante :

py -m pip install -U pygame --user

Si ça ne fonctionne toujours pas, vous pouvez aussi installer pygame à partir d’un fichier wheel. Il faut trouver le
fichier correspondant à votre version de Python et à la version 64 bit de Windows. On peut trouver ces fichiers
avec le lien suivant :

https://www.lfd.uci.edu/~gohlke/pythonlibs/#pygame

Voici le début de la liste des fichiers que vous pouvez télécharger sur ce site :

pygame‑2.1.2‑pp38‑pypy38_pp73‑win_amd64.whl
pygame‑2.1.2‑cp311‑cp311‑win_amd64.whl
pygame‑2.1.2‑cp311‑cp311‑win32.whl
pygame‑2.1.2‑cp310‑cp310‑win_amd64.whl
pygame‑2.1.2‑cp310‑cp310‑win32.whl

Si votre ordinateur est en 64 bits, il faut télécharger l’un des fichiers se terminant par amd64.whl. Parmi ces
fichiers, téléchargez celui qui correspond à votre version de Python : cp311 pour python 3.11, etc. Pour trouver
votre version de Python, tapez l’instruction suivante dans la console ou le PowerShell :

Python --version

Une fois le fichier téléchargé le bon fichier, ouvrir une console (le PowerShell par exemple), et se placer dans le
répertoire où vous avez téléchargé le fichier, en exécutant la commande :

cd chemin_du_répertoire_de_téléchargement

Exécuter alors l’instruction suivante :

pip install nom_fichier.whl

Pour vérifier ensuite si Pygame est bien installé, lancer IDLE et exécuter l’instruction suivante permettant d’avoir
la version de pygame installée :

>>> import pygame


>>> pygame.__version__

Vous devriez obtenir une sortie vous indiquant la version de Pygame installée.

7
Spécialité NSI Projet n° 3 – Recherche les paires 14/12/2023

Si aucune des méthodes précédentes ne fonctionne, vous pouvez utiliser le logiciel EduPython disponible sur les
ordinateurs de la région. Le module pygame est installé avec EduPython.

Une dernière solution consiste à créer un compte gratuit sur un site comme Replit :

https://replit.com/

Une fois inscrit, vous aurez un espace de stockage pour vos fichiers, et les modules comme pygame et matplotlib
sont disponibles.

1- Création d’une fenêtre avec pygame

➢ Copier puis exécuter le code ci-dessous avec le logiciel de votre choix. On nommera le fichier
fenêtre_pygame.py :

import pygame, sys


from pygame.locals import *

# Initialisation des fonctions de Pygame


pygame.init()
# Création de la surface associée à la fenêtre principale
surface_affichage = pygame.display.set_mode((300, 50))
pygame.display.set_caption('Hello World!')

# Boucle principale
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()

# Mise à jour de l'affichage


pygame.display.update()

L’exécution de ce programme affiche la fenêtre ci-contre :

Explication du code :

▪ import pygame, sys :


La première ligne importe le module pygame ainsi que le module sys. Ainsi, les fonctions qui gèrent les
sons et les graphiques contenues dans le module pygame seront utilisables dans notre programme en les
préfixant du nom du module suivi d’un point, comme dans l’instruction pygame.init(). Le module sys sera
utilisé pour quitter le programme avec l’instruction sys.exit().

8
Spécialité NSI Projet n° 3 – Recherche les paires 14/12/2023

▪ from pygame.locals import * :


La deuxième ligne est aussi une importation, mais au lieu d’utiliser la syntaxe import nomModule, on
utilise la syntaxe from nomModule import*. Cela permet d’utiliser le contenu du module pygame.locals
sans préfixer par le nom de module suivi d’un point. C’est dans ce module que sont définies des constantes
comme QUIT.

▪ pygame.init() :
La fonction init() du module pygame doit être appelée avant tout appel d’autres fonctions de pygame.
Cette fonction a un rôle d’initialisation pour toutes les fonctions de pygame.

▪ surface_affichage = pygame.display.set_mode((100, 50)):


Cette instruction appelle la fonction set_mode() du module pygame.display. Cette fonction prend en
argument un tuple contenant la largeur et la hauteur en pixels de la fenêtre. Elle retourne un objet du type
Surface défini dans le module pygame, qui est référencé par la variable surface_affichage. Les objets du
type Surface sont les objets sur lesquels vont être dessinés les objets à afficher dans la fenêtre.

▪ pygame.display.set_caption('Hello World!'):
Cette instruction définit le texte de la légende qui est affiché dans la barre des titres de la fenêtre à l’aide
de la méthode set_caption() du module pygame.display.

▪ while True:
Nous entrons avec cette instruction dans la boucle principale du jeu, que l’on retrouve dans tous les jeux et
dans toutes les applications graphiques plus généralement. La condition étant toujours vraie (True), c’est
une boucle infinie dont on ne peut sortir, dans notre programme, qu’en fermant la fenêtre, comme nous
allons le voir. C’est dans cette boucle que s’effectuent les trois opérations les plus importantes dans une
application graphique :
• Gestion des événements ;
• Mise à jour de l’état du jeu ;
• Dessin de l’état du jeu sur l’écran.

La gestion des événements désigne la prise en compte d’un clic de souris, l’appui sur une touche du clavier,
etc. En réponse à ces événements, l’état du jeu est modifié, c’est-à-dire que les variables qui caractérisent
l’état du jeu (niveau de vie du joueur, de ses ennemis, le temps écoulé, …), doivent être modifiées selon
les événements qui se sont produits. Une fois l’état du jeu mis à jour, il faut dessiner à l’écran l’état du jeu
afin que l’affichage soit en phase avec les valeurs des variables qui caractérisent le jeu.

▪ for event in pygame.event.get():


Comme nous venons de le dire, une étape importante de la boucle principale (ou boucle du jeu) est de
prendre en compte les événements qui se sont produits. Les événements sont représentés par des objets
du type EventType du module pygame.event. Dans pygame, ces événements sont récupérés grâce à la
fonction get() du module pygame.event qui renvoie une liste contenant tous les événements dans l’ordre
de leur apparition depuis le dernier appel de la méthode get() ou depuis le début du jeu lors du premier
appel de get(). La boucle for permet donc de traiter les uns après les autres les événements de la liste
renvoyée par la fonction get() en affectant ces objets à la variable event.

▪ if event.type == QUIT:
Les objets de type EventType possèdent une propriété (encore appelée membre ou attribut) nommée type
dont la valeur est une constante définie dans le module pygame.locals. Cette constante caractérise le type
de l’événement et ne doit pas être préfixée par le nom de module du fait du type d’importation utilisé pour
le module pygame.locals. Si l’utilisateur ferme la fenêtre, la propriété type de l’objet event prend la valeur

9
Spécialité NSI Projet n° 3 – Recherche les paires 14/12/2023

de la constante QUIT. Si tel est le cas, la condition de l’instruction conditionnelle vaut True et les deux
instructions des deux lignes suivantes sont exécutées.

▪ pygame.quit() et sys.exit():
La fonction pygame.quit() est un peu l’opposé de l’instruction pygame.init() : elle exécute le code
nécessaire à la désactivation de la librairie pygame. Vos programmes devraient systématiquement appeler
pygame.quit() avant d’appeler sys.exit() pour terminer un programme. Normalement, il ne devrait pas être
nécessaire d’appeler pygame.quit(), car à la fermeture du programme, Python devrait désactiver
automatiquement la librairie pygame. Cependant, avec IDLE, cela conduit à une erreur, certainement due
au fait qu’IDLE est écrit en Python et que Python n’est pas vraiment fermé à la fin du programme.

▪ pygame.display.update() :
La fonction update() du module pygame.display dessine à l’écran l’objet de type Surface renvoyé par
l’instruction pygame.display.set_mode(), soit l’objet référencé par la variable surface_affichage dans notre
programme.
Dans notre programme, comme nous n’avons rien dessiné sur l’objet surface_affichage, la fonction
update() affiche toujours le même écran noir.
Une fois cette instruction exécutée, le programme effectue à nouveau une itération de la boucle while et
ceci jusqu’à ce que l’utilisateur ferme la fenêtre et créé un événement dont la propriété type vaut QUIT.

II- La surface d’affichage

Les objets de type Surface sont des objets qui permettent de dessiner et d’afficher des images en deux
dimensions.
Les pixels d’un objet de type Surface peuvent être modifiés en appelant les fonctions de dessin de pygame que
l’on étudiera ultérieurement, puis affichés à l’écran. Les éléments d’une fenêtre tels que la bordures, la barre des
titres et la barre de boutons ne font pas partie des objets de type Surface.
L’objet particulier de type Surface renvoyé par l’instruction pygame.display.set_mode() est appelé Surface
d’affichage. Tout ce qui est dessiné sur l’objet Surface d’affichage est ensuite affiché sur la fenêtre lors de l’appel
de la fonction pygame.display.update() ou lors de l’appel de la fonction pygame.display.flip().

La fonction pygame.display.flip() permet d’actualiser toute la surface d’affichage, alors qu’avec


pygame.display.update(), on peut éventuellement préciser les zones de la surface d’affichage à redessiner en
passant en argument un objet pygame de type Rect associé à la zone à redessiner.

Sachant qu’il est bien plus rapide de dessiner sur un objet Surface (qui existe seulement dans la mémoire de
l’ordinateur) que de dessiner directement sur l’écran d’un ordinateur (la mémoire de l’ordinateur est plus
rapidement modifiable que ne peuvent être modifiés les pixels d’un écran), à chaque itération de la boucle
principale, on dessinera tout d’abord sur l’objet Surface d’affichage tout ce qui devra par la suite être affiché
dans la fenêtre du programme, avant d’afficher effectivement le contenu de l’objet Surface d’affichage à l’écran à
l’aide de l’instruction pygame.display.update() ou de l’instruction pygame.display.flip().

L’ordinateur peut afficher des images très rapidement et les programmes de jeu auront souvent un taux de
rafraîchissement de 30 Images Par Secondes (30 IPS) ou 30 Frames Per Second en anglais (30 FPS).

10
Spécialité NSI Projet n° 3 – Recherche les paires 14/12/2023

III- Les couleurs dans pygame : le système RGB

Dans Pygame, on représente les couleurs RGB par un tuple de trois Cyan (0, 255, 255)
éléments dont chaque élément correspond dans l’ordre à la Noir (0, 0, 0)
composante rouge, verte et bleue. Bleu (0, 0, 255)
Fuchsia (255, 0, 255)
Les valeurs de chaque composante varient de 0 à 255, la valeur 0 Gris (128, 128, 128)
correspondant à l’absence de la composante, alors que 255 Vert (0, 128, 0)
correspond à l’intensité maximum de la composante. Le nombre de Vert citron (0, 255, 0)
couleurs ainsi disponibles avec Pygame est de 2563 = 16777216. Marron (128, 0, 0)
Bleu marine (0, 0, 128)
Par exemple, on pourra créer un tuple (0, 0, 0) et l’enregistrer dans Olive (128, 128, 0)
une variable nommée NOIR, alors que le tuple (255, 255, 255) pourra Violet (128, 0, 128)
être affecté à une variable nommée BLANC.
Rouge (255, 0, 0)
Argenté (192, 192, 192)
Le tableau ci-contre donne les composantes de quelques couleurs
Cyan clair (0, 128, 128)
courantes :
Blanc (255, 255, 255)
Jaune (255, 255, 0)

IV-Dessiner dans une surface d’affichage

Pygame fournit un certain nombre de fonctions pour dessiner différentes formes sur des objets de type Surface.
Ces formes telles que des rectangles, des cercles, des ellipses ou des lignes sont appelées des primitives de
dessin. Les fonctions et les méthodes permettant de dessiner sur un objet du type Surface sont les suivantes :

▪ fill(color) : C’est une méthode des objets du type Surface qui remplit complètement l’objet Surface avec la
couleur donnée dans l’argument color.

▪ pygame.draw.polygon(surface, color, pointlist, width) : Cette fonction dessine un polygone dans l’objet
Surface passé en argument et dont la couleur est celle correspondant à l’argument color. Le paramètre
pointliste est une liste ou un tuple d’éléments, chaque élément étant un tuple de la forme (x, y) où x et y
sont les coordonnées d’un point. Le polygone est tracé en dessinant pour chaque point une ligne entre ce
point et le point suivant et entre ce point et le point précédent. Le dernier point étant naturellement relié
au premier point pour fermer le polygone. Le paramètre width est optionnel. S’il est omis, le polygone sera
rempli avec la couleur donnée par l’argument color. Si l’argument width est donné avec une valeur
strictement positive, seule le contour extérieure du polygone sera tracé avec une épaisseur en nombre de
pixels égale à l’argument width. Toutes les fonctions de dessin du module pygame.draw ont pour dernier
argument l’argument width, celui-ci se comportant toujours comme dans la fonction
pygame.draw.polygon().

▪ pygame.draw.line(surface, color, start_point, end_point, width) : Cette fonction dessine une ligne entre
les points définis par les tuples passés en argument à start_point et end_point.

▪ pygame.draw.lines(surface, color, closed, pointlist, width) : Cette fonction dessine une série de lignes,
d’un point au suivant, un peu comme pygame.draw.polygon() avec width > 0. La seule différence vient du
paramètre closed. Si celui-ci vaut False, le dernier point n’est pas relié au premier point de la liste de points
donnée par le paramètre pointlist. Si le paramètre closed vaut True, le dernier point est relié au premier
point.

11
Spécialité NSI Projet n° 3 – Recherche les paires 14/12/2023

▪ pygame.draw.circle(surface, color, center_point, radius, width) : Cette fonction dessine un cercle de


centre ayant pour coordonnées le tuple passé en argument à center_point, de rayon la valeur passée en
argument au paramètre radius et dont la couleur est donnée par le paramètre color.

▪ pygame.draw.ellipse(surface, color, bounding_rectangle, width) : Cette méthode dessine une ellipse


définie par le plus petit rectangle qui l’englobe. Ce rectangle est passé en argument par l’intermédiaire du
paramètre bounding_rectangle et peut être défini par un tuple de quatre éléments ou par un objet de
type Rect.

▪ pygame.draw.rect(surface, color, rectangle_tuple, width) : Cette fonction dessine un rectangle défini soit
par un tuple de quatre éléments, soit par un objet de type Rect.

➢ Copier et exécuter le code ci-dessous dans un fichier que vous nommerez primitive_dessin.py :

import pygame, sys


from pygame.locals import *
pygame.init()

# Création de la surface d’affichage


surface_affichage = pygame.display.set_mode((500, 400), 0, 32)
pygame.display.set_caption('Dessin')
# Définition des couleurs
NOIR = (0, 0, 0)
BLANC = (255, 255, 255)
ROUGE = (255, 0, 0)
VERT = (0, 255, 0)
BLEU = (0, 0, 255)

# Dessin sur l’objet surface


surface_affichage.fill(BLANC)
pygame.draw.polygon(surface_affichage, VERT, ((146, 0), (291, 106), (236, 277), (56, 277), (0, 106)))
pygame.draw.line(surface_affichage, BLEU, (60, 60), (120, 60), 4)
pygame.draw.line(surface_affichage, BLEU, (120, 60), (60, 120))
pygame.draw.line(surface_affichage, BLEU, (60, 120), (120, 120), 4)
pygame.draw.circle(surface_affichage, BLEU, (300, 50), 20, 0)
pygame.draw.ellipse(surface_affichage, ROUGE, (300, 250, 40, 80), 1)
pygame.draw.rect(surface_affichage, ROUGE, (200, 150, 100, 50))

# Entrée dans la boucle principale


while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
pygame.display.update()

12
Spécialité NSI Projet n° 3 – Recherche les paires 14/12/2023

V- Taux de rafraîchissement et l’objet du type Clock du module pygame.time

Le taux de rafraîchissement est le nombre d’images que le programme dessine par secondes, que l’on notera
IPS (ou FPS pour Frame Per Second). En début de programme, on définira donc généralement la constante
suivante :

IPS = 50 # 50 images par secondes

Afin de s’assurer que le programme ne s’exécute pas trop vite et que le temps de pause entre l’affichage de
chaque image est le même, on utilise une horloge en créant un objet de type Clock défini dans le module
pygame.time :

ipsHorloge = pygame.time.Clock()

A l’aide de cette horloge (ipsHorloge) et de la méthode tick() de la classe Clock, on peut commander à Pygame de
faire une pause, de telle sorte à avoir le taux de rafraîchissement désiré, quelle que soit la fréquence du
microprocesseur de la machine sur laquelle s’exécute le programme.

La méthode tick() prend en paramètre le taux de rafraîchissement souhaité (IPS ou FPS) et elle devrait être
appelée une seule fois à la fin de la boucle principale du jeu. Elle est généralement placée juste après l’une des
instructions de mise à jour de l’affichage pygame.display.update() ou pygame.display.flip() :

ipsHorloge.tick(IPS)

➢ Copier et exécuter le code ci-dessous qui déplace continuellement une balle de gauche à droite dans une
fenêtre. Vous nommerez ce fichier balle.py :

import pygame, sys


from pygame.locals import *

pygame.init()

IPS = 50 # Nombre d’images par secondes


LARGEUR = 200 # Largeur de la fenêtre en pixels
HAUTEUR = 150 # Hauteur de la fenêtre en pixels
JAUNE = (255, 255, 0) # Couleur de la balle
BLEU = (0, 0, 255) # Couleur de fond
RAYON = 20 # Rayon de la balle
PAS = 1 # Pas de déplacement en nombre de pixels

x, y = 20, 75 # Coordonnées initiales de la balle


sens = 1 # Sens de déplacement: 1 pour droite et -1 pour gauche

# Création de l’horloge
ipsHorloge = pygame.time.Clock()

# Création de la surface d’affichage


surface_affichage = pygame.display.set_mode((LARGEUR, HAUTEUR))

13
Spécialité NSI Projet n° 3 – Recherche les paires 14/12/2023

while True:
# On créé un fond bleu, ce qui permet aussi d’effacer le contenu précédent de la fenêtre pygame
surface_affichage.fill(BLEU)

# On gère les événements


for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()

x_new = x + sens * PAS # Calcul de la nouvelle abscisse de la balle

if (x_new < RAYON or x_new > (LARGEUR - 1 - RAYON)):


x_new = x # Si la balle sort de la fenêtre, on ne modifie pas les coordonnées de la balle
sens = -sens # La balle rebondit : on inverse son sens de déplacement
else:
x = x_new # On modifie l’abscisse de la balle si elle n’a pas atteint les bords

# On dessine la balle dans sa nouvelle position


pygame.draw.circle(surface_affichage, JAUNE, (x, y), RAYON, 0)

pygame.display.flip() # Mise à jour de l’affichage de la fenêtre


ipsHorloge.tick(IPS) # On bloque le programme pour avoir IPS images par secondes

VI-Utilisation des événements du clavier pour déplacer une forme


1- Complément concernant les événements de pygame

Les événements de pygame sont des objets du type EventType définis dans le module pygame.event. Nous avons
déjà dit que l’on pouvait récupérer ces événements dans une variable que nous avons toujours nommé event, à
l’aide d’une instruction du type « for event in pygame.event.get() » Ces objets event du type EventType ont tous
un attribut type dont les valeurs possibles sont données dans le tableau ci-dessous (première colonne). Selon la
valeur de l’attribut type, ces événements ont aussi d’autres attributs donnés dans la deuxième colonne :

Valeur de l’attribut type de l’événement Autres attribut(s) associé au type d’événement


QUIT none
ACTIVEEVENT gain, state
KEYDOWN unicode, key, mod
KEYUP key, mod
MOUSEMOTION pos, rel, buttons
MOUSEBUTTONUP pos, button
MOUSEBUTTONDOWN pos, button
JOYAXISMOTION joy, axis, value
JOYBALLMOTION joy, ball, rel
JOYHATMOTION joy, hat, value
JOYBUTTONUP joy, button
JOYBUTTONDOWN joy, button
VIDEORESIZE size, w, h
VIDEOEXPOSE none

14
Spécialité NSI Projet n° 3 – Recherche les paires 14/12/2023

Dans les exemples qui vont suivre, nous utiliserons souvent les attributs pos des événements de la souris
(événements MOUSEMOTION, MOUSEBUTTONUP et MOUSEBUTTONDOWN), car cet attribut contient les
coordonnées courantes de la souris, enregistrées dans un tuple. On exécutera donc souvent l’instruction ci-
dessous permettant de récupérer les coordonnées xs et ys de la souris au moment de l’événement :

xs, ys = event.pos

2- Utilisation du clavier

Pour déplacer une image avec le clavier, il faut utiliser les événements de type KEYDOWN (touche du clavier
enfoncée) ou KEYUP (touche du clavier relâchée). Ces événements possèdent un attribut key qui est un entier
identifiant la touche du clavier enfoncée ou relâchée. Les valeurs de cet attribut selon la touche du clavier
enfoncée sont données par des constantes définies dans le module pygame.key. Voici quelques constantes
associées à quelques touches du clavier :

Touche du clavier Attribut key


0 K_0
1 K_1
2 K_2
a K_a
b K_b
c K_c
Flèche haute K_UP
Flèche basse K_DOWN
Flèche gauche K_LEFT
Flèche droite K_RIGHT

➢ Dans l’exemple ci-dessous, on déplace une balle à l’aide des flèches du clavier. A chaque appui sur une de ces
touches, l’image est déplacée de 5 pixels si elle ne rencontre pas un bord de la fenêtre. Copier et exécuter ce
code que vous enregistrerez dans un fichier nommé balle_clavier.py :

import pygame, sys


from pygame.locals import *

pygame.init()

IPS = 50 # Nombre d’images par secondes


LARGEUR = 200 # Largeur de la fenêtre en pixels
HAUTEUR = 150 # Hauteur de la fenêtre en pixels
JAUNE = (255, 255, 0) # Couleur de la balle
BLEU = (0, 0, 255) # Couleur de fond de la fenêtre
RAYON = 20 # Rayon de la balle
x, y = 20, 75 # Coordonnées initiales de la balle
PAS = 5 # Pas de déplacement de la balle à chaque appui sur une flèche du clavier

ipsHorloge = pygame.time.Clock() # Création d’une horloge

15
Spécialité NSI Projet n° 3 – Recherche les paires 14/12/2023

surface_affichage = pygame.display.set_mode((LARGEUR, HAUTEUR))

while True:
surface_affichage.fill(BLEU) # On dessine un fond bleu pour la fenêtre pour en effacer le contenu

x_new = x # Nouvelle abscisse de la balle


y_new = y # Nouvelle ordonnée de la balle

# Gestion des événements


for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
# Gestion des événements du clavier
elif (event.type == KEYDOWN):
if (event.key == K_RIGHT):
x_new += PAS
elif (event.key == K_LEFT):
x_new -= PAS
elif (event.key == K_DOWN):
y_new += PAS
elif (event.key == K_UP):
y_new -= PAS

if (x_new < RAYON or x_new > (LARGEUR - 1 - RAYON)): # Si la balle touche les bords verticaux
x_new = x # L’abscisse reprend son ancienne valeur : la balle ne bouge pas
else:
x = x_new # On valide la nouvelle abscisse de la balle

if (y_new < RAYON or y_new > (HAUTEUR - 1 - RAYON)): # Si la balle touche les bords horizontaux
y_new = y # L’ordonnée reprend son ancienne valeur : la balle ne bouge pas
else:
y = y_new # On valide la nouvelle ordonnée de la balle

# On dessine la balle avec les nouvelles coordonnées


pygame.draw.circle(surface_affichage, JAUNE, (x, y), RAYON, 0)

# On met à jour l'affichage de la fenêtre


pygame.display.flip()

# On rafraîchit les images à la fréquence de IPS images par secondes


ipsHorloge.tick(IPS)

16
Spécialité NSI Projet n° 3 – Recherche les paires 14/12/2023

VII- Affichage d’une image dans pygame

Les fonctions de dessin que nous avons présentées précédemment sont utiles, mais de nombreux jeux utilisent
des images. Pygame est capable de charger des images aux formats PNG, JPG, GIF, BMP, PCX, TGA (non
compressé), TIF, LBM, PBM, PGM, PPM et XPM sur des objets de type Surface.

La fonction load() du module pygame.image prend en argument le nom d’un fichier image et retourne un objet
de type Surface associé à l’image. Cet objet Surface est un objet distinct de l’objet Surface d’affichage. L’exemple
ci-dessous créé une variable surface_chat qui référence l’objet Surface retourné par la fonction load() et associée
au fichier chat.png :

surface_chat = pygame.image.load(chat.png)

Si l’on souhaite que l’image soit dessinée sur l’objet Surface d’affichage, il faut transférer les blocs de données de
l’objet Surface associé à l’image sur l’objet Surface d’affichage à l’aide de la méthode blit() (de Bit Block
Transfer).

Par exemple, si on souhaite afficher l’image du chat sur l’objet surface_affichage aux coordonnées (xChat ;
yChat), on devra écrire :

surface_affichage.blit(surface_chat, (xChat , yChat))

Le premier argument de la fonction blit() est une référence de l’objet Surface associé à l’image du chat et le
deuxième argument est un tuple de deux éléments, ces éléments étant les coordonnées du coin supérieur
gauche de l’image dans la Surface d’affichage. Ce deuxième argument peut aussi être un objet de type
pygame.Rect et dans ce cas, le coin supérieur gauche du rectangle est pris comme référence pour positionner
l’objet Surface de l’image sur la Surface d’affichage.

➢ Copier et exécuter le code de l’exemple ci-dessous, qui déplace l’image d’un chat le long des bords de la
fenêtre. A chaque itération de la boucle principale, l’image est déplacée de 5 pixels. Vous enregistrerez le
fichier sous le nom bouger_chat.py :

import pygame, sys


from pygame.locals import *

pygame.init()

IPS = 30 # Nombre d’images par seconde


ipsHorloge = pygame.time.Clock()

surface_affichage = pygame.display.set_mode((494, 497))


pygame.display.set_caption('Animation d’un chat')

BLANC = (255, 255, 255)


surface_chat = pygame.image.load('chat.png') # On charge l’image du chat
xChat = 10
yChat = 10
direction = 'droite'

17
Spécialité NSI Projet n° 3 – Recherche les paires 14/12/2023

while True:
surface_affichage.fill(BLANC)

# On calcule les nouvelles coordonnées du coin supérieure gauche de l’image


if direction == 'droite':
xChat += 5
if xChat == 265:
direction = 'bas'
elif direction == 'bas':
yChat += 5
if yChat == 310:
direction = 'gauche'
elif direction == 'gauche':
xChat -= 5
if xChat == 10:
direction = 'haut'
elif direction == 'haut':
yChat -= 5
if yChat == 10:
direction = 'droite'

surface_affichage.blit(surface_chat, (xChat, yChat))

# Gestion des événements


for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()

pygame.display.update()
ipsHorloge.tick(IPS)

L’exécution de ce programme devrait vous permettre d’admirer ce magnifique chat …

18

Vous aimerez peut-être aussi