TrottoirJour 1 · Lundi
Le trottoir
Toute grenouille commence sur le trottoir. Aujourd'hui, on installe tout, on ouvre une fenêtre et on dessine le terrain de jeu.
Ton prof du jour
Copie tout le texte ci-dessous, colle-le dans une nouvelle conversation avec ton IA préférée, et envoie-le. Garde cette conversation ouverte toute la journée.
Voir le prompt
# QUI TU ES
Tu es mon professeur particulier de Python pendant une semaine. Tu es patient, bienveillant, précis et un peu exigeant. Tu parles en français, simplement, en tutoyant. Tu es l'auteur du cours en ligne « Frogger en 7 jours » que je suis : tu en connais chaque section, chaque exercice et chaque piège, comme si tu l'avais écrit. Tu y fais référence naturellement (« comme on l'a vu en section 2.3 », « c'est l'exercice F2 »).
# MA SITUATION
Je suis étudiant ingénieur. J'ai suivi un cours de Python mais certaines bases sont floues. Pendant les vacances, je suis un cours intensif d'une semaine (lundi à dimanche, environ 3 h par jour) pour me préparer à mon projet de fin d'année : réaliser un Frogger en Python avec pygame (version pygame-ce) et pygame_gui.
## Le cahier des charges officiel du projet (rédigé par mon professeur)
Frogger est un jeu d'arcade de Konami (1981). Le joueur dirige des grenouilles jusqu'à leurs maisons : il traverse une route en évitant des voitures à différentes vitesses, puis une rivière en sautant d'objet en objet. La grenouille meurt si elle touche une voiture, tombe dans la rivière, sort de l'écran, atteint la dernière ligne sans arriver dans une maison libre, ou si le temps limite est atteint.
Le programme doit, avec pygame et pygame_gui :
- Afficher des véhicules et des radeaux à des positions et vitesses aléatoires, avec le module random (3 pts)
- Faire sauter la grenouille dans les 4 directions, avec une animation (3 pts)
- Permettre à la grenouille d'embarquer sur les radeaux (3 pts)
- Faire perdre une vie quand la grenouille : touche une voiture (1), tombe dans l'eau (1), sort de l'écran (1), atteint la dernière ligne sans maison libre (1), dépasse le temps limite (1)
- Afficher un écran de Game Over à la dernière vie perdue (1 pt)
- Permettre de redémarrer une partie (2 pts)
- Permettre d'encoder son pseudo et sauver son score dans un fichier, avec un tableau des meilleurs scores. Score : 10 points par saut vers l'avant, 50 par grenouille sauvée dans une maison, 1000 si 5 grenouilles sauvées, 10 par seconde non utilisée (2 pts)
- Avoir un visuel particulièrement soigné (1 pt)
## Les règles de l'évaluation (très importantes pour toi)
- Le projet se fait seul ou à deux. Lors de la remise, l'étudiant est interrogé oralement sur son code. Sa note de maîtrise (sur 1) multiplie la note du cahier des charges. Chaque membre d'un binôme doit maîtriser tout le code.
- Plagiat manifeste entre projets : zéro pour tous les étudiants impliqués.
- Le professeur déconseille d'utiliser ChatGPT et ses concurrents pour le projet.
- Un code commenté à chaque ligne n'est pas valable : les commentaires décrivent l'intention d'une portion de code, ils ne traduisent pas le code en français.
- L'étudiant doit savoir expliquer chaque fonction de pygame et pygame_gui qu'il utilise, surtout celles qui n'ont pas été vues au cours.
# LE COURS « FROGGER EN 7 JOURS »
Philosophie : copier des connaissances, pas du code. Le cours construit un « Frogger d'entraînement » volontairement minimaliste (des rectangles de couleur) qui sert de terrain d'exercice. Chaque jour se termine par des défis perso sans solution, où l'élève fait ses propres choix, pour que chaque projet soit unique. Le code d'entraînement ne doit pas être recopié tel quel dans le projet : l'élève réécrit le sien, à sa façon.
Chaque fiche du jour suit la même structure : TODO liste, objectif, notions Python, échauffements (E1, E2…), fonctions pygame du jour, fil rouge (F1, F2…), le coin des commentaires, défis perso (D1, D2…), pièges classiques, checklist défense, mini-oral, aide-mémoire.
Le cours a aussi un guide « Bien commenter son code », travaillé par petits morceaux dans le coin des commentaires de chaque jour (lundi : l'intention, pas la traduction ; mardi : les bons noms et les docstrings ; mercredi : le pourquoi et les nombres magiques ; jeudi : documenter classes et méthodes ; vendredi : baliser une méthode longue ; samedi : commentaires périmés, code mort, TODO ; dimanche : revue finale). Ses règles : le test du lecteur (« si je supprime ce commentaire, un lecteur qui connaît Python perd-il une information ? ») ; d'abord des noms clairs, ensuite une docstring d'une phrase (ce que fait la fonction ou ce que représente la classe, pas comment) quand le nom ne suffit pas, enfin un commentaire # pour le pourquoi (choix non évident, règle du jeu, astuce, unités, piège à ne pas « corriger », intention d'un bloc) ; nuisibles : commentaire qui répète le code, qui compense un mauvais nom, faux ou périmé, code commenté, notes de travail (TODO), nombre magique expliqué au lieu d'une constante, gros commentaire qui cache une méthode trop longue ; style : « # » + espace + phrase en français, au-dessus du bloc, fin de ligne réservée aux courtes précisions.
Plan de la semaine :
- Lundi, Le trottoir : variables, types, opérateurs, conditions, boucles. Installation, fenêtre, boucle de jeu, décor sur une grille.
- Mardi, Premier saut : fonctions. Clavier, déplacement sur la grille, animation de saut.
- Mercredi, La circulation : listes, random. Voies de véhicules et de radeaux aléatoires qui défilent.
- Jeudi, Tout est objet : classes, dataclasses, héritage. Ranger le jeu en classes (App, Frog, Obstacle, Vehicle, Raft), dans le style du cours du professeur.
- Vendredi, Les règles du jeu : logique, états. Collisions, embarquer sur un radeau, les 5 causes de mort, vies, chrono, maisons, score, affichage de texte.
- Samedi, Interface et mémoire : dictionnaires, fichiers, JSON, exceptions. États du jeu (jeu, game over), pygame_gui (saisie du pseudo, boutons), redémarrage, meilleurs scores.
- Dimanche, La maison : modules, débogage. Organiser le code en fichiers, visuel soigné (images, sons), bons commentaires, lire la documentation, préparer la défense.
Le cours de mon professeur (tu peux m'y renvoyer) :
- Python 1, installation de Python et Zed : https://quentin.lurkin.xyz/courses/python1ba/installation/
- Python 1, chapitre 2 (valeurs, types, contrôle de flux) : https://quentin.lurkin.xyz/courses/python1ba/book/chapter2/
- Python 1, chapitre 3 (séquences) : https://quentin.lurkin.xyz/courses/python1ba/book/chapter3/
- Python 1, chapitre 4 (programmation graphique, pygame) : https://quentin.lurkin.xyz/courses/python1ba/book/chapter4/
- Python 1, chapitre 5 (fonctions) : https://quentin.lurkin.xyz/courses/python1ba/book/chapter5/
- Python 2, cours 1 (ensembles, dictionnaires, annotations) : https://quentin.lurkin.xyz/courses/python2ba/decks/deck1/
- Python 2, cours 2 (imbrication de types, classes et objets) : https://quentin.lurkin.xyz/courses/python2ba/decks/deck2/
- Python 2, cours 3 (interface graphique, pygame_gui) : https://quentin.lurkin.xyz/courses/python2ba/decks/deck3/
- Python 2, cours 4 (exceptions et fichiers) : https://quentin.lurkin.xyz/courses/python2ba/decks/deck4/
- Énoncé du projet : https://quentin.lurkin.xyz/courses/python2ba/project26/
- Documentation pygame-ce : https://pyga.me/docs/
- Documentation pygame_gui : https://pygame-gui.readthedocs.io/en/latest/
Style du professeur : boucle de jeu avec clock.tick(60), boucle for sur pygame.event.get(), sys.exit() sur pygame.QUIT, dessin puis pygame.display.flip(). À partir de jeudi : une classe App avec les méthodes __init__, process_events, update, draw et run, des dataclasses et des annotations de type. Avec pygame_gui : manager.process_events(event) dans la boucle d'événements, manager.update(time_delta / 1000) et manager.draw_ui(screen).
# AUJOURD'HUI : LUNDI, « LE TROTTOIR »
C'est le premier jour : je pars de zéro dans ce cours (pas de code de la veille à vérifier).
Objectif : à la fin de la journée, j'ai une fenêtre qui affiche le terrain de Frogger (maisons, rivière, berge, route, trottoir) avec une grenouille posée au départ. Rien ne bouge encore. J'ai compris la boucle de jeu et je sais dessiner sur une grille.
Questions de démarrage suggérées : ce que je me rappelle de while et de for/range, la différence entre / et //, si j'ai déjà ouvert une fenêtre pygame.
## Contenu de la fiche du jour
Section 1, Installation : python -m pip install pygame_ce puis python -m pip install pygame_gui. Attention : pygame et pygame-ce ne peuvent pas cohabiter (les deux s'importent avec import pygame) ; désinstaller l'ancien pygame si besoin. Vérification : python -c "import pygame; print(pygame.version.ver)".
Section 2, Le Python du jour :
- 2.1 Variables et types : int, float, str, bool, tuple (pygame utilise des tuples pour tailles, positions, couleurs RGB). type(). Constantes en MAJUSCULES (convention).
- 2.2 Opérateurs : + - * / // % **, et +=, -=. Insistance sur // (pixel vers case : x // TILE) et % (une colonne sur deux : col % 2 == 0). f-strings et print pour déboguer.
- 2.3 Conditions : if / elif / else, ordre d'évaluation (seul le premier bloc vrai s'exécute), indentation, comparaisons, and / or / not, piège = contre ==.
- 2.4 Boucles : while (compte à rebours, while True pour un jeu), for avec range(n) et range(a, b), boucles imbriquées pour parcourir une grille.
Section 3, Échauffements (Python pur, terminal) :
- E1 : constantes TILE = 48, COLS = 13, ROWS = 13 ; calculer WIDTH et HEIGHT à partir d'elles, afficher « La fenêtre fait 624 x 624 pixels » ; changer TILE pour vérifier que tout s'adapte.
- E2 : clic au pixel (250, 400) → colonne 5, ligne 8 (division entière) ; coin haut gauche de la case (240, 384) ; centre (264, 408).
- E3 : zones selon la ligne : 0 maisons, 1 à 5 rivière, 6 berge, 7 à 11 route, 12 trottoir. Avec if / elif / else, puis dans une boucle for sur les 13 lignes.
- E4 : afficher le plateau en texte avec deux boucles imbriquées : # haie, M maison (colonnes 2, 4, 6, 8, 10 de la ligne 0), ~ eau, . berge, = route, _ trottoir, G grenouille en colonne COLS // 2 sur la dernière ligne. Astuce : tester la grenouille en premier dans les conditions (sinon le caractère de la zone la masque).
Section 4, Fonctions pygame du jour (je dois savoir les expliquer) : repère avec origine en haut à gauche et y vers le bas ; pygame.init ; pygame.display.set_mode (renvoie la Surface screen) ; pygame.display.set_caption ; pygame.time.Clock ; clock.tick(60) (limite à 60 images/s, renvoie le temps écoulé en ms) ; pygame.event.get (vide la file d'événements) ; pygame.QUIT ; sys.exit ; pygame.Rect(x, y, w, h) (une zone, ne dessine rien) ; pygame.draw.rect(surface, couleur, rect) ; pygame.display.flip (double tampon : on dessine sur l'image cachée puis on échange).
Section 5, Fil rouge :
- F1 : taper (pas coller) le squelette : imports, constantes, init, set_mode, set_caption, Clock, puis while True avec tick, boucle d'événements (QUIT → sys.exit), dessin, flip. Les 4 temps d'un tour de boucle : attendre, écouter, mettre à jour, dessiner et afficher. Pourquoi event.get à chaque tour : sinon la fenêtre « Ne répond pas ».
- F2 : dessiner le trottoir (ligne 12) avec pygame.draw.rect(screen, TROTTOIR, pygame.Rect(0, 12 * TILE, WIDTH, TILE)), puis toutes les lignes avec for row in range(ROWS), une variable color choisie par if / elif / else, et un seul draw.rect. Je choisis mes couleurs.
- F3 : pointillés de la route (lignes 8 à 11, une colonne sur deux avec %) ; 5 maisons aux colonnes 2, 4, 6, 8, 10 (formule col = 2 + i * 2 pour i dans range(5)) ; grenouille avec frog_col = COLS // 2 et frog_row = ROWS - 1, carré plus petit qu'une case grâce à une marge (position col * TILE + marge, taille TILE - 2 * marge).
- Pourquoi redessiner tout à chaque image : pour effacer l'image précédente (sinon traînées quand ça bouge). screen.fill si le décor ne couvre pas tout l'écran.
Code de référence du fil rouge (une solution possible, visible dans la fiche sous un bouton « solution ») :
import sys
import pygame
TILE = 48
COLS = 13
ROWS = 13
WIDTH = COLS * TILE
HEIGHT = ROWS * TILE
HAIE = (34, 70, 50)
NENUPHAR = (96, 150, 90)
EAU = (58, 104, 150)
BERGE = (118, 158, 98)
ROUTE = (52, 54, 60)
MARQUAGE = (225, 215, 150)
TROTTOIR = (150, 138, 118)
GRENOUILLE = (130, 205, 80)
pygame.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Frogger d'entraînement - Lundi")
clock = pygame.time.Clock()
frog_col = COLS // 2
frog_row = ROWS - 1
while True:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
# Décor : chaque ligne de la grille reçoit la couleur de sa zone
for row in range(ROWS):
if row == 0:
color = HAIE
elif row <= 5:
color = EAU
elif row == 6:
color = BERGE
elif row <= 11:
color = ROUTE
else:
color = TROTTOIR
pygame.draw.rect(screen, color, pygame.Rect(0, row * TILE, WIDTH, TILE))
# Pointillés entre les voies de la route
for row in range(8, 12):
for col in range(COLS):
if col % 2 == 0:
dash = pygame.Rect(col * TILE + 8, row * TILE - 2, TILE - 16, 4)
pygame.draw.rect(screen, MARQUAGE, dash)
# Les 5 maisons, régulièrement espacées dans la haie
for i in range(5):
col = 2 + i * 2
pygame.draw.rect(screen, NENUPHAR, pygame.Rect(col * TILE + 4, 4, TILE - 8, TILE - 8))
# La grenouille, placée à partir de sa case (colonne, ligne)
margin = 8
frog = pygame.Rect(frog_col * TILE + margin, frog_row * TILE + margin, TILE - 2 * margin, TILE - 2 * margin)
pygame.draw.rect(screen, GRENOUILLE, frog)
pygame.display.flip()
Section 6, Le coin des commentaires : un commentaire (#) est ignoré par Python, écrit pour les humains ; règle du professeur : pas de commentaire à chaque ligne, un commentaire décrit l'intention d'une portion de code ; test : « si je supprime ce commentaire, un lecteur qui connaît Python perd-il une information ? » ; inutile « margin = 8 # la marge vaut 8 », utile « # La grenouille, placée à partir de sa case (colonne, ligne) » au-dessus du bloc. Exercice : réécrire une boucle de décor sur-commentée (« # on fait une boucle sur les lignes », « # si row vaut 0 », « # la couleur est HAIE », « # on dessine un rectangle »…) en gardant un seul commentaire « # Décor : chaque ligne de la grille reçoit la couleur de sa zone » (solution dans la fiche) ; puis relire mon frogger.py : au plus un commentaire par bloc. Relis aussi mes commentaires quand je te montre mon code.
Section 7, Défis perso (sans solution) :
- D1 : son propre terrain (nombre de voies, taille des cases, palette), avec des constantes pour tout changer à un seul endroit.
- D2 : explorer la documentation pygame.draw (https://pyga.me/docs/ref/draw.html) et utiliser au moins deux fonctions nouvelles (circle, ellipse, line, polygon…) en sachant expliquer chaque argument.
- D3 : une « voiture » (variable car_x) qui avance à chaque tour et revient à gauche quand elle sort à droite ; observer l'effet de la valeur de clock.tick.
Section 8, Pièges classiques : fenêtre qui se ferme aussitôt (pas de while True ou mauvaise indentation) ; « Ne répond pas » (pas d'event.get) ; fenêtre noire (pas de flip ou flip hors de la boucle) ; traînées (fond pas repeint) ; ModuleNotFoundError (installer avec python -m pip) ; IndentationError ; un elif jamais atteint (un if précédent a déjà attrapé le cas).
Section 9, Checklist défense « je sais expliquer » : chaque ligne du squelette et leur ordre ; les 4 temps d'un tour de boucle ; init, set_mode, Clock, tick, event.get, Rect, draw.rect, flip ; le repère et le sens de y ; passer de (col, row) aux pixels et inversement ; /, // et % ; pourquoi des constantes ; chaque fonction pygame.draw découverte en défi.
Section 10, Mini-oral (réponses attendues) :
1. clock.tick(60) : limite à 60 images/s ; sans lui, vitesse dépendante de la machine et processeur à 100 %.
2. flip : échange l'image cachée (dessinée) avec l'image affichée ; pas de clignotement.
3. Redessiner tout : effacer l'image précédente, éviter les traînées.
4. Pixel (250, 400) avec TILE = 48 : colonne 5, ligne 8.
5. event.get obligatoire : l'OS attend que la file soit lue, sinon « Ne répond pas ».
6. Changer TILE : tout s'adapte car tout est calculé à partir de TILE.
# TA PÉDAGOGIE
0. Titre de la conversation : ton tout premier message commence par cette ligne seule, en gras : « 🐸 Frogger en 7 jours · <Jour> : <titre du jour> », avec le jour et le titre de la section AUJOURD'HUI (par exemple « 🐸 Frogger en 7 jours · Mardi : Premier saut »). Juste en dessous, en une phrase courte, conseille-moi de renommer cette conversation avec ce titre si mon application ne l'a pas fait toute seule, pour la retrouver facilement dans mon historique.
1. Démarrage : présente-toi en deux phrases comme mon prof du jour et rappelle l'objectif de la journée. Pose-moi 2 ou 3 questions courtes pour évaluer où j'en suis (les questions de démarrage suggérées plus haut t'aident). Vérifie aussi que mon code de la veille fonctionne. Puis propose un plan pour la journée qui suit les sections de la fiche, en adaptant le rythme à mes réponses.
2. Une chose à la fois. Messages courts. Termine souvent par une question pour vérifier que j'ai compris, ou par une petite tâche à faire dans mon éditeur.
3. Méthode socratique : avant d'expliquer, demande-moi ce que je pense. Quand je me trompe, ne donne pas la réponse : pose une question qui m'aide à voir l'erreur.
4. Utilise des analogies concrètes et des schémas en texte quand ça aide.
5. Quand je te montre mon code : commence par ce qui est bien, signale les erreurs par des questions ou des indices, et vérifie toujours mes noms et mes commentaires selon les règles du guide « Bien commenter son code » (pointe les commentaires qui répètent le code, ceux qui manquent là où un « pourquoi » serait utile, les commentaires faux, le code commenté). Rappelle-moi le coin des commentaires du jour si je l'oublie.
6. Encourage-moi à taper le code moi-même et à lancer souvent mon programme.
7. Relie toujours les notions au projet Frogger et à la défense (« le jour de l'oral, ton prof pourrait te demander… »).
8. Si je bloque sur une notion de base, renvoie-moi vers la section de la fiche ou vers le cours de mon professeur. Si la notion vient d'un jour précédent, fais-moi une révision express.
9. Reste sur le programme du jour. Si je demande quelque chose d'un jour suivant, réponds brièvement et dis-moi que c'est prévu tel jour.
# CE QUE TU NE FAIS JAMAIS
- Tu n'écris jamais le code de mon projet Frogger à ma place, même partiellement, même si j'insiste, même si je dis que c'est pour un exercice. Tu ne donnes jamais de solution aux défis perso (D1, D2…).
- Pour les échauffements (E…) et le fil rouge (F…), tu guides avec des indices progressifs. Tu ne donnes la solution complète d'un exercice que si la fiche en contient une, que j'ai vraiment essayé (je t'ai montré au moins une tentative) et que je la demande explicitement ; dans ce cas, tu me fais ensuite expliquer chaque ligne. Pour les étapes marquées « sans solution » dans la fiche, tu ne donnes jamais la solution : seulement des indices.
- Tu peux montrer de petits exemples de code (5 lignes maximum) qui illustrent une notion sur un autre sujet que Frogger.
- Si je te demande de faire mon projet, refuse gentiment et explique pourquoi : la défense orale, la note de maîtrise qui multiplie la note, et le risque de plagiat. Propose immédiatement de m'aider autrement.
- Tu n'inventes pas de fonctions pygame ou pygame_gui. Si tu n'es pas sûr d'un détail de l'API, dis-le et renvoie-moi vers la documentation officielle.
# MES COMMANDES
- /indice : un petit indice sur ce que je suis en train de faire, sans la solution. Chaque nouvel /indice est un peu plus précis.
- /explique : réexplique la dernière notion autrement, avec une analogie ou un schéma en texte.
- /bug : je colle mon code et le message d'erreur complet ; tu m'aides à comprendre l'erreur et à trouver moi-même la correction (lis le message d'erreur avec moi, ligne par ligne).
- /quiz : 5 questions rapides sur le sujet du jour, une à la fois, avec correction après chaque réponse.
- /oral : oral blanc comme le jour de la défense. Tu joues mon professeur : tu me poses une question à la fois sur les notions du jour, les fonctions pygame du jour et mon code ; tu creuses avec des « pourquoi ? » et des « et si on changeait… ? ». À la fin, tu me donnes une note de maîtrise sur 1 et les 3 points à retravailler.
- /recap : résumé de ce que j'ai appris aujourd'hui et de ce qu'il me reste à faire dans la TODO liste du jour.
Commence maintenant par te présenter et me poser tes questions de démarrage.
Commandes : /indice /explique /bug /quiz /oral /recap
Pas envie de tout lire ?
Commence par ces étapes. Pour le reste, avance avec ton prof IA : il connaît toute la fiche.
- Objectif du jource que tu dois avoir à la fin de la journée1 min
- Le fil rouge : le terrain de jeula brique Frogger du jour, à faire dans ton éditeur1 h
- Checklist défense : je sais expliquer…ce que tu dois savoir expliquer le jour de la défense5 min
- Aide-mémoire du lunditout le jour en un coup d'œil, à garder ouvert2 min
Un paragraphe pas clair ? Copie-le dans ton IA et tape /explique.
Sommaire de la page
- Ton prof du jour
- Objectif du jour
- 1. Installation (15 min)
- 2. Le Python du jour (45 min)
- 3. Échauffements (30 min)
- 4. Les fonctions pygame du jour
- 5. Le fil rouge : le terrain de jeu (1 h)
- 6. Le coin des commentaires (10 min)
- 7. Défis perso (30 min, sans solution)
- 8. Les pièges classiques
- 9. Checklist défense : je sais expliquer…
- 10. Mini-oral
- 11. Aide-mémoire du lundi
- Pour aller plus loin
Objectif du jour
À la fin de la journée, tu auras une fenêtre qui affiche le terrain de Frogger : les maisons, la rivière, la berge, la route et le trottoir, avec une grenouille posée au départ.
Rien ne bouge encore. Mais tu auras compris la boucle de jeu, le cœur de tout jeu vidéo, et tu sauras dessiner sur une grille. Tout le reste de la semaine repose là-dessus.
Lien avec le cahier des charges : aucun point directement aujourd'hui, mais ce sont les fondations de tous les points.
1. Installation (15 min)
Installer les bibliothèques
Ouvre un terminal (dans Zed : Terminal → New Terminal) et tape :
python -m pip install pygame_ce
python -m pip install pygame_gui
Ce sont exactement les commandes du cours de ton prof.
Vérifier que tout marche
python -c "import pygame; print(pygame.version.ver)"
Tu dois voir une ligne qui commence par pygame-ce suivie d'un numéro de version. Si tu vois une erreur, colle-la à ton prof IA avec /bug.
2. Le Python du jour (45 min)
Ouvre un fichier essais.py dans ton éditeur et teste chaque exemple. Lance-le avec python essais.py.
2.1 Les variables et les types
Une variable est un nom qui désigne une valeur. On la crée avec =.
lives = 3 # int : un nombre entier
speed = 2.5 # float : un nombre à virgule
name = "Kermit" # str : du texte
is_alive = True # bool : True ou False
position = (6, 12) # tuple : plusieurs valeurs groupées
Pour connaître le type d'une valeur : print(type(speed)) affiche <class 'float'>.
Les tuples vont te servir tout de suite : pygame les utilise partout, pour les tailles (800, 600), les positions (x, y) et les couleurs (rouge, vert, bleu). On lit une case avec son indice, qui commence à 0 : position[0] vaut 6.
Les constantes
Une valeur qui ne change jamais pendant le programme s'écrit en MAJUSCULES. Python ne l'interdit pas de la modifier, c'est une convention pour les humains qui lisent le code.
TILE = 48 # taille d'une case de la grille, en pixels
COLS = 13 # nombre de colonnes
2.2 Les opérateurs
| Opérateur | Sens | Exemple | Résultat |
|---|---|---|---|
+ - * | addition, soustraction, multiplication | 13 * 48 | 624 |
/ | division (toujours un float) | 250 / 48 | 5.208… |
// | division entière | 250 // 48 | 5 |
% | reste de la division (modulo) | 250 % 48 | 10 |
** | puissance | 2 ** 3 | 8 |
On peut aussi modifier une variable à partir de sa propre valeur : lives -= 1 est un raccourci pour lives = lives - 1. Pareil avec +=, *=…
Afficher pour comprendre : les f-strings
score = 120
print(f"Score : {score}, vies : {lives}")
Le f devant les guillemets permet de glisser des variables entre { }. Quand ton jeu fait quelque chose de bizarre, un print bien placé est ton premier outil de débogage.
2.3 Les conditions
if row == 0:
print("Les maisons")
elif row <= 5:
print("La rivière")
else:
print("Ailleurs")
- Python teste les conditions dans l'ordre et exécute seulement le premier bloc vrai. C'est pour ça que
elif row <= 5ne concerne que les lignes 1 à 5 : la ligne 0 a déjà été prise par leif. - Le contenu de chaque bloc est indenté (décalé de 4 espaces). L'indentation n'est pas décorative en Python : elle définit les blocs.
Les comparaisons : == (égal), != (différent), <, <=, >, >=.
On combine avec and, or, not :
if row == 0 and col % 2 == 0:
print("Peut-être une maison")
2.4 Les boucles
while : tant que…
time_left = 3
while time_left > 0:
print(time_left)
time_left -= 1
print("Temps écoulé !")
La boucle tourne tant que la condition est vraie. Avec while True:, elle tourne pour toujours… et c'est exactement ce qu'on veut pour un jeu (on verra comment en sortir).
for : pour chaque…
for row in range(13):
print(row) # affiche 0, 1, 2, … 12
range(13)produit les nombres de 0 à 12 (13 non compris).range(8, 12)produit 8, 9, 10, 11.
Les boucles imbriquées
Une boucle dans une boucle permet de parcourir une grille : pour chaque ligne, pour chaque colonne.
for row in range(3):
for col in range(4):
print(f"case ({col}, {row})")
La boucle intérieure fait tous ses tours à chaque tour de la boucle extérieure : ce code affiche 3 × 4 = 12 cases.
📚 Pour revoir ces notions : Python 1 · Chapitre 2 du cours de ton prof.
3. Échauffements (30 min)
Du Python pur, dans le terminal. Crée un fichier echauffement.py.
E1. La taille de la fenêtre
Crée les constantes TILE = 48, COLS = 13 et ROWS = 13. Calcule WIDTH et HEIGHT, la taille de la fenêtre en pixels, à partir de ces constantes (pas en écrivant 624 à la main). Affiche :
La fenêtre fait 624 x 624 pixels
Puis change TILE en 32 et relance : tout doit s'adapter tout seul.
E2. Du pixel à la case, et retour
Le joueur clique au pixel x = 250, y = 400.
- Dans quelle colonne et quelle ligne de la grille a-t-il cliqué ? (Réponse attendue : colonne 5, ligne 8.)
- Quelles sont les coordonnées en pixels du coin en haut à gauche de cette case ?
- Et celles de son centre ?
Réponses de E2
col = x // TILEvaut5,row = y // TILEvaut8.(col * TILE, row * TILE)vaut(240, 384).(col * TILE + TILE // 2, row * TILE + TILE // 2)vaut(264, 408).
E3. Dans quelle zone suis-je ?
Notre terrain fait 13 lignes, numérotées de 0 (en haut) à 12 (en bas) :
| Ligne | Zone |
|---|---|
| 0 | les maisons |
| 1 à 5 | la rivière |
| 6 | la berge (zone sûre au milieu) |
| 7 à 11 | la route |
| 12 | le trottoir de départ |
- Avec une variable
rowet une suite deif / elif / else, affiche le nom de la zone. Teste avecrow = 0,3,6,9et12. - Mets ce code dans une boucle
forpour afficher la zone de chaque ligne, de 0 à 12.
E4. Le plateau en texte
Avant de dessiner avec pygame, dessinons avec des caractères ! Avec deux boucles imbriquées et tes conditions de E3, affiche le plateau. Chaque ligne est une chaîne de 13 caractères :
#pour la haie,Mpour une maison (colonnes 2, 4, 6, 8 et 10 de la ligne 0)~pour l'eau,.pour la berge,=pour la route,_pour le trottoirGpour la grenouille, en colonneCOLS // 2sur la dernière ligne
Résultat attendu :
##M#M#M#M#M##
~~~~~~~~~~~~~
~~~~~~~~~~~~~
~~~~~~~~~~~~~
~~~~~~~~~~~~~
~~~~~~~~~~~~~
.............
=============
=============
=============
=============
=============
______G______
Ce plateau en texte, c'est exactement ce qu'on va dessiner en couleurs dans quelques minutes.
4. Les fonctions pygame du jour
Le cahier des charges est clair : tu dois savoir expliquer chaque fonction pygame que tu utilises. Voici celles d'aujourd'hui.
Le repère de l'écran
En pygame, l'origine (0, 0) est en haut à gauche. x augmente vers la droite, et y augmente vers le bas (l'inverse des maths !).
(0,0) ─────────────► x
│
│ (x, y)
│ ┌──────────┐
│ │ │ hauteur
│ └──────────┘
│ largeur
▼
y
C'est pour ça que la ligne 0 de notre grille est en haut de l'écran.
Les fonctions
| Fonction | Ce qu'elle fait |
|---|---|
pygame.init() | Initialise tous les modules de pygame. À appeler une fois, au début. |
pygame.display.set_mode((w, h)) | Demande au système d'exploitation une fenêtre de w × h pixels. Renvoie une Surface : l'image sur laquelle on dessine (souvent appelée screen). |
pygame.display.set_caption(texte) | Change le titre de la fenêtre. |
pygame.time.Clock() | Crée une horloge qui sert à régler la vitesse de la boucle. |
clock.tick(60) | Attend juste ce qu'il faut pour ne pas dépasser 60 images par seconde. Sans ça, la boucle tourne aussi vite que possible : le jeu irait plus ou moins vite selon l'ordinateur. Renvoie le temps écoulé depuis le tick précédent, en millisecondes (utile plus tard). |
pygame.event.get() | Vide la file d'événements (touches, clics, fermeture…) et renvoie la liste des événements arrivés depuis le dernier appel. |
pygame.QUIT | Le type d'événement envoyé quand on ferme la fenêtre. |
sys.exit() | Termine le programme (module sys, à importer). |
pygame.Rect(x, y, w, h) | Un rectangle : position du coin en haut à gauche et taille. Il ne dessine rien tout seul ; c'est une zone. On s'en resservira pour les collisions. |
pygame.draw.rect(surface, couleur, rect) | Dessine le rectangle rect rempli avec couleur sur surface. |
pygame.display.flip() | Affiche à l'écran l'image qu'on vient de dessiner. |
Pourquoi flip() ? Le double tampon
La fenêtre a deux images : celle qui est affichée, et une image cachée sur laquelle on dessine. Si on dessinait directement sur l'image affichée, le joueur verrait le dessin se faire morceau par morceau (ça clignote). On dessine donc tout sur l'image cachée, puis flip() échange les deux d'un coup.
📚 Ton prof l'explique très bien dans le Chapitre 4 de Python 1. Et toutes les fonctions sont dans la documentation de pygame-ce.
5. Le fil rouge : le terrain de jeu (1 h)
F1. La boucle de jeu
Tout jeu vidéo tourne dans une boucle qui se répète environ 60 fois par seconde. Chaque tour de boucle, c'est une image, et chaque image suit toujours les mêmes 4 temps :
- Attendre pour garder un rythme régulier (
clock.tick) - Écouter les événements (clavier, souris, fermeture)
- Mettre à jour l'état du jeu (positions, vies… rien aujourd'hui)
- Dessiner l'image, puis l'afficher (
flip)
Crée un fichier frogger.py et tape (sans copier-coller) ce squelette :
import sys
import pygame
TILE = 48
COLS = 13
ROWS = 13
WIDTH = COLS * TILE
HEIGHT = ROWS * TILE
pygame.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Frogger d'entraînement")
clock = pygame.time.Clock()
while True:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
# Le dessin viendra ici
pygame.display.flip()
Lance-le : une fenêtre noire s'ouvre, et se ferme quand tu cliques sur la croix. 🎉
F2. Dessiner le décor
On veut dessiner une bande de couleur par ligne de la grille, en suivant les zones de E3.
Une ligne d'abord. Ajoute une couleur et dessine le trottoir (la ligne 12) :
TROTTOIR = (150, 138, 118)
pygame.draw.rect(screen, TROTTOIR, pygame.Rect(0, 12 * TILE, WIDTH, TILE))
Lis bien chaque argument de pygame.Rect : il commence à x = 0, à la hauteur de la ligne 12, il fait toute la largeur et une case de haut.
Puis toutes les lignes. À toi : avec une boucle for row in range(ROWS) et tes conditions de E3, choisis une couleur pour chaque ligne et dessine sa bande. Choisis tes couleurs toi-même : un outil de sélection de couleur en ligne te donne les valeurs (R, G, B).
F3. Les détails : marquage, maisons et grenouille
- Les pointillés de la route. Entre les voies de la route (lignes 8 à 11), dessine un petit rectangle une colonne sur deux. Deux boucles imbriquées et un
%! - Les 5 maisons. Dans la ligne 0, dessine une case de couleur aux colonnes 2, 4, 6, 8 et 10. Trouve une formule qui donne ces colonnes à partir de
idansrange(5). - La grenouille. Crée deux variables
frog_col = COLS // 2etfrog_row = ROWS - 1, puis dessine un carré un peu plus petit qu'une case à cette position. Change les valeurs defrog_coletfrog_row: la grenouille doit se déplacer sur la grille.
Tu devrais obtenir quelque chose comme ceci (avec tes couleurs) :

Une solution possible (essaie vraiment avant de regarder !)
import sys
import pygame
# Dimensions de la grille : tout le reste en découle
TILE = 48
COLS = 13
ROWS = 13
WIDTH = COLS * TILE
HEIGHT = ROWS * TILE
# Palette (R, G, B)
HAIE = (34, 70, 50)
NENUPHAR = (96, 150, 90)
EAU = (58, 104, 150)
BERGE = (118, 158, 98)
ROUTE = (52, 54, 60)
MARQUAGE = (225, 215, 150)
TROTTOIR = (150, 138, 118)
GRENOUILLE = (130, 205, 80)
pygame.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Frogger d'entraînement - Lundi")
clock = pygame.time.Clock()
frog_col = COLS // 2
frog_row = ROWS - 1
while True:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
# Décor : chaque ligne de la grille reçoit la couleur de sa zone
for row in range(ROWS):
if row == 0:
color = HAIE
elif row <= 5:
color = EAU
elif row == 6:
color = BERGE
elif row <= 11:
color = ROUTE
else:
color = TROTTOIR
pygame.draw.rect(screen, color, pygame.Rect(0, row * TILE, WIDTH, TILE))
# Pointillés entre les voies de la route
for row in range(8, 12):
for col in range(COLS):
if col % 2 == 0:
dash = pygame.Rect(col * TILE + 8, row * TILE - 2, TILE - 16, 4)
pygame.draw.rect(screen, MARQUAGE, dash)
# Les 5 maisons, régulièrement espacées dans la haie
for i in range(5):
col = 2 + i * 2
pygame.draw.rect(screen, NENUPHAR, pygame.Rect(col * TILE + 4, 4, TILE - 8, TILE - 8))
# La grenouille, placée à partir de sa case (colonne, ligne)
margin = 8
frog = pygame.Rect(frog_col * TILE + margin, frog_row * TILE + margin,
TILE - 2 * margin, TILE - 2 * margin)
pygame.draw.rect(screen, GRENOUILLE, frog)
pygame.display.flip()
Remarque les commentaires : un par bloc, qui dit pourquoi le bloc existe. Pas un par ligne. C'est exactement ce que demande ton prof.
Pourquoi on redessine tout à chaque image ?
Le décor ne bouge pas… alors pourquoi le redessiner 60 fois par seconde ? Parce que demain, la grenouille va bouger. Si on ne repeignait pas le décor par-dessus, on verrait toutes ses anciennes positions, comme une traînée. Redessiner toute l'image à chaque tour, c'est la base de toute animation.
6. Le coin des commentaires (10 min)
Aujourd'hui : qu'est-ce qu'un bon commentaire ?
Tout ce qui suit un # sur une ligne est un commentaire : Python l'ignore complètement. Il est écrit pour des humains : ton binôme, ton correcteur, et toi-même dans deux semaines.
Ton prof est très clair dans le cahier des charges : un code commenté à chaque ligne n'est pas un code valable. Un commentaire décrit l'intention d'une portion de code ; il ne traduit pas le code en français.
Le test à faire pour chaque commentaire :
Si je supprime ce commentaire, est-ce que quelqu'un qui connaît Python perd une information ?
Si la réponse est non, le commentaire est inutile.
❌ Inutile : il répète ce que le code dit déjà.
margin = 8 # la marge vaut 8
✅ Utile : il dit à quoi sert le bloc, ce qu'on ne voit pas en lisant les lignes une par une.
# La grenouille, placée à partir de sa case (colonne, ligne)
margin = 8
frog = pygame.Rect(frog_col * TILE + margin, frog_row * TILE + margin,
TILE - 2 * margin, TILE - 2 * margin)
pygame.draw.rect(screen, GRENOUILLE, frog)
Exercice
Ce code est sur-commenté. Réécris-le en ne gardant que ce qui apporte une information (indice : un seul commentaire suffit).
# on fait une boucle sur les lignes
for row in range(ROWS):
# si row vaut 0
if row == 0:
color = HAIE # la couleur est HAIE
# sinon si row est plus petit ou égal à 5
elif row <= 5:
color = EAU # couleur de l'eau
else:
color = ROUTE
# on dessine un rectangle
pygame.draw.rect(screen, color, pygame.Rect(0, row * TILE, WIDTH, TILE))
Une version possible
# Décor : chaque ligne de la grille reçoit la couleur de sa zone
for row in range(ROWS):
if row == 0:
color = HAIE
elif row <= 5:
color = EAU
else:
color = ROUTE
pygame.draw.rect(screen, color, pygame.Rect(0, row * TILE, WIDTH, TILE))
Puis relis ton propre frogger.py : au plus un commentaire par bloc, qui dit à quoi sert le bloc.
7. Défis perso (30 min, sans solution)
C'est ici que ton Frogger commence à devenir le tien. Fais tes propres choix, et sois prêt à les expliquer.
8. Les pièges classiques
| Symptôme | Cause probable |
|---|---|
| La fenêtre s'ouvre et se ferme aussitôt | Il manque la boucle while True:, ou le dessin n'est pas indenté dedans. |
| La fenêtre « Ne répond pas » | pygame.event.get() n'est pas appelé à chaque tour de boucle. |
| La fenêtre reste noire | Il manque pygame.display.flip(), ou il est en dehors de la boucle. |
| Les objets laissent une traînée | On ne repeint pas le fond avant de redessiner. |
ModuleNotFoundError: No module named 'pygame' | pygame-ce n'est pas installé pour ce Python. Utilise bien python -m pip install. |
IndentationError | Mélange d'espaces et de tabulations, ou bloc mal aligné. |
Un if qui ne fait jamais rien | Un if précédent dans la même chaîne if / elif a déjà « attrapé » le cas. L'ordre compte ! |
9. Checklist défense : je sais expliquer…
10. Mini-oral
Réponds à voix haute, puis vérifie. Mieux : tape /oral dans ton IA.
1. Que fait clock.tick(60) ? Que se passerait-il sans ?
Il limite la boucle à 60 tours (images) par seconde en attendant le temps nécessaire. Sans lui, la boucle tourne aussi vite que l'ordinateur le permet : le jeu irait plus vite sur un ordinateur puissant et consommerait 100 % du processeur.
2. À quoi sert pygame.display.flip() ?
On dessine sur une image cachée ; flip() l'échange avec l'image affichée. Le joueur voit l'image complète d'un coup, sans clignotement.
3. Pourquoi redessiner tout le décor à chaque image ?
Pour effacer l'image précédente. Sinon, tout ce qui bouge laisserait une traînée de ses anciennes positions.
4. Le pixel (250, 400) est dans quelle case si TILE = 48 ?
Colonne 250 // 48 = 5, ligne 400 // 48 = 8. La division entière donne le numéro de la case.
5. Pourquoi faut-il appeler pygame.event.get() même si on ne gère que la fermeture ?
Le système d'exploitation envoie des messages à la fenêtre et attend qu'ils soient lus. Si la file n'est jamais vidée, il considère que le programme est bloqué (« Ne répond pas »).
6. Que se passe-t-il si je change TILE de 48 à 32 ?
Tout s'adapte : la taille de la fenêtre, des bandes, des maisons et de la grenouille, puisque tout est calculé à partir de TILE. C'est tout l'intérêt des constantes.
11. Aide-mémoire du lundi
# Variables et types
n = 3; v = 2.5; s = "texte"; ok = True; pos = (6, 12)
# Opérateurs de grille
col = x // TILE # pixel -> case
x = col * TILE # case -> pixel (coin haut gauche)
col % 2 == 0 # une colonne sur deux
# Conditions
if a == b and not c:
...
elif d <= e:
...
else:
...
# Boucles
while condition:
...
for i in range(5): # 0, 1, 2, 3, 4
...
for row in range(ROWS): # grille
for col in range(COLS):
...
# Squelette pygame
pygame.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
clock = pygame.time.Clock()
while True:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
pygame.draw.rect(screen, (R, G, B), pygame.Rect(x, y, w, h))
pygame.display.flip()
Pour aller plus loin
- 📚 Python 1 · Chapitre 2 : Valeurs, types et contrôle de flux
- 📚 Python 1 · Chapitre 4 : Programmation graphique
- 📚 Python 2 · Cours 3 : Interface graphique
- 📖 Documentation pygame-ce : pygame.draw et pygame.Rect
Demain, mardi : les fonctions, le clavier, et la grenouille fait son premier saut 🐸