Initiation à Pygame
1. Préparation de la scène
import pygame
from [Link] import *
[Link]() #
fenetre = [Link].set_mode((640, 480)) #
[Link]((10, 186, 181)) #
running = True
while running:
[Link]((10, 186, 181)) #
[Link]() #
[Link]()
Ce code devrait vous donner ceci :
Remarques
La ligne from [Link] import * permettra d'utiliser des
variables locales déjà définies par pygame,
comme MOUSEBUTTONDOWN, par exemple.
Durant tout le code, notre scène de travail sera l'objet fenetre, dans
lequel nous viendrons coller de nouveaux éléments.
Pour l'instant, notre code nous enferme dans une boucle infinie : la
fenêtre ne se ferme pas, il faut arrêter Python depuis Thonny. Nous y
remedierons bientôt.
Les éléments structurants d'un code pygame
[Link]() effectue une initialisation globale de tous les
modules pygame importés. À mettre au début du code.
while running: comme très souvent dans les jeux, la structure
essentielle est une boucle infinie dont on ne sortira que par la
bascule d'un booléen. Ici on restera bloqué dans la boucle jusqu'au
moment où la variable running passera à False.
[Link]() effectue un rafraîchissement total de tous les
éléments graphiques de la fenêtre. À mettre à l'intérieur de la boucle
infinie, généralement à la fin de celle-ci.
2. Apparition d'un personnage
2.1. Téléchargement de l'image
Nous allons travailler avec le sprite ci-dessous, nommé [Link]. Il est
issu de [Link]
graphique-pygame-pour-python/1399813-premieres-fenetres
Téléchargez-le pour le mettre dans le même dossier que votre
code pygame.
Vous pouvez trouver sur internet un grand nombre de sprites libres de
droits, au format png (donc gérant la transparence), dans de multiples
positions (ce qui permet de simuler des mouvements fluides). Ici nous
travaillerons avec un sprite unique.
2.2. Importation de l'image dans la fenêtre
perso = [Link]('[Link]').convert_alpha()
La fonction convert_alpha() est appelée pour que soit correctement traité
le canal de transparence (canal alpha) de notre image.
2.3. Affichage de l'image
À ce stade, perso est un objet pygame de type Surface .
Afin de facilement pouvoir le déplacer, nous allons stocker la position de
cet objet dans une variable position_perso, grâce à
l'instruction perso.get_rect().
Notre image est devenue «un rectangle» que nous allons positionner où
nous voulons.
Par exemple, pour positionner le coin supérieur gauche du personnage aux
coordonnées (100, 200), nous écrirons :
position_perso = perso.get_rect()
position_perso.topleft = (100, 200)
Il y a d'autres instructions que topleft : vous pouvez les retrouver ici.
Pour afficher cette image, nous allons venir le superposer aux éléments
graphiques déjà dessinés (en l'occurence : rien) avec l'instruction blit() :
[Link](perso, position_perso)
▸ récapitulatif du code
import pygame
from [Link] import *
[Link]()
fenetre = [Link].set_mode((640, 480))
perso =
[Link]('[Link]').convert_alpha(
)
position_perso = perso.get_rect()
running = True
while running:
[Link]((10, 186, 181))
position_perso.topleft = (100, 200)
[Link](perso, position_perso)
[Link]()
[Link]()
3. Gestion des évènements
Lorsqu'un programme pygame est lancé, la variable
interne [Link]() reçoit en continu les évènements des
périphériques gérés par le système d'exploitation.
Nous allons nous intéresser aux évènements de type KEYDOWN (touche
de clavier appuyée) ou de type MOUSEBUTTONDOWN (boutons de souris
appuyé).
Pour commencer, la gestion des évènements nous permettra de pouvoir
enfin fermer proprement la fenêtre Pygame, grâce au code suivant :
for event in
[Link]():
if [Link] ==
[Link]:
running = False
Exercice 1
Intégrer le code ci-dessus au code précédent afin de pouvoir fermer
proprement la fenêtre.
Correction
import pygame
from [Link] import *
[Link]()
fenetre = [Link].set_mode((640, 480))
perso =
[Link]('[Link]').convert_alpha(
)
position_perso = perso.get_rect()
running = True
while running:
[Link]((10, 186, 181))
position_perso.topleft = (100, 200)
[Link](perso, position_perso)
[Link]()
for event in [Link]():
if [Link] == [Link]:
running = False
[Link]()
3.1. Évènements clavier
3.1.1. Exemple de code
La structure de code pour détecter l'appui sur une touche de clavier est,
dans le cas de la détection de la touche «Flèche droite» :
for event in
[Link]():
if [Link] ==
KEYDOWN:
if [Link] ==
K_RIGHT:
print('flèche droite
appuyée')
La touche (en anglais key) «Flèche Droite» est
appelée K_RIGHT par pygame.
il ne doit y avoir qu'une seule boucle de capture d'évènements, donc
la routine de fermeture de la fenêtre doit être dans la même boucle :
for event in
[Link]():
if [Link] ==
KEYDOWN:
if [Link] ==
K_RIGHT:
print('flèche droite
appuyée')
if [Link] ==
[Link]:
running = False
Le nom de toutes les touches peut être retrouvé à
l'adresse [Link]
Remarque : c'est grâce à la ligne initiale
from [Link] import *
que la variable K_RIGHT (et toutes les autres) est reconnue.
3.1.2. Problème de la rémanence
Quand une touche de clavier est appuyée, elle le reste un certain temps.
Parfois volontairement (sur un intervalle long) quand l'utilisateur décide de
la laisser appuyée, mais aussi involontairement (sur un intervalle très
court), lors d'un appui «classique».
Il existe donc toujours un intervalle de temps pendant lequel la touche
reste appuyée. Que doit faire notre programme pendant ce temps ? Deux
options sont possibles :
option 1 : considérer que la touche appuyée correspond à un seul
et unique évènement, quelle que soit la durée de l'appui sur la
touche.
option 2 : considérer qu'au bout d'un certain délai, la touche encore
appuyée doit déclencher un nouvel évènement.
Par défaut,pygame est réglé sur l'option 1. Néanmoins, il est classique
pour les jeux vidéos de vouloir que «laisser la touche appuyée» continue à
faire avancer le personnage. Nous allons donc faire en sorte que toutes les
50 millisecondes, un nouvel appui soit détecté si la touche est restée
enfoncée. Cela se fera par l'expression :
[Link].set_repeat(50)
3.2 Évènements souris
3.2.1. Exemple de code
La structure de code pour détecter l'appui sur un bouton de la souris est :
for event in [Link]():
if [Link] == MOUSEBUTTONDOWN and [Link] == 1 :
print('clic gauche détecté')
if [Link] == MOUSEBUTTONDOWN and [Link] == 3 :
print('clic droit détecté')
Le clic-gauche est associé à la valeur 1, le clic-droit à la valeur 3 (le clic-
molette éventuel à la valeur 2).
Exercice 2
Reprendre le code initial et y intégrer la capture d'évènements souris afin
que s'affiche en console le bouton de souris appuyé.
3.2.2. Récupération des coordonnées de la souris
Le tuple (abscisse, ordonnée) des coordonnées de la souris sera récupéré
avec l'instruction [Link].get_pos().
Cette fonction n'a pas besoin d'être dans notre boucle d'écoute des
évènements : elle peut se situer n'importe où dans le code.
Exercice 3
Faire afficher en console les coordonnées de la souris.
Correction
import pygame
from [Link] import *
[Link]()
fenetre = [Link].set_mode((640, 480))
perso =
[Link]('[Link]').convert_alpha()
position_perso = perso.get_rect()
[Link].set_repeat(50)
running = True
while running:
[Link]((10, 186, 181))
position_perso.topleft = (100, 200)
[Link](perso, position_perso)
x, y = [Link].get_pos()
print(x, y)
[Link]()
for event in [Link]():
if [Link] == [Link]:
running = False
if [Link] == MOUSEBUTTONDOWN and
[Link] == 1 :
print('clic gauche détecté')
if [Link] == MOUSEBUTTONDOWN and
[Link] == 3 :
print('clic droit détecté')
[Link]()
3.3 Activation d'un framerate
Pour l'instant, notre boucle infinie tourne «à fond» et le rafraîchissement
de l'affichage se fait aussi rapidement que le peut le processeur. Afin de
garder le contrôle sur cet fréquence de rafraîchissement (le nombre
de frames par seconde, le fameux FPS) nous allons utiliser une horloge.
clock = [Link]() crée une horloge dans le corps du
programme.
Ensuite, dans la boucle, nous rajouterons
[Link](30)
pour régler (par exemple) le FPS à 30.
4. Déplacement du personnage
Le déplacement d'un personnage se fera toujours par modification de ses
coordonnées (et visuellement, par effacement de la dernière position). Ce
déplacement pourra être :
absolu : on donne de nouvelles coordonnées au personnage.
relatif : on indique de combien le personnage doit se décaler par
rapport à sa position initiale.
4.1. Déplacement absolu
Rappel : pour afficher le personnage à la position (300,200), on écrit
simplement:
position_perso.topleft = (300,200)
Au prochain [Link](perso, position_perso), le personnage sera
positionné à cette nouvelle position.
Correction
import pygame
from [Link] import *
from random import randint
[Link]()
clock = [Link]()
fenetre = [Link].set_mode((640, 480))
perso =
[Link]('[Link]').convert_alpha(
)
position_perso = perso.get_rect()
running = True
while running :
[Link](30)
[Link]((10, 186, 181))
position_perso = (randint(0, 540), randint(0,
380))
[Link](perso, position_perso)
[Link]()
[Link](1000)
for event in [Link]():
if [Link] == [Link]:
running = False
[Link]()
4.2. Déplacement relatif
Pour déplacer le personnage de 15 pixels vers la droite et de 10 pixels vers
le haut par rapport à sa position précédente, on écrira :
position_perso = position_perso.move(15,-10)
où position_perso est l'objet de type rect contenant les coordonnées.
Exercice 5
Réaliser un contrôle au clavier du personnage, comme dans l'animation ci-
dessous.
Correction
import pygame
from [Link] import *
[Link]()
[Link].set_repeat(50)
clock = [Link]()
fenetre = [Link].set_mode((640, 480))
perso =
[Link]('[Link]').convert_alpha()
position_perso = perso.get_rect()
pas = 15
running = True
while running:
[Link](30)
[Link]((10, 186, 181))
[Link](perso, position_perso)
for event in [Link]() :
if [Link] == KEYDOWN:
if [Link] == K_DOWN :
position_perso = position_perso.move(0, pas)
if [Link] == K_UP :
position_perso = position_perso.move(0, -pas)
if [Link] == K_RIGHT :
position_perso = position_perso.move(pas, 0)
if [Link] == K_LEFT :
position_perso = position_perso.move(-pas, 0)
# routine pour pouvoir fermer «proprement» la
fenêtre Pygame
if [Link] == [Link]:
running = False
[Link]()
[Link]()
Exercice 6
Rajouter des instructions afin que le personnage ne puisse pas sortir de la
fenêtre de jeu.
On utilisera les variables suivantes :
position_perso.top : ordonnée du haut du personnage
position_perso.bottom : ordonnée du bas du personnage
position_perso.left : abscisse de la gauche du personnage
position_perso.right : abscisse de la droite du personnage
Correction
import pygame
from [Link] import *
[Link]()
[Link].set_repeat(50)
clock = [Link]()
fenetre = [Link].set_mode((640, 480))
perso =
[Link]('[Link]').convert_alpha(
)
position_perso = perso.get_rect()
pas = 15
running = True
while running:
[Link](30)
[Link]((10, 186, 181))
[Link](perso, position_perso)
if position_perso.top < 0:
position_perso.top = 0
if position_perso.bottom > 480:
position_perso.bottom = 480
if position_perso.left < 0:
position_perso.left = 0
if position_perso.right > 640:
position_perso.right = 640
for event in [Link]() :
if [Link] == KEYDOWN:
if [Link] == K_DOWN :
position_perso =
position_perso.move(0, pas)
if [Link] == K_UP :
position_perso =
position_perso.move(0, -pas)
if [Link] == K_RIGHT :
position_perso =
position_perso.move(pas, 0)
if [Link] == K_LEFT :
position_perso =
position_perso.move(-pas, 0)
if [Link] == [Link]:
running = False
[Link]()
[Link]()
Exercice 7
Reprendre l'exercice précédent mais faire en sorte que le personnage
réapparaisse à l'opposé de là où il est sorti.
Correction
import pygame
from [Link] import *
[Link]()
[Link].set_repeat(50)
clock = [Link]()
fenetre = [Link].set_mode((640, 480))
perso =
[Link]('[Link]').convert_alpha(
)
position_perso = perso.get_rect()
pas = 15
running = True
while running:
[Link](30)
[Link]((10, 186, 181))
[Link](perso, position_perso)
if position_perso.top < 0:
position_perso.bottom = 480
if position_perso.bottom > 480:
position_perso.top = 0
if position_perso.left < 0:
position_perso.right = 640
if position_perso.right > 640:
position_perso.left = 0
for event in [Link]() :
if [Link] == KEYDOWN:
if [Link] == K_DOWN :
position_perso =
position_perso.move(0, pas)
if [Link] == K_UP :
position_perso =
position_perso.move(0, -pas)
if [Link] == K_RIGHT :
position_perso =
position_perso.move(pas, 0)
if [Link] == K_LEFT :
position_perso =
position_perso.move(-pas, 0)
if [Link] == [Link]:
running = False
[Link]()
[Link]()
5. Collisions avec d'autres éléments
5.1 Création d'un objet Rect
La variable position_perso de notre personnage est de type Rect.
Nous pouvons en créer une autre avec la fonction [Link], qui prend
4 arguments:
l'abscisse du point en haut à gauche
l'ordonnée du point en haut à gauche
la largeur du rectangle (sur l'axe des abscisses)
la hauteur du rectangle (sur l'axe des ordonnées)
Par exemple, l'instruction
barre = [Link](250, 50, 10, 200)
créera une variable barre de type Rect, qui sera un rectangle dont les
coordonnées du point en haut à gauche sont (250,50), de largeur 10 et de
hauteur 200.
Attention, créer l'objet ne l'affiche pas !
Il faut pour cela donner l'instruction
[Link](fenetre, (74,55,242), barre)
où (74,55,242) est la couleur de remplissage du rectangle.
Exercice 8
Écrire les instructions précédentes pour faire apparaître la barre :
5.2 Collision avec un seul élément
Pygame possède une fonction colliderect qui renvoie un booléen attestant
(ou pas) de la collision entre deux objets de type Rect.
Pour tester la collision entre deux objets R1 et R2, on écrira
[Link](R2)
Cette instruction renvoie True si les deux objets se touchent, False sinon.
Exercice 9
Détecter la collision et faire reculer le personnage en cas de collision (par
exemple, mais vous pouvez faire autre chose !).
5.3 Collision avec plusieurs éléments⚓︎
Il est aussi possible d'utiliser la fonction collidelist qui prend en
paramètre une liste d'objets de type Rect.
Attention, cette fonction ne renvoie pas un booléen mais un nombre, qui
correspond à l'indice dans la liste de l'élément touché. Si aucun élément
n'est touché, cette fonction renvoie -1.
Par exemple, si nous avons un objet A et trois objets B, C et D réunis dans
une liste lst, alors l'expression
[Link](lst)
renverra :
0 si A touche B
1 si A touche C
2 si A touche D
-1 si A ne touche rien.
Exercice 10
Rajouter une barre (faire un début de labyrinthe) et faire en sorte que la
fenêtre se ferme dès qu'on touche une barre.
6. Contrôle avec la micro:bit
Pour pouvoir contrôler notre personnage avec (par exemple) les boutons
de la carte micro:bit, il va falloir :
mettre dans la carte un programme minimal qui va se contenter
d'envoyer des données.
mettre dans notre programme Pygame une instruction capable de
recevoir les données envoyées par la carte.
6.1 Programme à téléverser dans la micro:bit
Lien vers le simulateur
from microbit import *
while True:
incX =
accelerometer.get_x()
incY =
accelerometer.get_y()
message = "{},
{}".format(incX,incY)
print(message)
sleep(50)
Ce programme va envoyer, 20 fois par seconde, la valeur de l'inclinaison
en X et la valeur de l'inclinaison en Y.
6.2 Récupération des données dans Pygame
Il faut connaître le port utilisé par le système d'exploitation pour
communiquer avec la micro:bit. Sous Linux, ce port est de la
forme ttyACM0, sous Windows il sera de la forme COM2.
connaitre le port sous Windows
Ouvrir un terminal via cmd et taper la commande mode.
Une fois le programme d'envoi téléversé dans la micro:bit et le port connu,
testez le programme suivant :
import serial
port = "COM2" # à adapter en allant voir le port utilisé
par la microbit
s = [Link](port)
[Link] = 115200
while True:
[Link]()
data = [Link]()
data = [Link]('utf-8')
data = [Link](',')
incX = int(data[0])
incY = int(data[1])
print(incX, incY)
En inclinant la carte, vous devriez voir bouger les valeurs dans la console
de Thonny. Observer quelles sont les valeurs minimales et maximales.
Exercice 11
À l'aide de l'exemple précédent, modifiez le code de l'exercice 5 afin de
pouvoir bouger le personnage à l'aide de la micro:bit.