TD: Programmation graphique avec Pygame

Introduction

Pygame est un module (ce que dans d'autre langages on appelle aussi une bibliothèque), c'est à dire un ensemble de fonctions Python, qui permet de créer des jeux. Le module gère les graphiques (affichage de points, d'images, etc, comme le module PIL), mais aussi les entrées/sorties avec la gestion du clavier, de la souris, et du son. Pygame gère aussi la fenêtre dans laquelle les graphiques sont affichés. Une technique utilisée par le module est la gestion d'événements: le programme peut attendre que l'utilisateur fasse quelque chose puis y réagir. C'est un peu comme l'utilisation de la fonction "input", mais avec plusieurs types d'événements possibles (touche au clavier, clic de souris, fenêtre fermée etc).

Installation de pygame et gestion de la fenêtre


  import pygame
pygame.init()
Si pygame n'est pas encore installé, Python affiche une erreur "No module named 'pygame'". Pour l'installer dans Thonny, il faut aller dans "Outils", puis "Gérer les paquets", puis sélectionner "pygame" dans la liste à gauche, puis cliquer sur "installer". (Instructions détaillées sur ce lien). (Remarque: Si vous n'utilisez pas thonny, vous pouvez taper "pip install pygame" dans "l'invite de commande"; attention ce n'est pas la même chose que la console de Python.)

Mode d'affichage


screen = pygame.display.set_mode((720, 480))

pygame.time.wait(10000)
pygame.quit()

Ajouter les lignes ci-dessus à votre programme puis l'exécuter. Une fenêtre s'affiche pendant 10000 millisecondes, c'est à dire 10 secondes (attention, elle peut apparaître derrière la fenêtre de spyder).
Que se passe-t-il quand on essaye de fermer cette fenêtre?

Mise à jour de la fenêtre


  blanc= (255, 255, 255)
screen.fill(blanc)
pygame.display.update()

Ajouter les lignes ci-dessus à votre programme, juste avant la ligne contenant "wait". Modifier certains des paramètres pour comprendre leurs rôles. Définir des nouvelles variables "noir", "rouge", "vert", et "bleu". Essayer d'enlever la ligne contenant "update" et de relancer le programme. Que se passe-t-il?

A retenir: "x.fill(couleur)" remplit l'objet x avec la couleur donnée. Ici l'objet est tout l' "écran" pygame, c'est à dire la fenêtre.

A retenir: L'instruction display.update() est indispensable: tant qu'elle n'est pas exécutée, pygame va seulement "préparer" la prochaine image, sans l'afficher (ceci évite d'afficher des images à moitié finies). C'est update() qui mets à jour, ou "rafraîchit" l'écran.

ATTENTION: L'ordre des instruction est crucial (pour les questions suivantes aussi). Si update() est après quit(), le programme va attendre d'avoir fermé la fenêtre avant d'afficher, ce qui bien sûr ne peut pas marcher.

Rectangles


Avec pygame, pour afficher des images ou autre à l'écran, il faut utiliser un "rectangle" pygame.Rect.
  rect = pygame.Rect((100, 100), (32, 32))
image = pygame.Surface((32, 32))
image.fill(noir)
screen.blit(image, rect)

Ajouter les lignes ci-dessus juste avant la ligne contenant "update". Remarque: pour fonctionner, la variable "noir" doit avoir été définie comme demandé dans la question précédente.

Explications: la première ligne crée un objet de type pygame.Rect, de dimensions 32x32. La suivante crée une image de dimensions 32x32; la suivante remplit ("fill") cette image avec la couleur noir. Enfin la dernière affiche l'image à l'écran, à la position donnée par le rectangle.

Questions: Modifier les paramètres de la première ligne pour comprendre leurs rôles. Quel est le type de l'expression "(100, 100)"?

Mouvement


La ligne suivante modifie la position du rectangle rect (remarque: le "_ip" signifie "in place"; il est nécessaire).
  rect.move_ip(10, 0)
Ajouter cette ligne juste avant la ligne avec "blit". Dans quelle direction le rectangle a-t-il bougé? Modifier votre programme pour que le rectangle avance 10 fois de suite (avec une boucle), en attendant une seconde entre chaque étape.

Attention, ce n'est pas si facile: il faut bien penser à répéter certaines des lignes des questions précédentes (rectangles et mise à jour de la fenêtre) pour que tout se passe correctement. Rappelez-vous que python fait exactement ce que vous lui dites, et rien de plus; si vous lui demandez simplement de déplacer le rectangle, mais pas de l'afficher, ou que vous oubliez de mettre à jour ("update") l'écran, il ne le fera pas pour vous.
Si le programme ne marche pas, il faut bien vérifier l'ordre des instruction. Est-ce que votre programme répète dans la boucle l'instruction "quit()"? Est-ce qu'il répète bien "update()"?

Gestion des événements


  import pygame
pygame.init()

screen = pygame.display.set_mode((720, 480))
noir =  (0, 0, 0)
blanc = (255, 255, 255)

rect = pygame.Rect((100, 100), (32, 32))
image = pygame.Surface((32, 32))
image.fill(noir)

while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
        elif event.type == pygame.KEYDOWN:
            if event.key == pygame.K_RIGHT:
                rect.move_ip(10, 0)

    screen.fill(blanc)
    screen.blit(image, rect)
    pygame.display.update()

Voici cette fois (sur la page suivante) un programme complet. Le tester (en utilisant les touches avec les flèches directionnelles, situées à droite de votre clavier). Attention, si vous avez copié-collé le programme, il faut bien vérifier les espaces.

Explications: La fonction pygame.event.get retourne une liste d'"événements". Ce sont des objets de pygame que représentent chacun un clic, une touche ou autre. Il peut y en avoir plusieurs car la fonction donne tous les événements depuis la dernière fois qu'on les lui a demandés. Dans la boucle for, le programme regarde ensuite de quel type d'événement il s'agit. Le premier cas permet (enfin!) de détecter que l'utilisateur a essayé de fermer la fenêtre. Le deuxième cas (pygame.KEYDOWN) indique qu'une touche a étée pressée. Il faut ensuite regarder de quelle touche il s'agit, avec event.key. Attention: KEYDOWN ne représente pas la touche du bas, mais le fait que l'utilisateur appuie sur la touche; KEYUP signifie que l'utilisateur a relâché la touche (qu'elle est "remontée").

Questions: Modifier le programme pour faire bouger le rectangle dans les 3 autres directions. Pour trouver la syntaxe, vous pouvez deviner, ou chercher "pygame keys" sur internet.