NSI Première

Initiation à Pygame⚓︎

1. Préparation de la scène⚓︎

1. Préparation de la scène⚓︎

import pygame
from pygame.locals import *

pygame.init() # (4)

fenetre = pygame.display.set_mode((640, 480)) # (1)
fenetre.fill((10, 186, 181)) # (2)

running = True
while running: 
    fenetre.fill((10, 186, 181)) # (2)
    pygame.display.flip() #(3) 

pygame.quit()
  1. On crée une fenêtre de taille (640, 480).
  2. On remplit la fenêtre avec la couleur (10, 186, 181).
  3. Permet de rafraîchir la totalité de la fenêtre. Pour l'instant inutile car rien ne bouge...
  4. Initialisation du module pygame.

Ce code devrait vous donner ceci :

image

Remarques

  • La ligne from pygame.locals 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 l'éditeur Python.
    Nous y remedierons bientôt.

Les éléments structurants d'un code pygame

  • pygame.init() 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.
  • pygame.display.flip() 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é perso.png.
Il est issu de openclassrooms.com interface-graphique-pygame-pour-python

image

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 = pygame.image.load('perso.png').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() :

fenetre.blit(perso, position_perso)

▸ récapitulatif du code

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
import pygame
from pygame.locals import *

pygame.init()

fenetre = pygame.display.set_mode((640, 480))

perso = pygame.image.load('perso.png').convert_alpha()
position_perso = perso.get_rect()

running = True
while running: 
    fenetre.fill((10, 186, 181))
    position_perso.topleft = (100, 200)
    fenetre.blit(perso, position_perso)
    pygame.display.flip()

pygame.quit()

Aperçu

image

3. Gestion des évènements⚓︎

Lorsqu'un programme pygame est lancé, la variable interne pygame.event.get() 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 :

1
2
3
for event in pygame.event.get():
    if event.type == pygame.QUIT:
        running = False

Exercice 1

Intégrer le code ci-dessus au code précédent afin de pouvoir fermer proprement la fenêtre.

Correction

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» :

1
2
3
4
for event in pygame.event.get():   
    if event.type == KEYDOWN:
        if event.key == 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 :

1
2
3
4
5
6
7
for event in pygame.event.get():
    if event.type == KEYDOWN:
        if event.key == K_RIGHT:
            print('flèche droite appuyée')

    if event.type == pygame.QUIT:
        running = False

Le nom de toutes les touches peut être retrouvé à l'adresse https://www.pygame.org/docs/ref/key.html.

Remarque : c'est grâce à la ligne initiale

from pygame.locals 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 :

pygame.key.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 pygame.event.get():    
    if event.type == MOUSEBUTTONDOWN and event.button == 1 :
        print('clic gauche détecté')
    if event.type == MOUSEBUTTONDOWN and event.button == 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é.

Correction

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 pygame.mouse.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

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 = pygame.time.Clock() crée une horloge dans le corps du programme.

Ensuite, dans la boucle, nous rajouterons

clock.tick(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 fenetre.blit(perso, position_perso), le personnage sera positionné à cette nouvelle position.

Exercice 4

Réaliser un déplacement aléatoire, comme l'animation ci-dessous.

image

Vous pourrez utiliser les instructions :

  • pygame.time.delay(1000) afin de ne bouger le personnage que toutes les 1000 millisecondes.
  • randint(a,b) du package random, qui renvoie un entier pseudo-aléatoire entre a et b.
Correction

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)
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. image

Correction

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

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

5. Organisation du projet⚓︎

Calendrier du projet

  • 28/11/2024 : démarrage du projet et constitution des groupes
  • Groupe 1NSINF2 séance du mercredi 4/12/2024 : travail sur le projet
  • remise du projet sur Capytale :

Dépôt de projet sur Capytale

Cliquez ici. Servez-vous de cette feuille de projet pour y déposer les différentes versions de votre travail si vous voulez. Je pourrai ainsi le consulter au fur et à mesure de votre progression.

Ce que je ne veux pas voir : DU CODE VENANT D'ESPACES ET DE FORUMS D'ECHANGE

Groupes de projet



Bibliographie