CoderDojo: Python & Pygame

Bienvenue ! Voici le curriculum pour les ninjas entre 10 et 17 ans qui veulent apprendre Python et Pygame en créant des jeux.

Comment ça marche ?

  • 10 sessions de 3 heures, environ une fois par mois (sauf en juillet et en août).
  • À chaque session, tu crées un petit jeu complet en 3 heures.
  • Tu rates une session ? Pas de problème : tu peux toujours rejoindre le groupe.
  • Amuse-toi, expérimente, et demande à un coach si tu bloques.

Dojo Defender, pour les ninjas réguliers

Pour ceux qui suivent 4 sessions ou plus : on construit ensemble un jeu maison, Dojo Defender, qui grandit chaque mois. Tu ne viens qu’occasionnellement ? Fais simplement le jeu de la session du jour. Il est toujours complet en soi.

30 octobre 2026, 15:59

Sous-sections de CoderDojo: Python & Pygame

Installation

Pour créer un jeu Python, il te faut deux choses :

  1. Python : le langage de programmation qui exécute ton code. L’ordinateur comprend Python, pas le néerlandais ni l’anglais.
  2. Un éditeur : le programme dans lequel tu tapes ton code. Comme Word, mais pour du code.

Tu n’as jamais programmé ? Commence par Thonny, car il installe Python automatiquement et il est spécialement conçu pour les débutants.

Choisis ton éditeur

  • Thonny : ★☆☆ Facile. Pour les débutants. Installe Python automatiquement. C’est le point de départ de toutes les sessions CoderDojo.
  • VS Code : ★★☆ Moyen. L’éditeur que les programmeurs professionnels utilisent. Bien si Thonny te semble trop petit et que tu veux gérer plusieurs fichiers.
  • PyCharm : ★★★ Avancé. Un IDE complet avec débogueur intégré et aide intelligente à la saisie. Pour quand tu programmes déjà depuis un moment.

Ensuite : un environnement virtuel

Tu as choisi un éditeur ? Lis alors aussi comment fonctionnent les environnements virtuels. C’est le « sac à dos » de chaque projet Python — un dossier séparé avec exactement les bons paquets pour ton jeu.

Ça ne marche pas ? Va voir Résolution de problèmes. Tu y trouves les erreurs d’installation les plus courantes avec leur solution.

30 octobre 2026, 15:59

Sous-sections de Installation

Installer Thonny + Pgzero

Installation rapide

Télécharge le script pour ton système d’exploitation. Un double-clic et il installe Python, uv, Thonny, pgzero, pygame-ce et tout le code de départ pour toi. Prêt en 5 à 10 minutes.

Ton système d'exploitation est en cours de détection...

Afficher tous les téléchargements

Astuce

Le script est sûr : il installe seulement les mêmes programmes que les étapes manuelles ci-dessous. Tu peux consulter le code source en ouvrant le fichier dans le Bloc-notes ou dans un éditeur de texte.


Installation manuelle

Thonny est un éditeur Python gratuit, spécialement conçu pour les débutants. Il installe Python automatiquement. Après l’installation, vérifie quelle version de Python tu as : ton jeu fonctionne avec Python 3.13, 3.14 ou 3.15.

Installer Thonny

Va sur thonny.org et télécharge la version pour ton système d’exploitation.

Windows

Télécharge le fichier .exe et double-clique dessus. Suis les étapes d’installation (clique simplement sur “Next”). Ensuite, tu retrouves Thonny dans le menu Démarrer.

macOS

Télécharge le fichier .pkg et ouvre-le. Glisse Thonny dans ton dossier Applications. La première fois que tu l’ouvres, clique avec le bouton droit et choisis “Open” (pour que macOS lui fasse confiance).

Linux

Ouvre un terminal et tape :

bash <(wget -qO - https://thonny.org/installer-for-linux)

Ou utilise ton gestionnaire de paquets si Thonny y est disponible (par ex. sudo apt install thonny sur Ubuntu).

Remarque

Utilise la version de thonny.org, pas celle de l’app store. Elle est parfois obsolète.

Vérifier la version de Python

Pygame-ce et pgzero ont des versions prêtes à l’emploi pour Python 3.13, 3.14 et 3.15. Les versions plus récentes (3.16 ou plus) ne fonctionnent pas encore.

  1. Ouvre Thonny.
  2. Regarde en bas à droite de la fenêtre. La version active de Python y est affichée, par ex. Python 3.14.8.
  3. Tu vois 3.13, 3.14 ou 3.15 ? Alors tout va bien. Tu vois autre chose ? Installe alors Python 3.14 avec les étapes ci-dessous.
Astuce

Tu vois Python 3.13, 3.14 ou 3.15 ? Saute le reste de cette partie et passe à Installer Pygame-ce.

Installer Python 3.14 et faire pointer Thonny dessus

  1. Va sur python.org/downloads et clique sur “All releases”. Cherche Python 3.14 dans la liste et télécharge l’installeur pour ton système d’exploitation.
    • Windows : choisis le Windows installer (64-bit) et laisse la case “Add Python to PATH” cochée.
    • macOS : choisis le macOS 64-bit universal2 installer.
    • Linux : utilise ton gestionnaire de paquets, par ex. sudo apt install python3.14.
  2. Déroule l’installation et termine-la.
  3. Ouvre Thonny et clique en bas à droite sur le nom de la version de Python (ou va dans Tools → Options → Interpreter).
  4. Choisis “Interpréteur Python 3 alternatif ou environnement virtuel”.
  5. Clique sur l’icône de dossier et navigue jusqu’à l’exécutable Python 3.14 :
    • Windows : C:\Users\<tonnom>\AppData\Local\Programs\Python\Python314\python.exe
    • macOS : /Library/Frameworks/Python.framework/Versions/3.14/bin/python3
    • Linux : /usr/bin/python3.14
  6. Clique sur OK et redémarre Thonny.

En bas à droite, tu vois maintenant Python 3.14. Passe à l’installation de Pygame-ce.

Installer Pygame-ce

Pgzero a besoin de Pygame pour fonctionner. On utilise pygame-ce, la version communautaire maintenue qui fonctionne aussi sur Python 3.14 et 3.15. Dans ton code, ça reste simplement import pygame.

  1. Ouvre Thonny.
  2. Clique en haut sur Tools → Manage packages…
  3. Tape dans le champ de recherche : pygame-ce
  4. Clique sur le résultat de recherche et ensuite sur Install.
  5. Attends la fin de l’installation (tu vois “Done” en bas).

Installer Pgzero

Pgzero est la bibliothèque avec laquelle tu crées des petits jeux. Voici comment l’installer :

  1. Retourne dans Tools → Manage packages…
  2. Tape dans le champ de recherche : pgzero
  3. Clique sur le résultat de recherche et ensuite sur Install.

Vérifie ensuite que la version est 1.2 ou plus. Tu vois la version à droite du nom dans la liste des paquets.

Remarque

L’installation de pgzero bloque sur Python 3.14 ou 3.15 ? C’est parce que pgzero entraîne automatiquement l’ancien pygame, qui n’a pas de version prête à l’emploi pour ces versions. Utilise alors le script d’installation en un clic en haut de cette page, ou choisis Python 3.13 dans Thonny.

Tester si tout fonctionne

Crée un nouveau fichier dans Thonny et colle ce code dedans :

# test_setup.py
import pgzrun

WIDTH = 400
HEIGHT = 300

def draw():
    screen.fill((30, 30, 60))
    screen.draw.text("Pgzero fonctionne !", center=(200, 150), color="white")

pgzrun.go()

Enregistre-le sous test_setup.py et clique sur le bouton vert Run dans Thonny.

Si tout va bien, une fenêtre s’ouvre avec un fond bleu foncé et le texte “Pgzero fonctionne !”. Ferme la fenêtre en cliquant sur la croix.

Ça ne marche pas ?

Pas de panique ! Va voir la page de résolution de problèmes pour les erreurs les plus courantes et comment les résoudre.

30 octobre 2026, 15:59

VS Code (parcours avancé)

Tu as déjà fait quelques sessions de Python et tu veux plus de contrôle sur ton code ? Alors VS Code est un bon pas suivant. C’est l’éditeur que les vrais programmeurs utilisent aussi.

Quand changer ?

Seulement quand Thonny te paraît trop limité, par exemple si tu veux gérer plusieurs fichiers à la fois, utiliser Git, ou si tu es juste curieux de voir comment les développeurs professionnels travaillent.

Changer n’est pas obligatoire. Thonny reste parfait pour les débutants et les sessions courtes.

Astuce : essaie VS Code quand tu as déjà suivi au moins 3 sessions et que tu es à l’aise avec les bases de Python.

Installer VS Code

Télécharge VS Code via code.visualstudio.com. Choisis l’installeur pour ton système d’exploitation (Windows, macOS ou Linux) et suis les étapes d’installation.

Installer l’extension Python

VS Code fonctionne avec des extensions. Pour Python, tu as besoin de l’extension officielle de Microsoft :

  1. Ouvre VS Code.
  2. Clique sur l’onglet Extensions dans la barre latérale (ou appuie sur Ctrl+Shift+X).
  3. Cherche ms-python.python.
  4. Clique sur Install.

Après l’installation, VS Code reconnaît automatiquement les fichiers Python et tu obtiens l’autocomplétion, les messages d’erreur et plus encore.

Installer uv

uv est un gestionnaire de paquets Python rapide, bien plus simple à utiliser que le pip standard. Installe-le via astral.sh/uv.

Windows (PowerShell) :

powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"

macOS / Linux :

curl -LsSf https://astral.sh/uv/install.sh | sh

Redémarre ton terminal après l’installation pour que la commande uv soit disponible.

Installer le projet

Ouvre un terminal dans VS Code (`Ctrl+`` ou via Terminal → New Terminal) et exécute ces commandes dans ton dossier de projet :

# Utilise Python 3.13, 3.14 ou 3.15
uv init --python 3.14
uv add pgzero pygame-ce pygbag
Remarque

Utilise Python 3.13, 3.14 ou 3.15. On installe pygame-ce au lieu de pygame : c’est la version communautaire qui fonctionne aussi sur les Python les plus récents. Pgzero demande cependant encore l’ancien pygame.

Mets donc cette ligne dans ton pyproject.toml, pour que uv ignore cet ancien pygame :

[tool.uv]
exclude-dependencies = ["pygame"]

Ensuite, tu dois dire à VS Code quelle version de Python le projet utilise :

  1. Appuie sur Ctrl+Shift+P et tape Python: Select Interpreter.
  2. Choisis l’interpréteur qui se trouve dans ton dossier .venv (il ressemble à .venv/bin/python ou .venv\Scripts\python.exe).

VS Code utilise maintenant le bon environnement avec tous les packages que tu viens d’installer.

Lancer Pgzero

Ouvre un terminal dans VS Code et utilise :

uv run pgzrun main.py

Ou crée un launch.json dans le dossier .vscode/ pour pouvoir démarrer avec F5 :

{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Pgzero: run current file",
      "type": "debugpy",
      "request": "launch",
      "module": "pgzero",
      "args": ["${file}"],
      "console": "integratedTerminal"
    },
    {
      "name": "Pygame: run current file",
      "type": "debugpy",
      "request": "launch",
      "program": "${file}",
      "console": "integratedTerminal"
    }
  ]
}

Crée le dossier .vscode/ dans ton dossier de projet s’il n’existe pas encore, et enregistre le fichier sous launch.json. Tu vois ensuite les configurations dans le panneau Run and Debug (Ctrl+Shift+D).

Lancer Pygame

Pour les projets Pygame normaux (sans pgzrun), tu utilises :

uv run python main.py

Ou choisis dans le panneau Run and Debug la configuration “Pygame: run current file” si tu as créé le launch.json.

30 octobre 2026, 15:59

PyCharm (parcours avancé)

PyCharm est un IDE complet de JetBrains. Tu n’en as pas besoin pour te lancer avec Pgzero ou Pygame, mais si tu veux continuer à progresser comme programmeur, c’est un pas utile. Pense à un débogueur intégré, à la complétion de code intelligente et à de puissants outils de refactoring.

Quand changer ?

Continue simplement à travailler avec Thonny tant que ça te va bien. N’envisage PyCharm que si tu veux :

  • inspecter des variables pendant que ton code est en pause (débogueur),
  • renommer rapidement des fonctions ou des variables dans tout ton projet (refactoring), ou
  • une autocomplétion qui connaît aussi les types de tes variables.

Pour les débutants et la plupart des sessions de la dojo, Thonny est largement suffisant.

Installer PyCharm Community

Télécharge l’édition Community gratuite sur jetbrains.com/pycharm. Choisis Community, pas Professional. Professional est payant et tu n’en as pas besoin.

  1. Va sur la page de téléchargement et clique sur Community-Free.
  2. Lance le programme d’installation et garde tous les réglages par défaut.
  3. Démarre PyCharm. Tu ne dois pas créer de compte JetBrains.

Créer un nouveau projet et configurer l’interpréteur

Quand tu démarres PyCharm pour la première fois, tu choisis New Project.

PyCharm 2024.1 ou plus récent avec uv :

Si tu as déjà uv sur ton système (voir le guide Thonny), PyCharm le reconnaît automatiquement. Choisis dans Python version l’option 3.13, 3.14 ou 3.15 et laisse PyCharm créer un environnement uv.

Version plus ancienne ou sans uv avec venv :

  1. Choisis comme Interpreter type l’option Virtualenv.
  2. Sélectionne dans Base interpreter l’installation de Python sur ton système (le plus souvent python3 ou python3.x).
  3. Laisse la case Create a main.py welcome script cochée ou décoche-la. Ça n’a pas d’importance.

Clique ensuite sur Create. PyCharm crée l’environnement et ouvre le projet.

Installer des paquets

Tu installes pgzero, pygame-ce et pygbag via les réglages :

  1. Ouvre File → Settings (sur macOS : PyCharm → Preferences).
  2. Va dans Project: <nom> → Python Interpreter.
  3. Clique en bas à droite sur l’icône +.
  4. Cherche pgzero dans le champ de recherche et clique sur Install Package. Fais de même pour pygame-ce et pygbag.
  5. Ferme la fenêtre quand les trois sont terminés.

Vérifie que tout a réussi : à droite dans la liste, tu vois maintenant pgzero, pygame-ce et pygbag avec leurs numéros de version.

Remarque

Le bouton Install Package pour pgzero ne fonctionne pas sur Python 3.14 ou 3.15 ? C’est parce que pgzero entraîne l’ancien pygame. Utilise alors le terminal intégré avec uv add pgzero pygame-ce et mets [tool.uv] exclude-dependencies = ["pygame"] dans ton pyproject.toml. Voir aussi Installer Thonny + Pgzero.

Configuration d’exécution pour Pgzero

Pgzero fonctionne autrement qu’un script Python normal : tu le démarres comme un module et tu passes le nom de ton fichier comme argument.

  1. Clique en haut sur Add Configuration… (ou ouvre Run → Edit Configurations…).
  2. Clique sur l’icône + et choisis Python.
  3. Remplis :
    • Name : Pgzero
    • Run : mets le choix sur Module name (pas Script path)
    • Module name : pgzero
    • Parameters : main.py
    • Working directory : le dossier de ton projet (s’il est encore vide, clique sur l’icône de dossier et choisis ton dossier de projet)
  4. Clique sur OK.

Sélectionne ensuite la configuration Pgzero dans le menu déroulant en haut et appuie sur le bouton vert de lecture pour lancer ton jeu.

Configuration d’exécution pour Pygame

Pygame, tu le démarres bien comme un script normal :

  1. Ouvre à nouveau Run → Edit Configurations… et clique sur + → Python.
  2. Remplis :
    • Name : Pygame
    • Run : laisse le choix sur Script path
    • Script path : navigue jusqu’à main.py dans ton dossier de projet
    • Working directory : ton dossier de projet
  3. Clique sur OK.

Choisis la configuration Pygame dans le menu déroulant et appuie sur le bouton de lecture.


Voilà. Tu as maintenant deux configurations d’exécution prêtes à l’emploi : une pour les jeux Pgzero et une pour les jeux Pygame. Change simplement de configuration dans le menu déroulant en haut selon ce que tu es en train de construire.

Astuces utiles

  • Utiliser le débogueur : place un point d’arrêt en cliquant à gauche d’un numéro de ligne (point rouge). Démarre ensuite ta configuration avec le bouton bug au lieu du bouton de lecture. PyCharm met en pause à cette ligne pour que tu puisses regarder tes variables.
  • Import automatique : si PyCharm souligne en rouge un nom que tu viens d’écrire, appuie sur Alt+Enter pour ajouter automatiquement la bonne instruction import en haut.
  • Terminal : en bas, tu peux ouvrir un terminal intégré (View → Tool Windows → Terminal). Pratique pour uv add ou pour exécuter pygbag et publier.
30 octobre 2026, 15:59

Environnements virtuels (venv)

Imagine : tu pars en camp et tu dois préparer ton sac à dos. Pour un camp de sport, tu y mets d’autres choses que pour un camp de musique. Si tu mélanges tout, tu ne retrouves plus rien.

C’est pareil avec les projets Python. Chaque projet a besoin de son propre « sac à dos » : un environnement virtuel avec exactement ce qu’il faut dedans.

Qu’est-ce qu’un environnement virtuel ?

Un environnement virtuel (en abrégé venv, prononce : « ven-vee ») est un dossier séparé sur ton ordinateur qui contient Python et tous les paquets supplémentaires d’un seul projet.

Suppose que tu as deux projets :

  • Projet A utilise Pygame version 2.5
  • Projet B utilise Pygame version 2.6

Sans environnements virtuels, tu ne pourrais installer qu’une seule version de Pygame sur ton ordinateur. L’un des projets ne fonctionnerait alors plus. Avec des environnements virtuels, chaque projet a sa propre boîte fermée avec la bonne version dedans. Ils ne se gênent pas.

Métaphore : un environnement virtuel, c’est comme un sac à dos personnel par projet. Tu y mets exactement ce dont ce projet a besoin, et les sacs à dos sont rangés séparément dans l’armoire.

Pourquoi les utiliser ?

  1. Pas de conflit entre projets. Les versions 2.5 et 2.6 peuvent exister toutes les deux, chacune dans son propre environnement.
  2. Partager est facile. Si tu partages ton projet avec un ami (ou une amie), tu ne dois pas envoyer tous les paquets. Ton ami (ou amie) crée simplement son propre environnement virtuel et installe les mêmes paquets.
  3. Ton ordinateur reste rangé. Tu n’installes rien « comme ça » sur tout ton ordinateur. Tout reste bien dans le sac à dos du bon projet.

Comment créer un environnement virtuel avec uv

uv est le gestionnaire de paquets Python qu’on utilise à la CoderDojo. Il peut créer et gérer des environnements virtuels.

Étape 1 : ouvrir un terminal

  • Windows : appuie sur ⊞ Windows, tape cmd et ouvre “Invite de commandes” (ou utilise PowerShell).
  • macOS / Linux : ouvre “Terminal”.

Étape 2 : aller dans le dossier de ton projet

cd chemin/vers/ton/dossier-de-projet
Astuce

Remplace chemin/vers/ton/dossier-de-projet par le vrai chemin, par exemple cd Bureau/mon-jeu.

Étape 3 : créer l’environnement virtuel

uv venv

uv crée maintenant un petit dossier .venv dans ton dossier de projet. Il contient une installation Python séparée.

Tu veux utiliser une version précise de Python ? C’est possible aussi :

uv venv --python 3.14

Pourquoi faire ça ? Pour être sûr d’utiliser une version de Python qui fonctionne avec nos bibliothèques de jeux. Choisis 3.13, 3.14 ou 3.15.

Étape 4 : activer l’environnement virtuel

L’environnement existe, mais tu dois encore l’“allumer”. C’est ce qu’on appelle activer.

Windows (Invite de commandes ou PowerShell) :

.venv\Scripts\activate

macOS / Linux :

source .venv/bin/activate

Après l’activation, tu vois (.venv) apparaître à gauche dans ton terminal. C’est le signe que tu travailles maintenant dans ton environnement virtuel.

(.venv) seppe@computer:~/project$

Étape 5 : installer des paquets

Maintenant que ton environnement est actif, tu peux installer des paquets. Ils arrivent uniquement dans ce seul sac à dos :

uv add pgzero pygame-ce
Remarque

pygame-ce est la version communautaire de Pygame et fonctionne aussi sur Python 3.14 et 3.15. Pgzero demande cependant encore l’ancien pygame.

Mets donc aussi cette ligne dans ton pyproject.toml :

[tool.uv]
exclude-dependencies = ["pygame"]

Étape 6 : désactiver

Tu as fini de programmer ? Tape simplement :

deactivate

Le signe (.venv) disparaît et tu retravailles avec le Python normal de ton ordinateur.

À quoi faire attention ?

⚠️ N’oublie pas d’activer l’environnement

L’erreur la plus fréquente : tu ouvres un nouveau terminal et tu oublies d’activer l’environnement virtuel. Python se plaint alors de ne pas trouver les paquets, alors que tu les as bien installés.

Solution : active toujours d’abord avec .venv\Scripts\activate (Windows) ou source .venv/bin/activate (macOS/Linux) avant de lancer ton programme.

⚠️ Mets .venv dans .gitignore

Le dossier .venv est gros (parfois des centaines de Mo). Tu ne dois pas le partager via Git ou GitHub. Mets .venv dans ton fichier .gitignore, pour que Git l’ignore :

.venv/

Ton ami (ou amie) crée simplement son propre .venv avec uv venv et installe les mêmes paquets via le fichier pyproject.toml qui, lui, est bien dans Git.

⚠️ Utilise uv run comme raccourci

Pas envie d’activer et de désactiver à chaque fois ? uv a un raccourci pratique :

uv run python main.py

Il exécute python main.py à l’intérieur de l’environnement virtuel, même s’il n’est pas activé. uv comprend tout seul quel environnement va avec le projet.

⚠️ Terminaux différents, environnements différents

Si tu actives l’environnement dans un terminal, il n’est pas actif automatiquement dans un autre terminal. Tu dois activer séparément chaque terminal où tu veux utiliser l’environnement.

En résumé

ActionCommande (Windows)Commande (macOS/Linux)
Créeruv venvuv venv
Activer.venv\Scripts\activatesource .venv/bin/activate
Désactiverdeactivatedeactivate
Raccourciuv run python main.pyuv run python main.py

La règle d’or : tu vois (.venv) dans ton terminal ? Alors tout va bien. Tu ne le vois pas ? Active d’abord, programme ensuite.


Quelle est la différence avec virtualenv et pip ? Avant uv, il existait déjà d’autres outils comme virtualenv (pour les environnements) et pip (pour les paquets). Avec eux, tu pouvais faire la même chose, mais tu devais utiliser deux commandes séparées et ça marchait beaucoup plus lentement. uv fait tout en une fois, est bien plus rapide, et est bien plus simple pour les débutants. À la CoderDojo, on préfère donc uv.

Tu as des problèmes avec ton environnement virtuel ? Va voir Résolution de problèmes pour les erreurs fréquentes.

30 octobre 2026, 15:59

Résolution de problèmes

Ton code ne fonctionne pas et tu ne sais pas pourquoi ? Pas de panique : presque chaque problème a une solution simple. Parcours la liste ci-dessous et regarde si ton message d’erreur y figure.

Pgzero ou pygame ne peut pas être installé

Tu vois une erreur comme No matching distribution found ou Package not found quand tu installes pgzero ou pygame.

Cause : tu utilises une version de Python pour laquelle la bibliothèque n’a pas encore de version prête à l’emploi. Ça arrive avec Python 3.16 ou plus, et avec l’ancien pygame sur Python 3.14 et 3.15. Utilise Python 3.13, 3.14 ou 3.15 et la version communautaire pygame-ce au lieu de pygame.

Ubuntu 26.04 a Python 3.14 par défaut. Le script d’installation en un clic règle ça automatiquement :

  • Un Python 3.13, 3.14 ou 3.15 existant est utilisé ; s’il n’y en a pas, Python 3.14 est installé (via le PPA deadsnakes, ppa:deadsnakes/ppa, si apt n’a pas cette version)
  • Thonny est détecté via PATH, snap, pip ou flatpak
  • Si Thonny est installé en snap, la configuration est écrite dans le bon dossier (~/snap/thonny/current/.config/Thonny/)
  • Si apt install thonny ne marche pas, le script essaie pip install --user thonny

Solution : utilise Python 3.13, 3.14 ou 3.15 comme interpréteur actif :

  • Thonny : voir Installer Thonny + Pgzero → Vérifier la version de Python.
  • VS Code : recrée ton environnement avec uv venv --python 3.14.
  • PyCharm : crée un nouvel interpréteur et sélectionne Python 3.14 dans Base interpreter.

pgzrun: command not found

Ça veut dire que Pgzero n’est pas installé, ou que tu utilises une mauvaise version de Python.

Solution : ouvre Thonny, va dans Tools → Manage Packages, cherche pgzero et clique sur Install. Redémarre Thonny ensuite et réessaie.

ModuleNotFoundError: No module named 'pygame'

Python ne trouve pas la bibliothèque pygame. C’est presque toujours parce que Thonny utilise le mauvais interpréteur Python.

Solution : regarde en bas à droite dans la barre d’état de Thonny quel interpréteur est actif. Choisis le même interpréteur que celui utilisé pendant l’installation. Réinstalle ensuite pygame-ce via Tools → Manage Packages.

La fenêtre s’ouvre et se ferme tout de suite

La fenêtre du programme apparaît une seconde puis disparaît.

  • Pgzero : il te faut WIDTH et HEIGHT comme variables séparées en haut de ton fichier, en dehors de toute fonction. Sans ces variables, Pgzero ne sait pas quelle taille la fenêtre doit avoir et s’arrête tout de suite.
  • Pygame : il te faut une boucle d’événements qui appelle pygame.event.get() à chaque frame. Sans cet appel, la fenêtre se fige et le système d’exploitation la ferme.

Les sons ne font rien

Tu appelles sounds.jump.play() mais on n’entend rien.

Vérifie ceci :

  1. Y a-t-il un dossier sounds/ à côté de ton main.py ? Le dossier doit être exactement au même endroit.
  2. Les noms de fichiers sont-ils en minuscules et utilises-tu des underscores au lieu d’espaces ? Par exemple jump.wav, pas Jump.wav ni jump sound.wav.
  3. Pgzero n’accepte que des fichiers .wav dans le dossier sounds/. Pgzero les charge automatiquement, donc tu n’as rien à importer toi-même.

Le son ne marche pas dans pygame (session 5 et plus)

Tu utilises pygame.mixer.Sound(...) mais on n’entend rien, sans message d’erreur ; le jeu démarre simplement sans son.

Cause : Python cherche le fichier audio relativement au dossier depuis lequel tu démarres le script, pas au dossier où se trouve main.py. Si tu ouvres VS Code depuis la racine du projet et que ton script est dans un sous-dossier, Python cherche sounds/hit.wav dans la racine du projet et ne le trouve pas. Le try/except du starter attrape cette erreur en silence.

Solution : utilise __file__ pour rendre le chemin absolu :

import os
_DIR = os.path.dirname(os.path.abspath(__file__))
snd_hit = pygame.mixer.Sound(os.path.join(_DIR, 'sounds/hit.wav'))

__file__ est toujours le chemin vers main.py lui-même, peu importe d’où tu démarres le script. Les fichiers de départ à partir de la session 5 le font déjà. Ajoute les deux lignes juste au-dessus du chargement des sons si ton propre jeu ne le fait pas encore.

Les images ne s’affichent pas

Ton actor ou ton arrière-plan n’est pas visible.

Vérifie ceci :

  1. Y a-t-il un dossier images/ à côté de ton main.py ?
  2. Tous les noms de fichiers sont-ils en minuscules ? player.png fonctionne ; Player.png non.
  3. Utilise de préférence des fichiers .png, car ce sont eux qui marchent le plus sûrement avec Pgzero.

KeyError avec une image

Tu obtiens un KeyError quand tu crées un Actor ou charges une image.

Cause : le nom que tu passes doit correspondre exactement au nom du fichier, sans extension. Actor('basket') cherche images/basket.png. Une faute de frappe ou une majuscule en trop suffit à provoquer l’erreur.

Solution : vérifie le nom du fichier dans le dossier images/ et assure-toi qu’il correspond exactement à ce que tu as écrit dans le code.

Chromebook ou pas de droits d’installation

Tu ne peux pas installer Thonny ou Pgzero parce que tu n’as pas les droits d’administrateur sur l’ordinateur.

Solution : travaille avec quelqu’un qui a déjà Thonny, parce que le pair-programming est de toute façon une bonne idée ! À la maison, tu peux continuer avec la version pygbag : elle fait tourner ton projet Pygame directement dans le navigateur, sans installation.

L’antivirus bloque l’installation

Ta tentative d’installation est interrompue ou bloquée par un antivirus.

Solution : désactive temporairement l’antivirus pendant l’installation, ou demande à un coach de mettre une version portable de Thonny sur une clé USB. Cette version n’a pas besoin d’installation et fonctionne directement depuis la clé.


Toujours bloqué ?

Pas de problème. Demande simplement à un coach pendant la session, ou poste ta question dans le chat CoderDojo. Donne le message d’erreur exact (copie et colle le texte de Thonny), on pourra t’aider plus vite.

30 octobre 2026, 15:59

Sessions

Choisis une série ci-dessous. Les sessions Python construisent des jeux avec Pygame. Les sessions Git t’apprennent la gestion de versions : de ton premier commit aux pull requests.

30 octobre 2026, 15:59

Sous-sections de Sessions

Sessions Python

Dix sessions dans lesquelles tu construis chaque mois un jeu Pygame complet. Chaque session contient une fiche de travail, un cheatsheet et du code de départ à télécharger.

  • Session 1 : Catch the Stars : Une étoile tombe, tu l’attrapes. Tu écris ta première boucle draw()/update() et tu déplaces un sprite avec les flèches.
  • Session 2 : Dodge Meteors : Des météores apparaissent et tombent. Tu les gardes dans une liste, tu les supprimes quand ils sortent de l’écran et tu retires une vie à chaque collision.
  • Session 3 : Space Blaster : Les ennemis descendent, tu les abats. Tu crées des projectiles avec la touche ESPACE et tu détectes les collisions avec une boucle sur une liste.
  • Session 4 : Pong : Deux raquettes, une balle. Tu apprends pygame.Rect, tu fais rebondir la balle en inversant sa vitesse et tu tiens le score pour deux joueurs.
  • Session 5 : Breakout : Casser des briques avec une balle qui rebondit. Tu ajoutes des effets sonores avec pygame.mixer et tu construis un écran de victoire et de défaite.
  • Session 6 : Platformer : Sauter et tomber sur des plateformes. Tu simules la gravité avec une variable vel_y et tu détectes les collisions avec les plateformes grâce à pygame.Rect.
  • Session 7 : Bug Zapper : Des bugs rampent, tu les abats. Tu écris ta première classe avec __init__ et tu crées une sous-classe par héritage.
  • Session 8 : Sky Highway : Un vaisseau volant sur une route qui défile. Tu fais apparaître des obstacles par la droite et tu augmentes la vitesse à mesure que le score monte.
  • Session 9 : Boss Battle : Un boss avec une barre de HP et des phases d’attaque. Tu construis une machine à états qui adapte le tir et les déplacements à chaque phase.
  • Session 10 : Mon jeu : Pas de consigne fixe. Tu choisis le genre et tu combines tout ce que tu as appris en neuf sessions dans ton propre jeu.
30 octobre 2026, 15:59

Sous-sections de Sessions Python

Session 1 : Catch the Stars

Dans cette session, tu construis un mini-jeu : une étoile tombe et toi, tu l’attrapes avec un panier. À la fin de la session, tout bouge, le jeu compte combien d’étoiles tu attrapes et tu as ton premier jeu à toi.

Ce que tu vas apprendre aujourd’hui

  • Utiliser des variables pour placer des objets
  • La fonction draw() : ce que tu dessines à chaque frame
  • La fonction update() : ce qui change à chaque frame
  • Les entrées clavier : bouger avec les flèches

Étape 0 : Installation

  1. Ouvre Thonny.
  2. Télécharge le starter via ce lien, décompresse le ZIP et ouvre main.py dans Thonny.
  3. Clique sur le bouton vert Run. Tu vois une fenêtre bleu foncé avec un panier en bas et une étoile en haut, mais rien ne bouge encore.
  4. Des problèmes ? Va voir Installer Thonny.

Étape 1 : Laisse tomber l’étoile

La fonction update() tourne 60 fois par seconde. Tout ce que tu y mets est donc exécuté 60 fois par seconde. C’est comme ça que le mouvement fonctionne dans un jeu.

Pour l’instant, il n’y a que pass dans update(). Ça veut dire « ne fais rien ». Supprime pass et ajoute ceci :

def update():
    star.y = star.y + 3

Clique sur Run. L’étoile tombe maintenant du haut vers le bas. Quand elle sort de l’écran, elle disparaît. On va régler ça.

Que se passe-t-il ici ? star.y est la position verticale de l’étoile. Plus y est grand, plus l’étoile est bas sur l’écran. En ajoutant + 3 à chaque frame, l’étoile descend petit à petit.

Le système de coordonnées : (0, 0) se trouve en haut à gauche, pas en bas à gauche comme en maths. x va vers la droite, y va vers le bas. L’étoile commence à y = 30 (presque tout en haut), le panier est à y = 370 (presque tout en bas).

Système de coordonnées Pygame Zero : origine en haut à gauche, y va vers le bas

Bouge ta souris sur l’écran ci-dessous pour voir les coordonnées :

Bouge ta souris sur l'écran pour voir les coordonnées.

Tu veux en savoir plus sur le fonctionnement de l’écran ? → Les coordonnées expliquées

Bouge les curseurs et regarde comment actor.x et actor.y changent quand l’actor se déplace :

Étape 2 : ✅ Basic : fais bouger le panier

C’est le moment de piloter le panier. Pygame Zero a une variable pratique, keyboard, qui garde la trace des touches pressées.

Ajoute ceci dans update(), après la ligne de l’étoile :

def update():
    star.y = star.y + 3

    if keyboard.left:
        basket.x = basket.x - 5
    if keyboard.right:
        basket.x = basket.x + 5

Clique sur Run et utilise les flèches. Le panier bouge avec toi !

Astuce (facultatif, compte comme Stretch) : Si tu pousses le panier trop à gauche ou trop à droite, il disparaît de l’écran. Tu peux ajouter un test qui évite ça ? Indice : utilise WIDTH et compare avec basket.x.

Étape 3 : ⭐ Stretch : attrape l’étoile

Maintenant, tu veux que quelque chose se passe quand le panier touche l’étoile. Pour ça, tu utilises colliderect. Il vérifie si deux rectangles se chevauchent.

Ajoute ceci dans update() :

    if star.colliderect(basket):
        star.y = 0

L’étoile remonte quand tu l’attrapes. Mais et si tu la rates ? Ajoute aussi ceci :

    if star.y > HEIGHT:
        star.y = 0

Bonus : Fais réapparaître l’étoile à un endroit au hasard chaque fois. Ajoute en haut du fichier :

import random

Remplace ensuite star.y = 0 (aux deux endroits) par :

        star.x = random.randint(20, WIDTH - 20)
        star.y = 0

Maintenant, l’étoile tombe chaque fois à un autre endroit. Bien plus difficile à attraper !

Étape 4 : 🔥 Expert : ajoute un score

Un vrai jeu garde la trace de ton score. Pour ça, tu as besoin d’une variable qui vit en dehors des fonctions : une variable globale.

Comment fonctionne une variable : une petite boîte avec un nom et une valeur

Clique sur le bouton ci-dessous pour voir comment score change chaque fois que tu attrapes une étoile :

Ajoute ceci tout en haut, en dehors de toutes les fonctions (après les lignes de basket et star) :

score = 0

Dans draw(), ajoute :

    screen.draw.text(f"Score: {score}", topleft=(10, 10), color="white")

Dans update(), adapte le code de l’attrape pour que le score monte :

    if star.colliderect(basket):
        global score
        score = score + 1
        star.x = random.randint(20, WIDTH - 20)
        star.y = 0

global score dit à Python : « je parle du score d’en dehors de cette fonction, pas d’une nouvelle variable locale. » Sans cette ligne, tu obtiens une erreur.

Clique sur Run. Le score est en haut à gauche et augmente chaque fois que tu attrapes une étoile !

Showcase

Montre ton jeu à un coach et à un buddy. Raconte ce que tu as fait : ce qui marche et ce que tu as ajouté en plus.

À la prochaine !

« La prochaine fois : des trucs qui RÉPLIQUENT. Et ça fait BOUM, avec un vrai son. »

À emporter chez toi

Essaie une de ces extensions à la maison. Chacune a un indice de code pour te lancer.

  1. Limite les vies — Ajoute levens = 3. En cas de raté (star.y > HEIGHT) : levens -= 1. Arrête le jeu quand levens == 0 avec game_over = True et affiche « Game Over » dans draw().

  2. Couleur d’étoile aléatoire — À chaque attrape : donne une nouvelle couleur à l’étoile avec random.randint(50, 255) pour le rouge, le vert et le bleu. Commence à 50, pas à 0 — sinon l’étoile est parfois noire et invisible.

  3. Arrière-plan — Dessine des étoiles fixes en arrière-plan dans draw(), avant le score. Utilise screen.draw.filled_circle(x, y, 2, "white") à 20 positions au hasard. Fais random.seed(42) pour qu’elles ne clignotent pas.

  4. Deuxième étoile — Fais sterren = [star, Actor("star")]. Donne à chaque étoile son propre x. Mets-les à jour toutes les deux dans update() et dessine-les dans draw().

  5. Meilleur score — Garde high_score. Si score > high_score : high_score = score. Affiche f"Meilleur : {high_score}" à côté du score.

  6. Panier plus petit — Tous les 5 points : basket.width = max(30, basket.width - 5). Remets basket.width à sa valeur au redémarrage.

  7. Bombe — Ajoute un cercle rouge qui tombe de temps en temps. Utilise un timer bom_timer et random.randint pour décider quand il apparaît. Si le panier touche la bombe : score -= 2.

  8. Niveau de difficulté — Tous les 5 étoiles : augmente la vitesse de chute de 1. Prévois un maximum : max(3, star_snelheid).

Bloqué ? Demande au dojo suivant à un coach, ou essaie simplement autre chose. Programmer, c’est faire.

Regarde le cheatsheet de cette session

30 octobre 2026, 15:59

Session 2 : Dodge Meteors

Ton vaisseau flotte dans l’espace sombre pendant que des météores arrivent du haut vers le bas. Évite-les, ou perds une vie. Plus tu survis longtemps, plus ils vont vite. Et cette fois, tu construis aussi Dojo Defender : le plus grand projet qui grandit à chaque session.

Ce que tu vas apprendre aujourd’hui

  • Utiliser des listes pour garder plusieurs objets
  • Spawner des objets (les créer) et les supprimer
  • Tenir les vies à jour et afficher un écran de game over
  • Dojo Defender : ajouter ton propre vaisseau au plus grand projet

Étape 0 : Installation

  1. Ouvre Thonny.
  2. Télécharge le starter via ce lien, décompresse le ZIP et ouvre main.py.
  3. Clique sur Run. Tu vois ton vaisseau en bas, mais aucun météore ne tombe encore.
  4. Des problèmes ? Va voir Installer Thonny.

Étape 1 : Fais apparaître des météores

Complète la fonction spawn_meteor(). Un météore est un Actor qui commence en haut de l’écran à une position x au hasard :

import random

def spawn_meteor():
    rock = Actor('meteor')
    rock.x = 0
    rock.y = random.randint(30, WIDTH - 30)
    meteors.append(rock)

Appelle la fonction dans update(), mais pas à chaque frame, sinon l’écran se remplit d’un coup. La fonction update() tourne 60 fois par seconde. Utilise ça pour tenir un compteur :

Regarde ci-dessous à quelle vitesse un météore se déplace selon la vitesse, et combien de pixels ça fait par seconde :

Utilise un compteur :

# en haut, en dehors des fonctions :
timer = 0

def update():
    global timer
    timer += 1
    if timer % 60 == 0:   # chaque seconde (60 frames)
        spawn_meteor()

Clique sur Run. Après une seconde, le premier météore apparaît, mais il ne bouge pas encore.

Étape 2 : ✅ Basic : faire tomber les météores et les faire disparaître

Fais descendre tous les météores de la liste, et supprime-les quand ils sortent de l’écran :

def update():
    global timer
    timer += 1
    if timer % 60 == 0:
        spawn_meteor()

    for rock in meteors[:]:      # [:] = une copie pour pouvoir supprimer sans risque
        rock.y += 4
        if rock.y > HEIGHT + 30:
            meteors.remove(rock)

Détecter une collision : Si un météore touche le vaisseau, tu perds une vie. Ajoute ceci dans la boucle :

        if rock.colliderect(ship):
            meteors.remove(rock)
            global lives
            lives -= 1
            if lives <= 0:
                # TODO : game over (étape 3)
                pass

Étape 3 : ⭐ Stretch : game over et vitesse qui augmente

Game over : Ajoute une variable game_over = False en haut. Si lives == 0, mets game_over = True. Dans draw(), affiche un texte quand game_over vaut True :

    if game_over:
        screen.draw.text(
            "GAME OVER",
            center=(WIDTH / 2, HEIGHT / 2),
            color="red",
            fontsize=60,
        )

Arrête le mouvement dans update() quand game_over vaut True :

def update():
    if game_over:
        return
    ...

Augmenter la vitesse : Fais aller les météores plus vite à mesure que le score monte :

snelheid = 3 + score // 5   # tous les 5 points, +1 de vitesse
rock.y += snelheid

Étape 4 : 🔥 Expert : score et plusieurs tailles de météores

Score : Chaque seconde que tu survis, +1 point. Ajoute global score et augmente dans update() :

    if timer % 60 == 0:
        global score
        score += 1
        spawn_meteor()

Plusieurs tailles : Fais des petits, des moyens et des grands météores. Utilise une variable schaal et adapte la hitbox :

def spawn_meteor():
    rock = Actor('meteor')
    rock.x = random.randint(30, WIDTH - 30)
    rock.y = 0
    rock.schaal = random.choice([0.5, 1.0, 1.5])
    meteors.append(rock)

Les petits météores vont plus vite ; les grands sont plus difficiles à éviter mais rapportent plus de points.

Dojo Defender

Télécharge le starter Dojo Defender d’aujourd’hui. C’est la base du projet qui grandit à chaque session. Ajoute aujourd’hui ton vaisseau et fais-le bouger avec les flèches.

Tu n’étais pas là la dernière fois ? Pas de problème — télécharge la solution de la dernière fois et tu peux suivre tout de suite.

La fiche de travail complète de Dojo Defender se trouve sur la page Dojo Defender.

Showcase

Montre ton jeu à un coach et à un buddy. Combien de temps tu survis ? Qui fait le meilleur score ?

À la prochaine !

« La prochaine fois : ton propre vaisseau RÉPLIQUE. Des ennemis en formation, et c’est toi qui les exploses. »

À emporter chez toi

  1. Facile : change la couleur d’arrière-plan en violet foncé ou vert foncé.
  2. Moyen : ajoute un son quand un météore touche le vaisseau (sounds/hit.wav).
  3. Difficile : fais aller les météores plus vite à mesure qu’il y en a plus à l’écran (pas seulement le score).
  4. Très difficile : ajoute des power-ups : une étoile dorée qui te donne une vie de plus quand tu la touches.

Regarde le cheatsheet de cette session

30 octobre 2026, 15:59

Session 3 : Space Blaster

Les ennemis sont en formation en haut de l’écran. Toi, tu es en bas avec un vaisseau et un seul objectif : les éliminer tous avant qu’ils atteignent le fond. Appuie sur ESPACE pour tirer, et ne rate pas.

Ce que tu vas apprendre aujourd’hui

  • Garder les projectiles dans une liste
  • Créer un projectile quand tu appuies sur ESPACE
  • La collision entre les projectiles et les ennemis
  • Game over quand un ennemi atteint le fond

Étape 0 : Installation

  1. Ouvre Thonny.
  2. Télécharge le starter via ce lien, décompresse le ZIP et ouvre main.py.
  3. Clique sur Run. Tu vois le vaisseau en bas et 12 ennemis dans une grille, mais rien ne bouge et tu ne sais pas encore tirer.

Étape 1 : Fais bouger le vaisseau

Le vaisseau bouge déjà avec les flèches. Vérifie le code dans update(). Fais en sorte que le vaisseau ne sorte pas de l’écran :

if keyboard.left and ship.x > 30:
    ship.x -= 5
if keyboard.right and ship.x < WIDTH - 30:
    ship.x += 5

Étape 2 : ✅ Basic : tirer avec ESPACE

Complète la fonction shoot(). Un projectile est un Actor qui commence à la position du vaisseau :

def shoot():
    kogel = Actor('bullet')
    kogel.x = ship.x
    kogel.y = ship.y - 20
    bullets.append(kogel)

Appelle shoot() quand la barre d’espace est pressée. Utilise on_key_down (style Pgzero) :

def on_key_down(key):
    if key == keys.SPACE:
        shoot()

Fais monter les projectiles dans update() et supprime-les quand ils sortent de l’écran :

for kogel in bullets[:]:
    kogel.y -= 8
    if kogel.y < -10:
        bullets.remove(kogel)

Étape 3 : ⭐ Stretch : toucher les ennemis

colliderect vérifie si la hitbox rectangulaire de deux actors se chevauche. Bouge ta souris sur l’écran ci-dessous pour voir quand ça arrive :

Vérifie dans update() si un projectile touche un ennemi :

for kogel in bullets[:]:
    kogel.y -= 8
    if kogel.y < -10:
        bullets.remove(kogel)
        continue
    for vijand in enemies[:]:
        if kogel.colliderect(vijand):
            bullets.remove(kogel)
            enemies.remove(vijand)
            global score
            score += 10
            break

Condition de victoire : Si enemies est vide, tu as gagné :

    if not enemies:
        screen.draw.text("TU GAGNES !", center=(WIDTH/2, HEIGHT/2), color="yellow", fontsize=60)

Étape 4 : 🔥 Expert : faire bouger les ennemis et game over

Fais descendre les ennemis lentement. Utilise un timer :

vijand_timer = 0

def update():
    global vijand_timer
    vijand_timer += 1
    if vijand_timer % 90 == 0:   # toutes les 1,5 seconde
        for vijand in enemies:
            vijand.y += 20

Game over quand un ennemi atteint le fond :

        for vijand in enemies:
            if vijand.y > HEIGHT - 30:
                global game_over
                game_over = True

Tirer plus vite : Prévois un cooldown pour que le ninja ne puisse pas tirer à l’infini :

shoot_cooldown = 0

def update():
    global shoot_cooldown
    if shoot_cooldown > 0:
        shoot_cooldown -= 1

def on_key_down(key):
    global shoot_cooldown
    if key == keys.SPACE and shoot_cooldown == 0:
        shoot()
        shoot_cooldown = 15

Showcase

Montre ton jeu à un coach. En combien de temps tu élimines tous les ennemis ? Compare ton score avec un buddy.

À la prochaine !

« La prochaine fois : deux joueurs, une balle : PONG. Et tu apprends le vrai pygame, sans pgzrun. »

À emporter chez toi

  1. Facile : change la couleur des projectiles ou des ennemis.
  2. Moyen : fais bouger les ennemis à gauche et à droite (une seule direction par pas, demi-tour au bord).
  3. Difficile : ajoute une second wave : quand tous les ennemis sont partis, fais apparaître une nouvelle rangée qui descend plus vite.
  4. Très difficile : fais aussi tirer les ennemis : envoie un projectile vers le bas au hasard toutes les N frames.

Regarde le cheatsheet de cette session

Dojo Defender

Télécharge le starter Dojo Defender d’aujourd’hui.

Tu n’étais pas là la dernière fois ? Télécharge la solution de la session 1 et commence avec ça.

La fiche de travail complète : Dojo Defender Session 2.

30 octobre 2026, 15:59

Session 4 : Pong

Deux raquettes, une balle : le Pong classique. Mais il y a une surprise : dans cette session, tu écris le jeu en vrai pygame, sans pgzrun. Tu apprends à installer toi-même la game loop. C’est comme ça que marchent la plupart des vrais jeux.

Ce que tu vas apprendre aujourd’hui

  • La game loop pygame : events, update, draw
  • pygame.Rect pour les rectangles et les collisions
  • Faire rebondir la balle (inverser la vitesse)
  • Compter les points pour deux joueurs

Étape 0 : Installation

  1. Ouvre Thonny.
  2. Télécharge le starter via ce lien, décompresse le ZIP et ouvre main.py.
  3. Clique sur Run. Tu vois deux raquettes et une balle jaune au milieu, mais la balle ne bouge pas encore.

Différence avec pgzrun : il n’y a plus de fonctions draw() et update(). Tout est dans une seule boucle while running:.

Étape 1 : Fais bouger la balle

Cherche les lignes :

# bal.x += ball_dx  # active ceci quand tu as fini
# ball.y += ball_dy

Supprime le # devant les deux lignes. Mais règle d’abord une vitesse de départ. Cherche ball_dx, ball_dy = 0, 0 et remplace par :

ball_dx, ball_dy = 4, 4

Clique sur Run. La balle bouge maintenant, mais elle disparaît par le bord. On règle ça à l’étape 2.

Étape 2 : ✅ Basic : la balle rebondit sur les murs et les raquettes

Ajoute ceci après ball.x += ball_dx et ball.y += ball_dy :

# Rebondir sur le bord supérieur et inférieur
if ball.top <= 0 or ball.bottom >= HEIGHT:
    ball_dy = -ball_dy

# Rebondir sur les raquettes
if ball.colliderect(left_paddle) or ball.colliderect(right_paddle):
    ball_dx = -ball_dx

La balle rebondit maintenant à l’infini. Ajoute aussi des limites pour les raquettes pour qu’elles ne sortent pas de l’écran. Regarde le code qui est déjà dans le starter.

Étape 3 : ⭐ Stretch : compter les points

Si la balle sort à gauche, le joueur de droite marque. Si elle sort à droite, c’est celui de gauche :

# Balle sortie à gauche → la droite marque
if ball.left <= 0:
    score_right += 1
    ball.center = (WIDTH // 2, HEIGHT // 2)
    ball_dx = 4

# Balle sortie à droite → la gauche marque
if ball.right >= WIDTH:
    score_left += 1
    ball.center = (WIDTH // 2, HEIGHT // 2)
    ball_dx = -4

Le score s’affiche déjà dans draw(). Vérifie que les variables sont correctes.

Étape 4 : 🔥 Expert : condition de victoire et vitesse qui augmente

Gagner à 5 points : ajoute une variable won. Quand un joueur atteint 5, arrête le jeu :

if score_left >= 5:
    won = "La gauche gagne !"
if score_right >= 5:
    won = "La droite gagne !"

Affiche le gagnant à l’écran et arrête le mouvement.

Vitesse qui augmente : après chaque échange, la balle devient un peu plus rapide :

if ball.colliderect(left_paddle) or ball.colliderect(right_paddle):
    ball_dx = -ball_dx * 1.05   # 5 % plus rapide
    ball_dy = ball_dy * 1.05

Prévois un maximum : ball_dx = max(-12, min(12, ball_dx)).

Showcase

Joue une partie contre un buddy. Le premier à 5 points gagne. Montre-le à un coach.

À la prochaine !

« La prochaine fois : Breakout. La balle casse des briques. Et il y a du SON. »

À emporter chez toi

  1. Facile : change la couleur de la balle ou des raquettes.
  2. Moyen : agrandis une raquette au fur et à mesure que ce joueur perd (handicap).
  3. Difficile : ajoute un adversaire IA : la raquette de droite suit automatiquement la balle.
  4. Très difficile : ajoute des power-ups : un item qui double la balle ou agrandit la raquette.

Dojo Defender

Aujourd’hui, Dojo Defender passe au vrai Pygame ! Télécharge le starter. Tu n’étais pas là ? Télécharge la solution de la session 2. Fiche de travail : Dojo Defender Session 3.


Regarde le cheatsheet de cette session

30 octobre 2026, 15:59

Session 5 : Breakout

Une balle rebondit dans tous les sens et casse des rangées de briques colorées. Tu contrôles la raquette pour garder la balle en l’air. Et cette fois, tu l’entends aussi : il y a des effets sonores à chaque collision.

Ce que tu vas apprendre aujourd’hui

  • Charger et jouer un son avec pygame.mixer
  • Les collisions avec plusieurs objets (une liste de briques)
  • Faire rebondir la balle dans la bonne direction
  • Construire un écran de victoire et de défaite

Étape 0 : Installation

  1. Ouvre Thonny.
  2. Télécharge le starter via ce lien, décompresse le ZIP et ouvre main.py.
  3. Clique sur Run. Tu vois la raquette, la balle et les briques. La balle bouge déjà à l’horizontale mais pas à la verticale. C’est à toi de changer ça.

Étape 1 : Fais bouger la balle à la verticale

Cherche cette ligne dans le starter :

ball_dx, ball_dy = 4, 0
# ball_dy = -4  ← supprime le # pour faire bouger la balle !

Supprime le # devant ball_dy = -4. La balle a maintenant une vitesse verticale. Ajoute le mouvement dans la game loop (cherche la section update) :

ball.x += ball_dx
ball.y += ball_dy

Clique sur Run. La balle bouge en diagonale mais disparaît par les bords.

Étape 2 : ✅ Basic : la balle rebondit sur les murs et la raquette

Ajoute les rebonds :

# Bord supérieur, gauche et droit
if ball.left <= 0 or ball.right >= WIDTH:
    ball_dx = -ball_dx
if ball.top <= 0:
    ball_dy = -ball_dy

# Raquette
if ball.colliderect(paddle):
    ball_dy = -ball_dy
    if snd_hit:
        snd_hit.play()

Vies : si la balle atteint le bas, tu perds une vie :

if ball.top > HEIGHT:
    levens -= 1
    # Remets la balle au-dessus de la raquette
    ball.center = (paddle.centerx, paddle.top - BALL_SIZE)
    ball_dy = -4

Étape 3 : ⭐ Stretch : casser des briques

Vérifie la collision avec chaque brique dans la boucle :

for steen in stenen[:]:
    if ball.colliderect(steen['rect']):
        stenen.remove(steen)
        ball_dy = -ball_dy
        score += 10
        if snd_hit:
            snd_hit.play()
        break  # casser une seule brique par frame

Condition de victoire : si toutes les briques sont parties, le ninja a gagné. Affiche un message :

if not stenen:
    # affiche l'écran de victoire

Étape 4 : 🔥 Expert : vies, son d’explosion et vitesse

Son d’explosion quand une brique casse (utilise snd_explode du starter) :

if snd_explode:
    snd_explode.play()

Game over à 0 vie : affiche un écran et arrête la balle.

Vitesse qui augmente à mesure qu’il reste moins de briques :

snelheid_factor = 1 + (1 - len(stenen) / totaal_stenen) * 0.5
ball_dx_huidig = ball_dx * snelheid_factor

Une nouvelle rangée de briques quand tout est parti : rappelle stenen = maak_stenen() et augmente la difficulté.

Showcase

Qui enlève le plus de briques ? Compare les scores et montre à ton coach ta plus longue série.

À la prochaine !

« La prochaine fois : la gravité. Ton personnage tombe, et c’est à toi de le faire sauter de plateforme en plateforme. »

À emporter chez toi

  1. Facile : change les couleurs des briques pour tes couleurs préférées.
  2. Moyen : rends certaines briques deux fois plus solides (il faut les toucher deux fois).
  3. Difficile : ajoute un power-up qui élargit la raquette pendant un temps.
  4. Très difficile : ajoute une deuxième balle qui apparaît quand score > 50.

Regarde le cheatsheet de cette session

Dojo Defender

Dojo Defender reçoit un menu et de nouveaux types d’ennemis ! Télécharge le starter. Tu n’étais pas là ? Télécharge la solution de la session 3. Fiche de travail : Dojo Defender Session 4.

30 octobre 2026, 15:59

Session 6 : Platformer

Dans cette session, tu construis un micro-platformer. Ton personnage a de la gravité, peut sauter et ramasse des étoiles sur les plateformes. Pour la première fois, tu utilises pygame directement, sans pgzrun, et tu ajoutes des effets sonores avec pygame.mixer.

Ce que tu vas apprendre aujourd’hui

  • Simuler la gravité avec une variable vel_y
  • Sauter en rendant vel_y négatif
  • Détecter les collisions avec les plateformes grâce à pygame.Rect
  • Ramasser des items (collision avec les étoiles)
  • Jouer des sons avec pygame.mixer

Étape 0 : Installation

  1. Ouvre Thonny.
  2. Télécharge le starter via ce lien, décompresse le ZIP et ouvre main.py dans Thonny.
  3. Clique sur le bouton vert Run. Tu vois une fenêtre avec un personnage, des plateformes et des étoiles, mais le personnage ne tombe pas encore.
  4. Des problèmes ? Demande à un coach.

Étape 1 : La gravité

Dans un platformer, le personnage tombe en continu vers le bas, sauf s’il se trouve sur une plateforme. On simule ça avec vel_y : une vitesse verticale qui augmente à chaque frame à cause de la gravité.

Cherche le commentaire # STAP 1 dans main.py et remplace le pass par :

# Appliquer la gravité
vel_y += GRAVITY
player_rect.y += vel_y

# Vérifie si le personnage est sur une plateforme
on_ground = False
for platform in platforms:
    if (player_rect.colliderect(platform) and vel_y > 0):
        player_rect.bottom = platform.top
        vel_y = 0
        on_ground = True

GRAVITY = 0.5 est déjà en haut du fichier. Clique sur Run. Le personnage tombe maintenant sur la plateforme la plus proche et y reste.

Que se passe-t-il ici ? À chaque frame, vel_y augmente un peu (le personnage accélère vers le bas). Si le personnage touche une plateforme en tombant (vel_y > 0), tu places son bas (bottom) pile sur le haut de la plateforme et tu arrêtes la chute (vel_y = 0).

Étape 2 : ✅ Basic : sauter

Un platformer sans saut, c’est à moitié fini. Appuie sur ESPACE pour sauter : ce n’est rien d’autre que rendre vel_y soudainement négatif.

Cherche le commentaire # STAP 2 et ajoute :

keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
    player_rect.x -= SPEED
if keys[pygame.K_RIGHT]:
    player_rect.x += SPEED

# Sauter — seulement si tu es au sol
if keys[pygame.K_SPACE] and on_ground:
    vel_y = -12

Clique sur Run et teste :

  • Flèches : bouge à gauche/droite
  • ESPACE : saute

Astuce : si le saut te semble trop haut ou trop bas, remplace -12 par -10 (saut plus bas) ou -15 (saut plus haut).

Étape 3 : ⭐ Stretch : ramasser les étoiles

Ajoutons quelque chose à ramasser. Le starter a déjà une liste stars avec des objets pygame.Rect. C’est toi qui écris la détection de collision.

Cherche le commentaire # STAP 3 :

for star in stars[:]:  # [:] pour pouvoir supprimer sans risque pendant la boucle
    if player_rect.colliderect(star):
        stars.remove(star)
        score += 1

Et dans la fonction de dessin (cherche # TEKEN STERREN) :

for star in stars:
    pygame.draw.polygon(screen, YELLOW, star_points(star.centerx, star.centery, 12, 5))

star_points() est déjà défini dans le starter. Il calcule les points d’une étoile à 5 branches.

En haut du jeu, il y a score = 0. Dessine le score à l’écran (cherche # TEKEN SCORE) :

score_surf = font.render(f"Étoiles : {score}", True, WHITE)
screen.blit(score_surf, (10, 10))

Étape 4 : 🔥 Expert : son et écran de victoire

Maintenant, tu ajoutes un son de saut et un écran de victoire quand toutes les étoiles sont ramassées.

Charger le son (c’est déjà prêt dans le starter ; vérifie que jump.wav se trouve dans le dossier sounds/) :

pygame.mixer.init()
jump_snd = pygame.mixer.Sound("sounds/jump.wav")

Jouer le son au saut : ajoute ceci au code du saut :

if keys[pygame.K_SPACE] and on_ground:
    vel_y = -12
    jump_snd.play()

Écran de victoire : ajoute ceci après la boucle des étoiles :

if len(stars) == 0:
    win_surf = font.render("Gagné ! Toutes les étoiles ramassées !", True, YELLOW)
    screen.blit(win_surf, (WIDTH // 2 - win_surf.get_width() // 2, HEIGHT // 2))
    pygame.display.flip()
    pygame.time.wait(3000)
    running = False

Showcase

Montre ton jeu à un coach et à un buddy. Tu arrives à ramasser toutes les étoiles avant la fin du temps ?

Dojo Defender

Le snapshot Dojo Defender d’aujourd’hui continue sur la session 5 :

  • Fond étoilé en parallaxe — trois couches d’étoiles avec leur propre vitesse
  • Particle effects — gaz d’échappement, débris d’explosion, étincelles
  • Astéroïdes destructibles — big → med → small → disparu

Télécharge le starter Dojo Defender ou la solution.

À la prochaine !

« La prochaine fois : clique sur les bugs et ZAPPE-les, avec tes propres classes. »

À emporter chez toi

Essaie une de ces extensions à la maison :

  1. Facile : change la couleur du personnage quand il est en l’air.
  2. Moyen : ajoute un timer. Le personnage a 30 secondes pour ramasser toutes les étoiles.
  3. Difficile : ajoute un ennemi qui marche d’un bout à l’autre d’une plateforme ; si le personnage le touche, le jeu redémarre.
  4. Très difficile : fais faire un double saut au personnage (deux fois ESPACE pour un deuxième saut en l’air).

Bloqué ? Demande au dojo suivant à un coach, ou essaie simplement autre chose. Programmer, c’est faire.

Regarde le cheatsheet de cette session

30 octobre 2026, 15:59

Session 7 : Bug Zapper

Les bugs tombent du haut vers le bas. Toi, tu tires vers le haut pour les toucher. Dans cette session, tu apprends la POO : tu écris ta première classe à toi (Bug), puis deux sous-classes : une qui oscille et une qui plonge sur toi. Les classes sont les briques de presque tous les gros programmes.

Ce que tu vas apprendre aujourd’hui

  • Écrire une classe avec __init__ et tes propres méthodes
  • L’héritage : une sous-classe qui étend une classe existante
  • Garder les projectiles dans une liste
  • La détection de collision entre les projectiles et les bugs

Étape 0 : Installation

  1. Ouvre Thonny.
  2. Télécharge le starter via ce lien, décompresse le ZIP et ouvre main.py dans Thonny.
  3. Clique sur Run. Tu vois un écran avec un joueur en bas, mais pas encore de bugs et pas de projectiles.
  4. Des problèmes ? Demande à un coach.

Étape 1 : Faire apparaître des bugs et tirer

La classe Bug

Cherche le commentaire # ÉTAPE 1 — CLASSE BUG et écris :

class Bug:
    def __init__(self, x, y):
        self.x = x
        self.y = y
        self.alive = True

    def update(self):
        self.y += 2  # tombe vers le bas

    def draw(self, screen):
        pygame.draw.circle(screen, GREEN, (int(self.x), int(self.y)), 15)
        # Yeux
        pygame.draw.circle(screen, BLACK, (int(self.x) - 5, int(self.y) - 4), 3)
        pygame.draw.circle(screen, BLACK, (int(self.x) + 5, int(self.y) - 4), 3)

Faire apparaître des bugs : le starter a déjà un timer. Cherche # SPAWN BUG :

bugs.append(Bug(random.randint(30, WIDTH - 30), -20))

Tirer : cherche # TIR (c’est dans la boucle des événements, à K_SPACE) :

bullets.append(pygame.Rect(player_x - 3, player_y - 20, 6, 12))

Mets les projectiles à jour à chaque frame (cherche # MISE À JOUR PROJECTILES) :

for b in bullets[:]:
    b.y -= 10
    if b.y < 0:
        bullets.remove(b)
pygame.draw.rect(screen, YELLOW, b)  # ceci est déjà en place

Étape 2 : ✅ Basic : toucher les bugs

Maintenant tu écris la détection de collision : quand un projectile touche un bug, le bug meurt.

Cherche # ÉTAPE 2 — COLLISION :

for bug in bugs[:]:
    bug.update()
    bug.draw(screen)
    if bug.y > HEIGHT + 20:
        bugs.remove(bug)
        continue
    bug_rect = pygame.Rect(bug.x - 15, bug.y - 15, 30, 30)
    for bullet in bullets[:]:
        if bullet.colliderect(bug_rect):
            bug.alive = False
            bullets.remove(bullet)
            score += 1
            break
    if not bug.alive:
        bugs.remove(bug)

Clique sur Run. Tire sur les bugs : ils disparaissent dès que tu les touches !

Étape 3 : ⭐ Stretch : SlingerBug

Maintenant, tu crées une sous-classe : un Bug qui oscille de gauche à droite.

import math

class SlingerBug(Bug):
    def __init__(self, x, y):
        super().__init__(x, y)
        self.start_x = x
        self.timer = 0

    def update(self):
        self.timer += 0.05
        self.x = self.start_x + math.sin(self.timer) * 60
        self.y += 1.5  # un peu plus lent, mais plus dur à toucher

    def draw(self, screen):
        super().draw(screen)
        # Cercle orange autour, comme repère visuel
        pygame.draw.circle(screen, ORANGE, (int(self.x), int(self.y)), 18, 2)

Faire apparaître des SlingerBugs : ajoute ceci dans le code de spawn (par exemple un bug sur trois) :

if random.random() < 0.3:
    bugs.append(SlingerBug(random.randint(30, WIDTH - 30), -20))
else:
    bugs.append(Bug(random.randint(30, WIDTH - 30), -20))

super().__init__(x, y) appelle le __init__ de la classe parente (Bug), donc tu ne dois pas réécrire self.x, self.y et self.alive.

Étape 4 : 🔥 Expert : DuikBug

Le DuikBug détecte la position du joueur et plonge droit sur lui.

class DuikBug(Bug):
    def __init__(self, x, y, player_x_ref):
        super().__init__(x, y)
        self.player_x_ref = player_x_ref  # fonction qui donne le x actuel du joueur
        self.speed_x = 0
        self.speed_y = 1

    def update(self):
        target_x = self.player_x_ref()
        dx = target_x - self.x
        dist = max(abs(dx), 1)
        self.x += dx / dist * 2
        self.y += 2.5

    def draw(self, screen):
        super().draw(screen)
        pygame.draw.circle(screen, RED, (int(self.x), int(self.y)), 18, 2)

Spawn : utilise un lambda pour passer le x du joueur :

bugs.append(DuikBug(random.randint(30, WIDTH - 30), -20, lambda: player_x))

Bonus : dessine une barre de HP. Commence avec lives = 3 et enlève-en une quand un bug atteint le bas de l’écran.

Showcase

Montre ton jeu à un coach et à un buddy. Combien de bugs arrives-tu à zapper avant de ne plus avoir de vies ?

À la prochaine !

« La prochaine fois : une route infinie dans le ciel, et tout DÉFILE derrière toi. »

À emporter chez toi

Essaie une de ces extensions à la maison :

  1. Facile : rends les bugs plus grands ou plus rapides à mesure que le score monte.
  2. Moyen : ajoute un système de lives avec 3 vies ; si un bug atteint le bas, tu en perds une.
  3. Difficile : écris un PantserbBug qui a besoin de 3 tirs avant de mourir (utilise un attribut hp).
  4. Très difficile : ajoute le contrôle à la souris : le joueur suit la position de la souris et tire automatiquement toutes les 0,5 seconde.

Bloqué ? Demande au dojo suivant à un coach, ou essaie simplement autre chose. Programmer, c’est faire.

Dojo Defender : boss final

Dans cette session, tu continues aussi à construire Dojo Defender. Tu ajoutes un boss final qui apparaît toutes les 5 vagues, en 3 phases.

Va voir la session 6 de Dojo Defender pour les instructions.

Le starter et la solution sont prêts.


Regarde le cheatsheet de cette session

30 octobre 2026, 15:59

Session 8 : Sky Highway

Ton vaisseau vole dans une route aérienne sans fin. L’arrière-plan défile derrière toi, des obstacles rouges arrivent par la droite, et des étoiles rapportent des points. Plus tu survis longtemps, plus ça va vite !

Ce que tu vas apprendre aujourd’hui

  • Faire un arrière-plan qui défile avec une variable scroll_x
  • Faire apparaître des objets qui vont de droite à gauche
  • La détection de collision avec des vies
  • L’augmentation de la difficulté : accélérer à mesure que le score monte

Étape 0 : Installation

  1. Ouvre Thonny.
  2. Télécharge le starter via ce lien, décompresse le ZIP et ouvre main.py dans Thonny.
  3. Clique sur Run. Tu vois un écran statique avec un vaisseau et un fond de ciel, mais rien ne bouge encore.
  4. Des problèmes ? Demande à un coach.

Étape 1 : Faire défiler l’arrière-plan

Un arrière-plan qui défile donne l’illusion du mouvement. On dessine l’arrière-plan deux fois côte à côte et on décale la position à chaque frame.

Cherche # ÉTAPE 1 et ajoute :

# Décaler l'arrière-plan vers la gauche
scroll_x -= speed
if scroll_x <= -WIDTH:
    scroll_x = 0

# Dessiner l'arrière-plan deux fois
screen.blit(bg_image, (int(scroll_x), 0))
screen.blit(bg_image, (int(scroll_x) + WIDTH, 0))

scroll_x commence à 0 et diminue à chaque frame. Quand il atteint -WIDTH, on revient à 0 : une boucle sans couture.

Clique sur Run. Le ciel défile maintenant derrière ton vaisseau !

Étape 2 : ✅ Basic : obstacles et vies

Les obstacles arrivent par la droite et vont vers la gauche. Si tu les touches, tu perds une vie.

Mettre les obstacles à jour (cherche # ÉTAPE 2) :

for obs in obstacles[:]:
    obs.x -= speed
    if obs.x < -obs.width:
        obstacles.remove(obs)
    pygame.draw.rect(screen, RED, obs)
    # Collision
    if ship_rect.colliderect(obs):
        obstacles.remove(obs)
        lives -= 1
        if lives <= 0:
            running = False

Dessiner les vies :

for i in range(lives):
    pygame.draw.rect(screen, RED, (10 + i * 25, 10, 18, 18))

Faire apparaître des obstacles (dans l’événement du timer de spawn) :

h = random.randint(40, 120)
obstacles.append(pygame.Rect(WIDTH, random.randint(50, HEIGHT - h - 50), 30, h))

Étape 3 : ⭐ Stretch : ramasser les étoiles

Les étoiles rapportent des points et disparaissent quand tu les touches.

Cherche # ÉTAPE 3 :

for star in stars[:]:
    star.x -= speed
    if star.x < -20:
        stars.remove(star)
        continue
    pygame.draw.circle(screen, YELLOW, star.center, 10)
    if ship_rect.colliderect(star):
        stars.remove(star)
        score += 1

# Dessiner le score :
score_surf = font.render(f"Score : {score}", True, WHITE)
screen.blit(score_surf, (WIDTH - 120, 10))

Faire apparaître des étoiles (dans le même timer de spawn, mais moins souvent) :

if random.random() < 0.4:
    stars.append(pygame.Rect(WIDTH, random.randint(40, HEIGHT - 40), 20, 20))

Étape 4 : 🔥 Expert : spawn et vitesse qui augmente

Maintenant tu rends le jeu de plus en plus difficile à mesure que le score monte.

Faire augmenter la vitesse (cherche # ÉTAPE 4) :

speed = BASE_SPEED + score * 0.1

BASE_SPEED = 4 est déjà en haut du fichier. À un score de 20, tout va deux fois plus vite !

Adapter l’intervalle de spawn : plus le score est haut, plus les nouveaux obstacles arrivent souvent :

spawn_interval = max(500, 1800 - score * 30)  # min. 500ms
pygame.time.set_timer(SPAWN_EVENT, spawn_interval)

Écran de game over :

if not running:
    go_surf = font.render("GAME OVER", True, RED)
    screen.blit(go_surf, (WIDTH // 2 - go_surf.get_width() // 2, HEIGHT // 2 - 30))
    sc_surf = font.render(f"Score : {score}", True, WHITE)
    screen.blit(sc_surf, (WIDTH // 2 - sc_surf.get_width() // 2, HEIGHT // 2 + 10))
    pygame.display.flip()
    pygame.time.wait(3000)

Showcase

Montre ton jeu à un coach et à un buddy. Qui fait le meilleur score ?

À la prochaine !

« La prochaine fois : un boss qui se défend, en TROIS phases. »

À emporter chez toi

Essaie une de ces extensions à la maison :

  1. Facile : ajoute un deuxième type d’obstacle (par exemple un obstacle bleu qui vole plus haut ou plus bas).
  2. Moyen : ajoute des power-ups. Attrape une capsule verte pour un bouclier temporaire (le vaisseau peut être touché 1 fois).
  3. Difficile : fais monter et descendre le vaisseau avec les flèches et limite l’écran pour que le vaisseau ne sorte pas.
  4. Très difficile : ajoute du parallax scrolling : une deuxième couche d’arrière-plan (des nuages) qui défile plus lentement que la première.

Bloqué ? Demande au dojo suivant à un coach, ou essaie simplement autre chose. Programmer, c’est faire.


Dojo Defender : ta propre version

Aujourd’hui, tu continues aussi à travailler sur Dojo Defender — mais sans instructions pas à pas. C’est toi qui choisis ce que tu construis.

Télécharge le starter Dojo Defender — c’est le jeu complet avec tout dedans (vaisseau, ennemis, astéroïdes, vagues, boss). Choisis une feature dans la liste, planifie-la rapidement avec un coach, et lance-toi.

👉 Tout sur Dojo Defender se trouve sur la page Dojo Defender.


Regarde le cheatsheet de cette session

30 octobre 2026, 15:59

Session 9 : Boss Battle

Le boss final t’attend. Il va et vient, tire des projectiles et devient de plus en plus dangereux à mesure que ses HP baissent. Toi, tu tires en retour, tu suis ses HP sur une barre, et tu survis à trois phases. C’est la session la plus difficile, et la plus satisfaisante si tu y arrives.

Ce que tu vas apprendre aujourd’hui

  • Dessiner une barre de HP à l’écran
  • Une state machine : le boss ne se comporte pas pareil selon la phase
  • Faire tirer le boss avec un timer de projectiles
  • Activer des phases à des seuils de HP

Étape 0 : Installation

  1. Ouvre Thonny.
  2. Télécharge le starter via ce lien, décompresse le ZIP et ouvre main.py dans Thonny.
  3. Clique sur Run. Tu vois le boss en haut, ton vaisseau en bas. Pas encore de mouvement, pas encore de projectiles.
  4. Des problèmes ? Demande à un coach.

Étape 1 : Faire bouger le boss

Le boss va et vient sur l’écran. Quand il touche le bord, il repart dans l’autre sens.

Cherche # ÉTAPE 1 et ajoute :

boss_rect.x += boss_speed

# Repartir dans l'autre sens au bord
if boss_rect.right >= WIDTH or boss_rect.left <= 0:
    boss_speed = -boss_speed

boss_speed = 3 est déjà en haut du fichier. Clique sur Run : le boss traverse l’écran de gauche à droite !

Bouger le joueur et tirer (cherche # JOUEUR) :

keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT] and player_rect.left > 0:
    player_rect.x -= PLAYER_SPEED
if keys[pygame.K_RIGHT] and player_rect.right < WIDTH:
    player_rect.x += PLAYER_SPEED

# Tirer (cherche # TIR dans la boucle des événements) :
player_bullets.append(pygame.Rect(player_rect.centerx - 3, player_rect.top - 15, 6, 15))

Étape 2 : ✅ Basic : toucher le boss et la barre de HP

Collision entre le projectile du joueur et le boss :

Cherche # ÉTAPE 2 :

for b in player_bullets[:]:
    b.y -= 8
    if b.y < 0:
        player_bullets.remove(b)
        continue
    pygame.draw.rect(screen, YELLOW, b)
    if b.colliderect(boss_rect):
        player_bullets.remove(b)
        boss_hp -= 1
        if boss_hp <= 0:
            running = False  # le joueur gagne !

Dessiner la barre de HP (cherche # BARRE HP) :

# Fond de la barre
pygame.draw.rect(screen, DARK_RED, (10, 10, 300, 20))
# Partie remplie selon les HP actuels
breedte = int(300 * boss_hp / BOSS_MAX_HP)
pygame.draw.rect(screen, RED, (10, 10, breedte, 20))
# Texte
hp_surf = font.render(f"HP du boss : {boss_hp}", True, WHITE)
screen.blit(hp_surf, (320, 10))

Clique sur Run. Tire sur le boss : la barre de HP diminue !

Étape 3 : ⭐ Stretch : le boss tire en retour

Le boss tire un projectile vers le bas toutes les N frames.

Cherche # ÉTAPE 3 :

boss_shoot_timer += 1
if boss_shoot_timer >= boss_shoot_interval:
    boss_shoot_timer = 0
    boss_bullets.append(pygame.Rect(boss_rect.centerx - 4, boss_rect.bottom, 8, 16))

Mettre à jour les projectiles du boss :

for b in boss_bullets[:]:
    b.y += 6
    if b.y > HEIGHT:
        boss_bullets.remove(b)
        continue
    pygame.draw.rect(screen, ORANGE, b)
    if b.colliderect(player_rect):
        boss_bullets.remove(b)
        player_lives -= 1
        if player_lives <= 0:
            running = False

Dessine player_lives en petits cœurs ou en blocs rouges en bas de l’écran.

Étape 4 : 🔥 Expert : trois phases

Maintenant, le boss réagit à ses HP :

  • Phase 1 (HP de 100 à 50) : comportement normal
  • Phase 2 (HP de 50 à 25) : se déplace plus vite, tire plus souvent
  • Phase 3 (HP < 25) : vitesse maximale, projectiles doubles

Cherche # ÉTAPE 4 :

if boss_hp > 50:
    boss_phase = 1
    boss_speed_abs = 3
    boss_shoot_interval = 60
elif boss_hp > 25:
    boss_phase = 2
    boss_speed_abs = 5
    boss_shoot_interval = 35
else:
    boss_phase = 3
    boss_speed_abs = 7
    boss_shoot_interval = 20

# Adapter la vitesse sans changer la direction :
boss_speed = boss_speed_abs * (1 if boss_speed > 0 else -1)

Phase 3 : projectiles doubles (ajoute ceci dans le code de tir) :

if boss_phase == 3:
    boss_bullets.append(pygame.Rect(boss_rect.left + 10, boss_rect.bottom, 8, 16))
    boss_bullets.append(pygame.Rect(boss_rect.right - 18, boss_rect.bottom, 8, 16))
else:
    boss_bullets.append(pygame.Rect(boss_rect.centerx - 4, boss_rect.bottom, 8, 16))

Écran de victoire quand boss_hp <= 0 :

screen.fill(BLACK)
win = font.render("BOSS VAINCU !", True, YELLOW)
screen.blit(win, (WIDTH // 2 - win.get_width() // 2, HEIGHT // 2))
pygame.display.flip()
pygame.time.wait(3000)

Showcase

Montre ton jeu à un coach et à un buddy. Qui atteint la phase 3 et survit ?

À la prochaine !

« La prochaine fois : ton propre jeu, de zéro, entièrement ton idée. »

À emporter chez toi

Essaie une de ces extensions à la maison :

  1. Facile : change la couleur du boss selon la phase (vert → orange → rouge).
  2. Moyen : ajoute un score : plus tu bats le boss vite, plus tu marques de points.
  3. Difficile : fais aussi tirer le boss en diagonale en phase 2 (en biais à gauche et à droite).
  4. Très difficile : ajoute un deuxième joueur qui peut participer avec les touches WASD.

Bloqué ? Demande au dojo suivant à un coach, ou essaie simplement autre chose. Programmer, c’est faire.

Regarde le cheatsheet de cette session

30 octobre 2026, 15:59

Session 10 : Mon jeu

Cette session est la tienne. Pas d’étapes fixes, pas de mécaniques obligatoires. C’est toi qui décides ce que tu construis, et aujourd’hui tu le fais.

Ton jeu, tes règles

En neuf sessions, tu as appris :

  • Les variables, les fonctions et les boucles de jeu
  • Le clavier et la souris
  • Les sprites, la détection de collision et le score
  • Le son et l’animation
  • Les classes et l’héritage
  • Les arrière-plans qui défilent, le spawn et la difficulté qui augmente
  • Les barres de HP, les state machines et l’IA du boss

Toutes ces briques sont prêtes. Aujourd’hui, tu les combines dans ton propre jeu.

Choisis ton concept

Pas encore d’idée ? Voilà quelques genres pour commencer :

Dodge game : esquive des objets qui arrivent de plus en plus vite. Simple mais accrocheur.

Platformer : saute de plateforme en plateforme, ramasse des items, évite les ennemis.

Shooter : descends les ennemis qui arrivent d’en haut ou sur le côté.

Jeu de puzzle : fais glisser des blocs, relie des points, ou résous un motif.

Jeu de course : dessine un parcours et fonce vers l’arrivée le plus vite possible.

Raconte une histoire : pas de score, pas de vies. Laisse le joueur cliquer et faire des choix.

Tu peux aussi combiner : un shooter avec des éléments de puzzle, un platformer avec un boss à la fin. Tout est permis.

Planifie ton jeu

Avant d’écrire du code, réponds à ces trois questions :

  1. Que fait le joueur ? (se déplacer, tirer, sauter, cliquer, …)
  2. Quel est le but ? (faire un score, battre le boss, atteindre la fin, …)
  3. Qu’est-ce qui rend le jeu difficile ? (des ennemis, des obstacles, un timer, …)

Écris tes réponses sur une feuille ou dans un commentaire en haut de ton code. Ça t’aide à rester concentré quand tu bloques.

Animation : changer de sprite à chaque frame

Tu veux une animation en boucle, une explosion ou un objet qui clignote ? Fais une liste de noms d’images et change actor.image toutes les N millisecondes. La démo ci-dessous montre comment ça marche : utilise le curseur pour changer la vitesse et le bouton pour mettre en pause :

En Python, tu utilises alors une liste de noms d’images et un timer :

frames = ['lopen_1', 'lopen_2', 'lopen_3', 'lopen_4']
anim_timer = 0
FRAME_DUUR = 10   # frames (à 60 fps = ~167 ms)

def update():
    global anim_timer
    anim_timer += 1
    speler.image = frames[(anim_timer // FRAME_DUUR) % len(frames)]

À toi de jouer

Télécharge le starter via ce lien. Le starter a :

  • Une game loop pygame qui fonctionne
  • Une section draw() et update() vide
  • Des constantes de couleur et une variable de police prêtes
  • Des commentaires qui indiquent où mettre quoi

Ouvre main.py et commence par l’étape 1 de ton propre plan. Le cheatsheet de cette page a tous les patrons des sessions précédentes sous la main.

Bloqué ? Demande à un coach. Décris ce que tu veux obtenir, pas seulement ce qui ne marche pas. Comme ça, on peut chercher ensemble la meilleure approche.

Fini trop vite ? Ajoute du son, fais un écran de démarrage, ou ajoute un deuxième joueur.

Showcase

À la fin de la session, chacun présente son jeu. Tu ne dois pas l’avoir terminé. Montre ce que tu as fait et raconte :

  • Quel est le concept de ton jeu ?
  • Quelle technique d’une session précédente as-tu utilisée ?
  • Qu’est-ce que tu aimerais encore ajouter si tu avais plus de temps ?

Et maintenant ?

CoderDojo s’arrête après dix sessions. Construire toi-même, ça ne s’arrête pas.

Continue à construire. Les petits projets t’apprennent plus que les gros cours. Fais un jeu pour ton frère ou ta sœur, pour ton animal, ou juste pour toi.

Besoin d’inspiration ?

CoderDojo revient. Toi aussi ?

Continue à construire !

En dix sessions, tu as construit un platformer, un shooter, un boss battle et plus encore. Emporte ce code à la maison, rouvre-le la semaine prochaine et ajoute juste une chose. C’est comme ça que travaillent les programmeurs.

Regarde le cheatsheet de cette session

30 octobre 2026, 15:59

Sessions Git

Cinq sessions sur Git et GitHub, de ton premier commit aux pull requests. Plus une session bonus sur Markdown, le langage dans lequel tu écris tes notes et ta documentation.

30 octobre 2026, 15:59

Sous-sections de Sessions Git

Session 11 : Git : le livre d'histoire de ton code

Imagine : tu travailles trois heures sur ton jeu. Tu ajoutes une arme trop cool. Mais… maintenant le reste de ton jeu ne marche plus. Et tu ne sais plus ce que tu as changé exactement. Trois heures de travail perdues.

Git est la solution. Git se souvient de chaque version de tes fichiers. Comme un bouton « annuler » infini qui n’oublie jamais ce que tu as fait.

Dans cette session, tu installes Git, tu crées ton premier dépôt et tu enregistres pour toujours ce que tu fais : étape par étape, version par version. Et le plus chouette : Git ne sert pas qu’au code. Il marche aussi pour tes notes, tes travaux d’école et tes histoires.

Qu’est-ce que Git ?

Git est un système de gestion de versions. Il garde une trace de ce que tu changes dans tes fichiers, quand tu l’as fait, et pourquoi. Chaque fois que tu as fini un morceau de travail, tu fais un commit : une photo de tous tes fichiers à ce moment-là.

Ce qui rend Git spécial :

  • Chaque version est conservée. Tu peux toujours revenir à un commit précédent si quelque chose casse.
  • Tu travailles en local. Git tourne sur ton ordinateur. Pas besoin d’internet.
  • Git est rapide. Même des projets avec des milliers de fichiers se vérifient en millisecondes.

Git a été créé par Linus Torvalds, la même personne qui a construit Linux. Il avait besoin d’un outil pour travailler sur le noyau Linux avec des milliers de programmeurs en même temps. En 2005, il a construit Git en un week-end. Aujourd’hui, presque tous les développeurs du monde l’utilisent.

Git ne sert pas qu’au code

Git a été conçu pour le code source, mais il fonctionne avec tous les fichiers texte. Un fichier texte, c’est n’importe quel fichier que tu peux ouvrir et lire avec le Bloc-notes ou un éditeur simple : .py, .html, .css, .json, .txt, .csv, .md (Markdown), .yml, .toml, tout ce que tu veux.

Ce que Git ne sait pas bien faire : les fichiers binaires. Ce sont des fichiers qui ne sont pas du texte lisible : des images (.png, .jpg), des vidéos (.mp4), des programmes compilés (.exe), des documents Word (.docx). Git peut les suivre, mais c’est plus lent et tu ne vois pas ce qui a changé exactement. Avec un fichier texte, git diff montre chaque lettre que tu as ajoutée ou enlevée. Avec un .png, Git dit seulement « ce fichier a changé », mais pas ce qui a changé dans l’image.

Markdown et notes

Beaucoup d’applications de notes d’aujourd’hui utilisent Markdown (des fichiers .md) pour stocker tes documents. Par exemple :

  • Obsidian : tes notes sont juste des fichiers .md dans un dossier de ton ordinateur
  • Notion : exporte vers Markdown
  • Joplin : enregistre tout en Markdown
  • Typora, Zettlr, Logseq : tous basés sur Markdown

Comme les fichiers Markdown sont de simples fichiers texte, tu peux les mettre sous Git. Tu gardes l’historique de tes notes, tu peux revenir à une version précédente d’un document, et tu peux partager tes notes via GitHub, exactement comme tu le fais avec du code.

Mettre un dossier de notes Markdown sous Git est aussi simple qu’un projet Python :

mkdir mijn-notities
cd mijn-notities
git init
echo "# Mes notes" > start.md
git add start.md
git commit -m "Première note : page de départ"

À partir de ce moment, Git garde chaque modification de tes notes. Tu écris un travail pour l’école en Markdown ? Commit chaque paragraphe. Tu travailles à la construction d’un monde pour une histoire ? Git retient chaque version de ton intrigue.

Quand utiliser Git pour tes notes, et quand pas

Utilise GitMieux avec autre chose
Notes en Markdown (.md)Notes en Word (.docx)
Fichiers de configuration (.json, .yml)Grandes images ou vidéos avec tes notes
Textes : travaux, histoires, blogsCollaboration en temps réel comme Google Docs (Git est trop lent pour ça)
Tes cheatsheets CoderDojoMots de passe ou journaux intimes (sauf dépôt privé)

En résumé : tout ce qui est du texte peut aller dans Git. Tout ce qui est binaire, mieux vaut éviter.

Pourquoi la gestion de versions ?

Sans Git, ton workflow ressemble à ça :

game.py
game_backup.py
game_backup2.py
game_final.py
game_final_echt.py
game_final_echt_nieuwe_wapens.py

Tu reconnais ? Avec Git, tu n’as besoin que d’un seul fichier : game.py. Git se souvient du reste.

Ce que la gestion de versions t’apporte :

  • Plus jamais de travail perdu. Tout ce que tu commites reste. Pour toujours.
  • Comprendre ce qui s’est passé. Tu vois exactement quelles lignes tu as changées et quand.
  • Expérimenter sans risque. Tu fais une copie séparée de ton code (une branche), tu essaies un truc bizarre, et tu la jettes si ça ne marche pas. Ton code d’origine reste intact.
  • Collaborer. Plusieurs personnes peuvent travailler en même temps sur le même projet, sans écraser le code des autres.

Qu’est-ce que tu ne mets PAS dans Git ?

Git est fait pour les fichiers texte : les fichiers que tu écris toi-même : code, notes, configuration. Il y a des choses que tu gardes mieux en dehors de Git :

Mets dans GitNe mets PAS dans Git
Tes fichiers Python (.py)Mots de passe, clés API, tokens
Les images utilisées par ton jeuLes fichiers que ton programme crée lui-même (.exe, .pyc)
Les fichiers son (.wav, .mp3)Le dossier __pycache__
Les fichiers texte, la configurationLes gros fichiers (>50 MB) comme les vidéos
Ton README.mdLes réglages de ton ordinateur à toi

Pourquoi pas de mots de passe dans Git ? Parce que Git se souvient de tout, pour toujours. Même si tu supprimes un mot de passe plus tard, il est encore dans l’historique. Quiconque voit ton code un jour peut remonter jusqu’à ce commit. Et si ton code arrive un jour sur GitHub, ton mot de passe est sur internet. Pour l’éternité.

Utilise un fichier .gitignore pour dire à Git quels fichiers il doit ignorer. Tu vas voir ça tout de suite.

Étape 0 : Installer Git

Windows

  1. Va sur git-scm.com et télécharge l’installateur Windows.
  2. Double-clique sur le fichier téléchargé.
  3. Clique à travers l’installation. Les options par défaut sont très bien.
  4. Important : au choix de l’éditeur de texte, choisis Nano ou Notepad++ (pas Vim, sauf si tu connais déjà Vim).
  5. Après l’installation, ouvre Git Bash (cherche-le dans le menu démarrer).

Mac

Ouvre le Terminal (cherche « Terminal » dans Spotlight) et tape :

git --version

Si Git n’est pas installé, macOS te demande d’installer les developer tools. Clique sur « Install ». C’est fait.

Linux (Ubuntu/Debian)

sudo apt install git

Vérifier que ça marche

Ouvre un terminal (Git Bash sous Windows) et tape :

git --version

Tu vois quelque chose comme git version 2.47.0. Ça veut dire : Git est prêt.

Étape 1 : Dis à Git qui tu es

Git veut savoir qui tu es, pour pouvoir mettre ton nom sur chaque commit. Tu fais ça une seule fois, ensuite Git s’en souvient.

git config --global user.name "Ton Nom"
git config --global user.email "ton@email.com"

Utilise la même adresse e-mail que celle que tu utiliseras tout à l’heure pour GitHub. Ça rend le couplage plus simple.

Astuce : --global veut dire : ce réglage vaut pour tous tes projets Git. Tu ne dois le faire qu’une seule fois.

Étape 2 : Créer ton premier dépôt

Un dépôt (ou « repo ») est un dossier où Git garde les versions. On en crée un.

Crée d’abord un nouveau dossier pour ton projet :

mkdir mijn-eerste-git-project
cd mijn-eerste-git-project

Maintenant tu dis à Git : « Ce dossier est un dépôt. »

git init

Tu vois : Initialized empty Git repository in .../mijn-eerste-git-project/.git/

Git a créé un dossier caché .git. C’est là qu’il garde tout : l’historique, les commits, la configuration. Ne touche jamais ce dossier à la main, c’est Git qui le gère.

Étape 3 : Committer ton premier fichier

Crée un fichier. Par exemple un fichier Python avec une seule ligne :

echo 'print("Salut Git !")' > hallo.py

Maintenant tu dis à Git : « Fais attention à ce fichier. »

git add hallo.py

Avec git add, tu mets des fichiers dans la staging area : une zone intermédiaire. Tu dis à Git : « Ces changements, je veux les mettre dans mon prochain commit. »

Vérifie ce qui est prêt :

git status

Git affiche :

On branch master
Changes to be committed:
  new file:   hallo.py

Maintenant vient le commit lui-même :

git commit -m "Mon premier commit : hallo.py ajouté"

Que se passe-t-il ici ? -m veut dire « message ». Le texte entre guillemets est ton commit message : une courte explication de ce que tu as changé. Git a maintenant pris une photo permanente de ton projet.

Des bons commit messages : écris en anglais (c’est la convention dans presque tous les projets). Commence par un verbe : « Add », « Fix », « Update ». Reste court : 72 caractères maximum.

Étape 4 : Suivre les changements

Ouvre hallo.py dans un éditeur de texte. Change la ligne par :

print("Salut Git ! Tu te souviens de mon code.")

Enregistre le fichier. Regarde maintenant ce que Git voit :

git status

Git sait que hallo.py a changé. Mais qu’est-ce qui a changé exactement ?

git diff

git diff montre exactement quelles lignes tu as ajoutées (en vert avec +) et supprimées (en rouge avec -). C’est une des choses les plus puissantes de Git : tu vois littéralement ce qui a changé, caractère par caractère, depuis ton dernier commit.

Committe la modification :

git add hallo.py
git commit -m "Update : salutation étendue"

Étape 5 : Retour dans le temps

C’est ici que Git devient magique. Imagine : tu regrettes ta dernière modification. Tu veux revenir à la première version.

Montre d’abord tous les commits :

git log --oneline

Tu vois quelque chose comme :

a1b2c3d Update : salutation étendue
e4f5g6h Mon premier commit : hallo.py ajouté

Chaque commit a un code unique, un hash. Ce long code (raccourci à 7 caractères) identifie exactement cette version-là de ton projet.

Pour voir à quoi ressemblait hallo.py dans le premier commit :

git show e4f5g6h:hallo.py

Voilà ton print("Salut Git !") d’origine.

Tu veux vraiment retourner dans le temps ? C’est possible :

git checkout e4f5g6h -- hallo.py

Maintenant hallo.py est de nouveau comme dans ton premier commit. Vérifie avec cat hallo.py. Tu vois l’ancienne version. Mais ne t’inquiète pas : ton deuxième commit n’a pas disparu. Avec git checkout master -- hallo.py, tu reviens à la dernière version.

Étape 6 : Ce qui ne va pas dans Git : .gitignore

Crée un fichier que Git doit ignorer :

echo "GEHEIM_WACHTWOORD=12345" > geheimen.txt

git status montre maintenant ce fichier comme « untracked ». Git l’a vu, mais il ne sait pas si tu veux le suivre. Tu peux l’ignorer avec un fichier .gitignore :

echo "geheimen.txt" > .gitignore

Maintenant git status à nouveau et geheimen.txt a disparu de la liste. Git l’ignore. (Ajoute bien .gitignore lui-même à Git avec git add .gitignore et git commit, pour que les autres sachent aussi ce qu’il faut ignorer.)

Un bon .gitignore pour un projet Python :

# Python
__pycache__/
*.pyc
*.pyo

# Secrets
*.env
secrets.txt

# Ton éditeur
.vscode/
.idea/

Showcase

Montre à un coach et à un buddy :

  1. Ton dépôt avec au moins 3 commits.
  2. Le résultat de git log --oneline : ton historique de commits.
  3. Un git diff qui montre ce que tu as changé.
  4. Ton fichier .gitignore.

À la prochaine !

« La prochaine fois : deux versions de ton code en même temps. Tu travailles sur une nouvelle feature pendant que l’ancienne version continue de marcher. Ça s’appelle des branches, et c’est ce qui rend Git vraiment puissant. »

À emporter chez toi

  1. Facile : crée un dépôt pour tes notes. Mets un fichier Markdown avec ce que tu as appris aujourd’hui dans Git, et committe-le.
  2. Moyen : change quelque chose dans ton code ou tes notes, utilise git diff pour regarder la modification, et committe-la avec un bon message.
  3. Difficile : fais trois commits avec des modifications différentes. Utilise git show pour regarder chaque version. Utilise git checkout pour revenir au premier commit, puis de nouveau au dernier.
  4. Très difficile : fais un projet Python avec un bon .gitignore. Fais en sorte que __pycache__/ et les fichiers .pyc soient vraiment ignorés (vérifie avec git status).

Bloqué ? Demande au dojo suivant à un coach, ou essaie simplement autre chose. Programmer, c’est faire. Apprendre Git, c’est faire.

30 octobre 2026, 15:59

Session 12 : Git Branches : des univers parallèles pour ton code

La session précédente, tu as appris à faire des commits : des photos de ton code sur une seule ligne du temps. Tout bien à la suite.

Mais si tu veux essayer une nouvelle idée ? Ajouter un pistolet laser à ton jeu, par exemple. Tu ne sais pas si ça va marcher. Tu ne veux pas casser ton code qui fonctionne.

C’est pour ça que les branches existent.

Une branche est une copie de ton code où tu peux expérimenter librement. Ton code principal (la branche master) reste en sécurité. Si ton expérience marche, tu la recolles dans master. Si elle ne marche pas ? Tu jettes la branche. Ta branche master n’en a jamais rien su.

Note : sur GitHub et dans beaucoup de nouveaux projets, la branche principale s’appelle main au lieu de master. C’est exactement la même chose, seul le nom change. Dans ce cours, on utilise master, mais si tu croises main en ligne, tu sais que ça veut dire la même chose.

Ce que tu vas apprendre aujourd’hui

  • Ce qu’est une branche et comment Git stocke les branches en interne
  • Créer, changer et fusionner des branches
  • Ce qu’est un merge conflict et comment le résoudre
  • Quand utiliser une branche, et quand pas

Étape 0 : Rappel : où en es-tu ?

Ouvre ton terminal dans le projet de la session précédente. Vérifie où tu es :

git status
git log --oneline

Tu as quelques commits sur master. C’est ta base stable : c’est d’ici que tu vas te séparer tout à l’heure.

Étape 1 : Ta première branche

Tu vas ajouter une nouvelle feature : un fichier highscore.txt qui garde le meilleur score. Mais d’abord, tu crées une branche :

git branch highscore-feature

Git a maintenant créé une nouvelle branche. Mais tu es toujours sur master. Vérifie quelles branches existent :

git branch

Tu vois :

  highscore-feature
* master

L’astérisque à côté de master veut dire : « tu es ici ». Passe à ta nouvelle branche :

git switch highscore-feature

(Les versions plus anciennes de Git utilisent git checkout highscore-feature. Les deux marchent.)

Encore une fois git branch : l’astérisque est maintenant à côté de highscore-feature. Tout ce que tu commites maintenant se passe sur cette branche. master reste intact.

Astuce : tu peux créer une branche et y aller directement en une seule commande :

git switch -c mijn-nieuwe-branch

-c veut dire « create ». C’est plus rapide et tu n’oublies jamais de changer de branche.

Étape 2 : Travailler sur une branche

Crée un nouveau fichier :

echo "HIGHSCORE: 0" > highscore.txt

Committe ton travail :

git add highscore.txt
git commit -m "Add highscore.txt avec valeur de départ 0"

Ajoute encore un fichier qui lit le highscore :

echo 'def lees_highscore():' > highscore_manager.py
echo '    with open("highscore.txt") as f:' >> highscore_manager.py
echo '        return int(f.read().split(": ")[1])' >> highscore_manager.py

Committe encore :

git add highscore_manager.py
git commit -m "Add highscore_manager : fonction pour lire le highscore"

Regarde maintenant ton log :

git log --oneline

Tu vois tous tes commits de master, plus les deux nouveaux. Git se souvient de toute la chaîne.

Étape 3 : Deux mondes en même temps

Reviens sur master :

git switch master

Regarde ce qu’il y a ici :

ls

highscore.txt et highscore_manager.py ont… disparu. Ils existent seulement sur la branche highscore-feature. Sur master, tout est encore exactement comme tu l’as laissé.

C’est la magie des branches : deux (ou plus) versions de ton projet, en même temps sur ton ordinateur, sans se gêner.

Change encore une fois dans les deux sens pour le sentir :

git switch highscore-feature   # les fichiers sont revenus
git switch master                # les fichiers ont encore disparu

Étape 4 : Fusionner avec git merge

Ta feature highscore fonctionne. Il est temps de la remettre dans master. Ça s’appelle merger.

Assure-toi d’être sur master :

git switch master

Fusionne la branche :

git merge highscore-feature

Git affiche quelque chose comme Updating a1b2c3d..e4f5g6h et Fast-forward. Tes commits de highscore-feature font maintenant partie de master. Vérifie :

ls
git log --oneline

highscore.txt et highscore_manager.py sont maintenant sur master. Tous les commits de la branche feature sont repris dans l’historique.

Étape 5 : C’est quoi, un merge conflict ?

Imagine : tu as changé quelque chose sur master dans highscore.txt, par exemple “HIGHSCORE: 100” au lieu de “HIGHSCORE: 0”. Et en même temps, sur une autre branche, tu as aussi changé highscore.txt, en “HIGHSCORE: 500”.

Si tu essaies de merger maintenant, Git ne sait pas quelle version est la bonne. C’est un merge conflict. Git te demande à toi de décider.

Provoquons-le exprès.

Sur master :

echo "HIGHSCORE: 100" > highscore.txt
git add highscore.txt
git commit -m "Update highscore à 100 sur master"

Crée une nouvelle branche et change le même fichier :

git switch -c andere-highscore
echo "HIGHSCORE: 500" > highscore.txt
git add highscore.txt
git commit -m "Update highscore à 500"

Reviens sur master et essaie de merger :

git switch master
git merge andere-highscore

Git dit : CONFLICT (content): Merge conflict in highscore.txt. Ouvre highscore.txt dans ton éditeur. Tu vois :

<<<<<<< HEAD
HIGHSCORE: 100
=======
HIGHSCORE: 500
>>>>>>> andere-highscore

Ce sont les deux versions. HEAD, c’est ta version master. En dessous se trouve la version de andere-highscore. Tu choisis laquelle tu gardes, ou tu les combines.

Supprime les marqueurs et choisis une version :

HIGHSCORE: 500

Enregistre le fichier. Dis à Git que le conflit est résolu :

git add highscore.txt
git commit -m "Merge : highscore de andere-highscore choisi"

Conflit résolu. Git peut continuer.

Étape 6 : Ranger les branches

Ta feature est mergée. Tu n’as plus besoin de la branche :

git branch -d highscore-feature
git branch -d andere-highscore

-d veut dire « delete ». Git refuse de supprimer une branche qui n’est pas encore mergée : c’est une soupape de sécurité. Si tu veux vraiment jeter une branche sans la merger, utilise -D (majuscule). Mais fais attention avec ça.

Une branche ou pas, quand ?

Une branche, ouiPas de branche
Une nouvelle feature qui prend du tempsCorriger une faute dans un commentaire
Une expérience dont tu ne sais pas si ça marcheUn petit bugfix d’une ligne
Quelque chose qui peut casser ton code qui marcheTu travailles seul et ta modification est claire
Tu travailles avec d’autres(en solo, master suffit souvent)

Règle de base : si tu hésites, fais une branche. Une branche ne coûte rien. Perdre du code, si.

Astuces pour travailler vite avec les branches

  1. Garde tes branches courtes. Une branche de 3 heures, c’est parfait. Une branche de 3 semaines devient un cauchemar de merge : plus tu attends pour merger, plus master change entre-temps, et plus le risque de conflicts augmente.
  2. Une seule chose par branche. « Ajouter le highscore » est une bonne branche. « Ajouter le highscore, un menu et de nouveaux niveaux » est trop : découpe-le.
  3. Merge souvent. Quand ta feature est finie, merge-la tout de suite dans master. Des merges petits et fréquents sont plus faciles qu’un seul gros merge monstre.
  4. Donne des noms clairs à tes branches. highscore-feature, c’est bien. test123 ou branch2, c’est mauvais. Dans une semaine, tu ne sauras plus ce qu’il y avait dans test123.
  5. Vérifie où tu es avant de commencer. git branch ou git status te dit sur quelle branche tu es. Fais-en une habitude, pour éviter d’écrire par accident du code sur master qui appartient en fait à une branche feature.

Showcase

Montre à un coach et à un buddy :

  1. git branch avec au moins deux branches (dont master).
  2. Sur chaque branche, un autre fichier ou d’autre code.
  3. Le switch dans les deux sens : les fichiers apparaissent et disparaissent.
  4. Un merge réussi d’une branche feature dans master.

À la prochaine !

« Jusqu’ici, tout ton code vit seulement sur ton laptop. La prochaine fois, on le met en ligne. Tu crées un compte GitHub, tu pushes ton dépôt sur internet, et ton jeu est visible partout dans le monde. Et : tu peux collaborer avec d’autres. GitHub : ton code dans le monde entier. »

À emporter chez toi

  1. Facile : crée une branche pour une petite feature dans un projet existant. Committe ton travail et merge-la.
  2. Moyen : crée exprès un merge conflict (deux branches qui modifient le même fichier) et résous-le.
  3. Difficile : travaille avec trois branches en même temps sur le même projet. Merge-les une par une dans master. Vérifie après chaque merge que tout marche encore.
  4. Très difficile : crée une branche, fais trois commits, reviens sur master, fais là aussi une modification dans le même fichier, et merge la branche. Résous le conflit soigneusement et vérifie avec git log --graph à quoi ressemble l’historique.
30 octobre 2026, 15:59

Session 13 : GitHub : ton code en ligne, pour tout le monde

Jusqu’ici, tout ton code vit sur ton laptop. Pratique pour toi, mais personne d’autre n’y a accès. Et si ton laptop plante, tu perds tout.

GitHub est un site web où tu mets tes dépôts Git en ligne. C’est une sauvegarde, un portfolio et une plateforme de collaboration en un seul. Aujourd’hui, tu mets ton code sur GitHub. À la fin de cette session, n’importe qui avec une connexion internet peut voir tes projets, et toi ceux des autres.

C’est quoi GitHub ?

GitHub, ce n’est pas la même chose que Git. Git est le système de gestion de versions qui tourne sur ton ordinateur. GitHub est un site web (github.com) qui héberge des dépôts Git : une sorte de Google Drive pour le code, mais avec Git en dessous.

Ce que GitHub ajoute à Git :

  • Une sauvegarde dans le cloud. Ton code n’est pas seulement en local. Laptop cassé ? Ton code survit.
  • La collaboration. Plusieurs personnes peuvent travailler sur le même repo. GitHub gère qui a le droit de faire quoi.
  • Les pull requests. Tu demandes la permission de mettre tes modifications dans le projet de quelqu’un, avec discussion et review.
  • Les issues. Signaler des bugs, proposer des features, suivre des tâches : tout se passe dans ton repo.
  • Le portfolio. Ton profil GitHub, c’est ta carte de visite. Les employeurs le regardent.

GitHub n’est pas la seule option ; il y a des alternatives comme GitLab et Bitbucket. Mais GitHub est le plus grand, avec plus de 100 millions d’utilisateurs. Dans ces sessions, on utilise GitHub.

Étape 0 : Créer un compte GitHub

  1. Ouvre github.com dans ton navigateur.
  2. Clique sur Sign up.
  3. Remplis ton adresse e-mail. Utilise la même adresse que celle que tu as configurée dans git config à la session 11 : ça évite des soucis.
  4. Choisis un username. C’est ton identité sur GitHub. Choisis quelque chose que tu trouveras encore chouette dans 5 ans. Tu peux changer ton username plus tard, mais les anciens liens vers ton profil ne marcheront alors plus.
  5. Vérifie ton compte via l’e-mail que GitHub envoie.
  6. Choisis l’abonnement Free. Tout ce dont tu as besoin est gratuit : repos publics et privés illimités.

Astuce pour les coaches : vérifie que les ninjas ont accès à leur e-mail pendant la session. Certains laptops ne sont pas connectés au webmail. Prépare un plan B : si la vérification par e-mail ne marche pas, les ninjas peuvent vérifier leur compte GitHub plus tard à la maison. Le reste de la session marche aussi sans vérification.

Étape 1 : Ton premier dépôt sur GitHub

Tu as un projet local sur ton ordinateur (de la session 11). Tu vas le mettre en ligne.

Sur GitHub, clique en haut à droite sur l’icône + → New repository.

Remplis :

ChampCe que tu remplis
Repository namemijn-eerste-git-project (le même que ton dossier local)
Description“Mon premier projet Git (CoderDojo session 11)”
Public / PrivateChoisis Public : les autres peuvent voir ton code
Initialize with READMENE coche PAS : tu as déjà un projet local

Clique sur Create repository.

GitHub affiche maintenant des instructions. Choisis le bloc sous "…or push an existing repository from the command line". Copie ces trois commandes : tu en auras besoin tout de suite.

Étape 2 : Relier ton dépôt local à GitHub

Dans ton terminal (dans ton dossier de projet) :

git remote add origin https://github.com/JOUW_USERNAME/mijn-eerste-git-project.git

Que se passe-t-il ici ? remote est un endroit externe où ton repo se trouve aussi. origin est le nom que tu donnes à cet endroit. « origin » est le nom par défaut de ta remote principale. Tu peux avoir plusieurs remotes (par exemple origin pour GitHub, backup pour GitLab), mais une seule suffit la plupart du temps.

Vérifie que ça a marché :

git remote -v

Tu vois :

origin  https://github.com/JOUW_USERNAME/mijn-eerste-git-project.git (fetch)
origin  https://github.com/JOUW_USERNAME/mijn-eerste-git-project.git (push)

fetch = c’est de là que tu récupères du code. push = c’est là que tu envoies ton code. La plupart du temps, c’est le même endroit.

Étape 3 : Mettre ton code en ligne avec git push

Voilà le moment : envoyer tes commits locaux vers GitHub.

git push -u origin master

push = envoie mes commits vers la remote. -u origin master = « retiens que master sur mon ordinateur correspond à master sur origin. » La prochaine fois, tu peux juste taper git push, parce que Git se souvient du lien.

GitHub demande de te connecter. Deux possibilités :

  1. Via le navigateur : GitHub ouvre une fenêtre de navigateur, tu cliques sur « Authorize ». C’est fait.
  2. Avec un Personal Access Token : crée-le via GitHub → Settings → Developer settings → Personal access tokens → Tokens (classic). Donne un nom au token, coche repo, copie le token, et colle-le comme mot de passe dans le terminal.

Pour les ninjas : la méthode 1 (navigateur) est la plus simple. Si ça ne marche pas, aide-les avec un token.

Après un push réussi, rafraîchis ta page GitHub. Tes fichiers sont là ! Ton hallo.py, ton historique de commits : tout.

Étape 4 : Pusher des modifications

Fais une modification en local :

echo 'print("GitHub is cool!")' >> hallo.py
git add hallo.py
git commit -m "Add GitHub enthusiasm"

Pushe vers GitHub :

git push

Tu n’as plus besoin de -u origin master, parce que Git connaît le chemin. Rafraîchis GitHub : ton nouveau commit est là.

Étape 5 : Démarrer un nouveau projet via GitHub

C’est la route inverse : tu commences sur GitHub et tu le ramènes sur ton ordinateur.

Sur GitHub : New repository. Appelle-le python-spelletje. Cette fois, coche bien Add a README file ; GitHub crée alors un repo avec un fichier dedans. Clique sur Create repository.

Maintenant tu ramènes ce repo sur ton ordinateur. Ça s’appelle cloner :

cd ~   # va dans ton dossier home
git clone https://github.com/JOUW_USERNAME/python-spelletje.git

GitHub crée un dossier python-spelletje avec le README dedans. Et c’est tout de suite un dépôt Git complet : le dossier .git est déjà là. Tu ne dois pas faire de git init.

cd python-spelletje
git log --oneline   # tu vois le premier commit que GitHub a fait pour toi

Maintenant tu peux continuer à travailler ici en local et pusher tes commits vers GitHub, exactement comme aux étapes 3 à 4.

Étape 6 : Et si quelqu’un d’autre fait aussi des modifications ?

Imagine : tu as travaillé à python-spelletje à la maison et tu as pushé. Maintenant tu es au dojo avec un laptop et tu veux continuer. Tu n’as pas encore la dernière version.

git pull

git pull récupère les derniers commits de GitHub sur ton ordinateur. C’est deux actions en une : git fetch (récupérer) + git merge (fusionner avec ton code local).

Fais toujours git pull avant de commencer à travailler, sinon tu prends du retard et tu récoltes des merge conflicts.

Résumé du workflow :

CommandeCe qu’elle fait
git pullRécupérer la dernière version depuis GitHub
Travailler à ton code, faire des commits (git add, git commit)
git pushEnvoyer tes commits vers GitHub

Retiens : pull avant de commencer, push quand tu as fini.

Showcase

Montre à un coach et à un buddy :

  1. Ton profil GitHub avec au moins un dépôt.
  2. L’historique de commits de ton repo sur GitHub (clique sur “X commits” au-dessus de la liste des fichiers).
  3. Un git push tout frais qui vient d’arriver sur GitHub.

À la prochaine !

« Maintenant ton code est en ligne. Mais qu’est-ce que tu mets dans un commit message ? Comment écrire un message qui sera encore clair dans trois mois ? Et comment travailler avec une équipe sans tout casser ? La prochaine fois : le côté professionnel de Git : les best practices que tous les développeurs utilisent. »

À emporter chez toi

  1. Facile : pushe un projet local existant vers un nouveau dépôt GitHub.
  2. Moyen : fais 3 commits en local, pushe-les, et vérifie sur GitHub qu’ils sont tous visibles.
  3. Difficile : clone un repo de GitHub, fais une modification, committe et pushe.
  4. Très difficile : simule un travail sur deux ordinateurs : clone un repo, fais un commit et pushe. Va dans un autre dossier, clone le même repo encore une fois (comme si c’était un autre ordinateur), fais un autre commit, et essaie de pusher. Que se passe-t-il ? Résous-le avec git pull.
30 octobre 2026, 15:59

Session 14 : Git Best Practices : écris des commits que tu comprendras encore plus tard

Tu sais taper des commandes Git. Ton code est sur GitHub. Mais il y a une différence entre « utiliser Git » et « bien utiliser Git ».

Cette session parle des habitudes que les développeurs expérimentés appliquent chaque jour. Pas de nouvelles commandes, mais des règles plus précises. À la fin, tu écriras des commit messages qui te serviront encore dans un an, et tu travailleras avec une stratégie de branching qui garde ton projet clair.

Ce que tu vas apprendre aujourd’hui

  • Comment écrire un commit message qui dit quelque chose
  • Trois règles simples pour le branching
  • Ce qu’est git stash et quand l’utiliser
  • La règle du pull avant le push

Partie 1 : Des commit messages qui disent quelque chose

Un mauvais commit message ressemble à ça :

git commit -m "fix"
git commit -m "update"
git commit -m "trucs modifiés"

Dans trois mois, tu regardes en arrière. C’était quoi « fix » ? Quels « trucs » ? Tu ne le sais plus. Tu dois fouiller dans le code pour retrouver ce qui s’est passé. C’est du temps perdu.

Le bon commit message : 3 parties

Un commit message professionnel a trois parties :

1. Un résumé court (72 caractères max)

Écris en anglais. Commence par un verbe au présent. Ça s’appelle l’« imperative mood » : comme si tu donnais un ordre à ta base de code. Pense : « Add », « Fix », « Remove », « Update », « Refactor ».

Add highscore tracking
Fix star spawning off-screen
Remove unused collision code

2. Une ligne vide

3. Une explication plus longue (optionnel, si c’est utile)

Add highscore tracking

Sauvegarde le meilleur score dans highscore.txt. Le score est
mis à jour après chaque game-over. Le fichier est créé s'il
n'existe pas encore.

Ça remplace l'ancienne méthode où le score restait seulement
en mémoire et se perdait à la fermeture du jeu.

L’explication détaillée raconte pourquoi tu as changé quelque chose, pas seulement quoi. Le code lui-même montre déjà le « quoi ». C’est le « pourquoi » dont tu auras besoin dans trois mois.

Les règles de commit message en un coup d’œil

À faireÀ ne pas faire
“Add player health bar”“added health bar thing”
“Fix collision detection on left wall”“fix”
“Remove debug print statements”“cleanup”
72 caractères max pour le titreUne histoire entière dans le titre
Présent, anglaisPassé (« added », « fixed »)

Pourquoi l’anglais ? Parce que presque tous les projets open source utilisent l’anglais. Le code est international. Ton code Python aussi, tu l’écris en anglais (def calculate_score). Tes commit messages suivent la même langue.

Pourquoi le présent ? Un commit décrit ce que cette modification fait, pas ce que toi tu as fait. « Add feature » (ce commit ajoute une feature), pas « Added feature » (j’ai ajouté une feature un jour). Git lui-même utilise le présent : Merge branch 'feature', pas Merged.

Des commits multi-lignes dans le terminal

Tu peux écrire un commit message sur plusieurs lignes en ne fermant pas les guillemets :

git commit -m "Add highscore tracking

Sauvegarde le meilleur score dans highscore.txt. Le fichier est
créé automatiquement au premier game-over."

Attention : tu ne tapes le guillemet fermant qu’à la dernière ligne. Tout ce qu’il y a entre les deux fait partie de ton message.

Quand est-ce que tu committes ?

Committe souvent. Committe petit.

Pas : trois heures de travail, un seul commit énorme avec 47 fichiers modifiés. Oui : un commit toutes les 15 à 30 minutes, chaque fois qu’un petit morceau logique est fini.

Règle de base : si ton commit message contient « et », ton commit est trop gros. « Add highscore tracking et fix menu bug et update sprites » → ça doit être trois commits séparés.

Des petits commits facilitent :

  • Comprendre ce qui a changé et quand
  • Annuler une modification précise sans casser le reste
  • Résoudre des merge conflicts (petits morceaux = moins de conflicts)

Partie 2 : Le branching : trois règles simples

Tu sais déjà comment créer des branches (session 12). Maintenant : quand et pourquoi.

Règle 1 : master marche toujours

La branche master, c’est ta vitrine. Quelqu’un qui clone ton repo doit pouvoir lancer ton code sans message d’erreur. master ne contient jamais du travail à moitié fini.

Pas ok sur master : du code avec # TODO: encore à finir, des fonctions en commentaire, des expériences que tu « répareras plus tard ».

Ok sur master : du code qui marche. Point.

Règle 2 : Une feature, une branche

Une branche fait exactement une chose. Pas plus.

  • Bien : feature/player-health-bar
  • Mauvais : feature/health-bar-and-menu-and-sound-effects

Si, en travaillant sur une feature, tu penses : « Oh, je peux aussi réparer ce bug de menu vite fait » : stop. Fais une nouvelle branche pour le bugfix. Merge-la d’abord. Ensuite, continue ta feature.

Règle 3 : Les branches ont une vie courte

Une branche qui existe depuis plus de quelques jours devient un problème. master change entre-temps, et ta branche prend du retard. Plus tu attends pour merger, plus le risque de merge conflicts augmente.

Merge ta branche dès que la feature est finie. Pour les petites choses (un bugfix de 10 minutes) : tu n’as peut-être même pas besoin d’une branche séparée.

Nommer les branches

Donne aux branches des noms que tu comprendras encore dans une semaine :

feature/highscore-tracking
bugfix/star-spawn-offscreen
experiment/particle-effects

Le préfixe (feature/, bugfix/, experiment/) dit tout de suite quel genre de travail se trouve dans cette branche. C’est une convention, pas une obligation technique, mais ça aide.

Partie 3 : Des commandes de workflow pratiques

git stash : mettre du travail de côté

Imagine : tu travailles sur une branche feature. Ton code est à moitié fini. Tu veux passer vite fait sur master pour un bugfix, mais tu ne veux pas committer ton travail à moitié fini. C’est pour ça que git stash existe :

git stash

Git garde toutes tes modifications de côté et remet ton working directory au dernier commit. Tu peux maintenant switcher, faire le bugfix, committer, et revenir :

git switch master
# ... faire le bugfix, committer ...
git switch feature-branch
git stash pop

git stash pop ramène tes modifications gardées de côté. Tout est de nouveau comme tu l’as laissé : à moitié fini, mais bien gardé.

git pull --rebase : un historique plus propre

Normalement, git pull fait un merge. Ça crée un commit de merge en plus. Parfois tu n’en veux pas ; tu veux une ligne droite de commits sans branches.

git pull --rebase

Ça récupère les derniers commits et met tes commits locaux par-dessus, comme si tu les avais faits après les commits du remote. Le résultat, c’est un historique linéaire : pas de merge-commits qui disent seulement « Merge branch ‘master’ ».

Attention : n’utilise --rebase que sur des branches que tu es seul à utiliser. Sur des branches partagées, un simple git pull (merge) est plus sûr.

La règle du pull avant le push

Avant de faire git push :

git pull

Toujours. Même si tu penses que personne d’autre n’a pushé. Ça prend une seconde et ça évite que GitHub refuse ton push avec « Updates were rejected because the remote contains work that you do not have locally. »

Cette règle compte surtout quand tu travailles à plusieurs. Si tu es le seul à travailler sur un repo, le risque est plus petit, mais l’habitude vaut de l’or.

Partie 4 : Le .gitignore qu’il te faut toujours

Chaque projet a des fichiers qui n’ont rien à faire dans Git. Ton .gitignore est ta première ligne de défense contre un mot de passe commité par accident.

.gitignore minimal pour un projet Python :

# Python
__pycache__/
*.pyc
*.pyo

# Environnement virtuel
venv/
.venv/

# Variables d'environnement (contiennent souvent des mots de passe/clés)
.env

# Ton éditeur
.vscode/
.idea/
*.swp
*.swo

# Fichiers du système
.DS_Store
Thumbs.db

Pourquoi ignorer __pycache__/ ? Ce sont des fichiers Python compilés que ton programme crée automatiquement. Ils sont différents selon la version de Python et selon l’ordinateur. Les mettre dans Git, ça ne fait que du bruit.

Pourquoi ignorer .env ? Les fichiers .env contiennent souvent des clés secrètes, des API keys, des mots de passe de base de données. Ceux-là ne doivent jamais, mais alors jamais, aller dans Git.

Showcase

Montre à un coach et à un buddy :

  1. Tes 5 derniers commits, avec de bons commit messages.
  2. Ton fichier .gitignore.
  3. Un nom de branche qui suit la convention du préfixe feature/.

À la prochaine !

« Maintenant tu travailles avec Git comme un pro. Mais il reste un concept que chaque équipe utilise : la pull request. Ton code est prêt, mais avant qu’il arrive dans master, quelqu’un d’autre doit l’approuver. Comment ça marche ? La prochaine fois : les pull requests, le mur de review par lequel chaque modification doit passer. »

À emporter chez toi

  1. Facile : réécris les commit messages de tes 5 derniers commits. Utilise les règles de cette session.
  2. Moyen : crée une branche avec le préfixe feature/, travaille dedans, merge-la et supprime-la. Fais pareil pour une branche bugfix/.
  3. Difficile : utilise git stash pour garder du travail à moitié fini, switch sur master, fais un fix rapide, push, et reviens sur ta feature avec git stash pop.
  4. Très difficile : crée une situation où git pull échoue (clone ton repo dans deux dossiers, fais un commit différent dans les deux, push le premier, et essaie de pusher le second). Résous-le : git pull, répare le merge conflict, et seulement après, pushe.
30 octobre 2026, 15:59

Session 15 : Pull Requests : la porte d'entrée de ton projet

Tu as construit une feature sur une branche. De bons commit messages, du travail propre. Maintenant tu veux mettre ton code dans master.

Tu pourrais faire git merge et c’est fini. Mais en équipe, ça ne marche pas. Quelqu’un d’autre doit d’abord regarder ton code : vérifier les erreurs, le style, les choses que tu as oubliées. Voilà ce qu’est une pull request.

Une pull request (PR) est une demande : « Récupère mes modifications. » Tu l’ouvres sur GitHub. Tes coéquipiers regardent ton code, donnent du feedback. Toi, tu modifies des choses. C’est seulement quand tout le monde est content que le code part vers master.

Dans cette session, tu fais ta première pull request. Tu reviewes celle d’un buddy. Et tu découvres ce que ça fait vraiment, le travail d’équipe avec Git.

Ce que tu vas apprendre aujourd’hui

  • Ce qu’est une pull request et pourquoi les équipes l’utilisent
  • Ouvrir une PR sur GitHub
  • Mettre à jour ta PR après du feedback
  • Reviewer la PR de quelqu’un d’autre
  • Merger une PR et nettoyer la branche

Étape 0 : Préparation : travailler en duo

Aujourd’hui, tu travailles avec un buddy. Décidez qui est l’auteur (celui qui construit la feature) et qui est le reviewer (celui qui regarde la PR). À la moitié, vous échangez.

L’auteur a besoin d’un repo GitHub auquel le reviewer a accès. La façon la plus simple :

  1. L’auteur crée un repo sur GitHub (public).
  2. L’auteur va dans Settings → Collaborators → Add people.
  3. L’auteur invite le reviewer avec son username GitHub.
  4. Le reviewer accepte l’invitation (par e-mail ou via les notifications GitHub).

Maintenant, vous pouvez tous les deux pusher vers le même repo.

Alternative (sans accès collaborator) : le reviewer forke le repo de l’auteur et ouvre une PR depuis le fork vers l’original. Mais aujourd’hui, on garde ça simple : accès collaborator direct.

Étape 1 : Créer et pusher une branche feature (auteur)

L’auteur clone le repo (si ce n’est pas encore fait) et crée une branche feature :

git clone https://github.com/AUTEUR_USERNAME/ons-samenwerk-project.git
cd ons-samenwerk-project
git switch -c feature/groet-functie

Crée un nouveau fichier :

echo 'def groet(naam):' > groet.py
echo '    return f"Hallo {naam}!"' >> groet.py

Committe et pushe :

git add groet.py
git commit -m "Add groet function

Retourne une salutation pour le nom donné."
git push -u origin feature/groet-functie

Étape 2 : Ouvrir une pull request (auteur)

  1. Va sur ton repo sur GitHub.
  2. GitHub affiche maintenant une barre jaune : « feature/groet-functie had recent pushes » : clique sur Compare & pull request. (Si tu ne vois pas la barre : clique sur l’onglet Pull requests, puis New pull request, choisis base: master ← compare: feature/groet-functie.)
  3. Écris un titre clair : « Add groet function »
  4. Écris une description. Une bonne description de PR a trois parties :
## Quoi

Une fonction `groet(naam)` qui retourne une salutation.

## Pourquoi

On a besoin d'une salutation réutilisable pour
l'interface utilisateur. Ça évite de devoir écrire
la même string à plusieurs endroits.

## Comment tester

```python
from groet import groet
print(groet("CoderDojo"))  # "Hallo CoderDojo!"
5. Clique sur **Create pull request**.

Ta PR est maintenant ouverte. Toute personne qui a accès au repo peut la voir. GitHub montre le diff : exactement quelles lignes tu as ajoutées (en vert) et supprimées (en rouge).

## Étape 3 : Reviewer une PR (reviewer)

Le reviewer ouvre la PR sur GitHub. Voici les étapes d'une review :

### 1. Lis la description

Tu comprends ce que fait cette PR ? Si non, demande des explications.

### 2. Regarde le diff

Clique sur l'onglet **Files changed**. GitHub montre chaque ligne modifiée. Regarde :

- **Est-ce que le code marche ?** Est-ce que tu le lancerais toi-même si tu le clonais ?
- **Est-ce que le style est cohérent ?** Les mêmes conventions de nommage que le reste du projet ?
- **Est-ce qu'il y a des erreurs ?** Des typos, des imports manquants, des erreurs de logique ?
- **Est-ce qu'il n'y a pas de secrets dedans ?** Des mots de passe, des API keys, des tokens ?
- **Est-ce que c'est compréhensible ?** Quelqu'un qui voit ce code pour la première fois peut-il suivre ce qui se passe ?

### 3. Donne du feedback

Clique sur une ligne pour ajouter un comment. Sois précis :

**Du bon feedback :**
> Dans `groet.py` ligne 2 : que se passe-t-il si `naam` est vide ? Peut-être ajouter une valeur par défaut ?

**Du mauvais feedback :**
> Ce n'est pas bon.

### 4. Envoie ta review

Clique sur **Review changes**. Tu as trois options :

- **Comment** : juste du feedback, pas de décision.
- **Approve** : le code est bon, il peut être mergé.
- **Request changes** : il faut changer quelque chose avant que la PR puisse être mergée.

Pour ta première review : choisis **Approve** si tout a l'air bon, ou **Request changes** si tu veux faire changer quelque chose.

## Étape 4 : Traiter le feedback (auteur)

Le reviewer a laissé un comment. L'auteur modifie le code :

```bash
# Vérifie que tu es bien sur ta branche feature
git switch feature/groet-functie

Modifie groet.py sur base du feedback. Par exemple :

def groet(naam="wereld"):
    return f"Hallo {naam}!"

Committe et pushe :

git add groet.py
git commit -m "Add default parameter to groet function"
git push

Le nouveau commit apparaît automatiquement dans la PR. Le reviewer voit la mise à jour et peut regarder à nouveau.

Étape 5 : Merger et nettoyer

Si le reviewer a mis Approved, il est temps de merger.

Sur GitHub, dans la PR, tu cliques sur Merge pull request. Choisis Create a merge commit (l’option par défaut). Clique sur Confirm merge.

La branche feature est maintenant fusionnée avec master. Sur GitHub, tu peux supprimer la branche avec le bouton Delete branch qui apparaît après le merge.

En local, tu dois aussi nettoyer :

git switch master
git pull                      # récupère le merge qui vient d'avoir lieu sur GitHub
git branch -d feature/groet-functie   # supprime la branche locale

Ton master est maintenant up-to-date. Ta branche feature a disparu, en local et sur GitHub. Prêt pour le prochain morceau de travail.

Le workflow PR complet en un coup d’œil

1. git switch -c feature/iets        ← Crée une branche feature
2. Travaille, committe, travaille, committe
3. git push -u origin feature/iets   ← Push vers GitHub
4. Ouvre une PR sur GitHub           ← Demande une review
5. Le reviewer regarde, donne du feedback
6. Modifie le code, committe, pushe  ← Traite le feedback
7. Le reviewer a approuvé
8. Merge la PR sur GitHub            ← Le code part vers master
9. git switch master && git pull       ← Récupère master en local
10. git branch -d feature/iets       ← Nettoie la branche

Reviewer la PR de quelqu’un d’autre : comment bien faire ?

Une review, ce n’est pas : « Ça a l’air bon. » Une bonne review est précise, constructive et respectueuse.

Les questions que tu te poses pendant une review :

  • Est-ce que je comprends ce que fait ce code ? (Si non : demande de meilleurs comments ou une description plus claire.)
  • Est-ce que le code fait ce que promet la description de la PR ?
  • Est-ce que ça peut être plus simple ?
  • Est-ce qu’il manque quelque chose ? (Gestion des erreurs, edge cases, documentation)
  • Est-ce qu’il y a des secrets, des mots de passe ou des données personnelles dedans ?
  • Est-ce que le code suit le style du reste du projet ?

Comment donner du feedback :

Commence par ce qui est bien. Sois ensuite précis sur ce qui peut être mieux. Termine par une conclusion claire.

Exemple :

La fonction marche exactement comme décrit. Deux suggestions :

  1. À la ligne 2 : une valeur par défaut pour naam serait pratique.
  2. Pense à ajouter une docstring qui explique ce que la fonction retourne.

Pour le reste, ça a l’air bon. Si tu changes ces deux choses, je l’approuve avec plaisir.

Showcase

Échange ton rôle avec ton buddy et refais tout le workflow une fois : maintenant, c’est toi le reviewer.

Montre à un coach :

  1. Une pull request ouverte sur GitHub avec une description.
  2. Au moins un comment de review sur une PR de ton buddy.
  3. Une PR mergée avec succès : le code de la feature est maintenant sur master.

À la prochaine !

C’était la dernière session Git. Ce que tu sais faire maintenant :

  • Gérer les versions de ton code avec Git (init, add, commit, log, diff)
  • Expérimenter sur des branches sans casser master (branch, switch, merge)
  • Partager ton code en ligne via GitHub (push, pull, clone)
  • Écrire des commit messages professionnels
  • Travailler à plusieurs via des pull requests : en ouvrir et en reviewer

Ce n’est pas « en plus ». C’est comme ça que les développeurs travaillent chaque jour. Que tu fasses des jeux, des sites web ou de l’IA : Git et GitHub sont les outils qui gardent ton projet sous contrôle. Utilise-les.

À emporter chez toi

  1. Facile : ouvre une pull request pour une modification dans un de tes propres projets.
  2. Moyen : demande à un ami ou à un membre de ta famille de créer un compte GitHub. Invite-le comme collaborator et laisse-le reviewer une PR.
  3. Difficile : contribue à un vrai projet open source. Cherche sur GitHub des issues avec le label good first issue. Forke le repo, fais un fix et ouvre une PR.
  4. Très difficile : construis un petit projet avec deux autres personnes. Utilise des branches, des pull requests et des reviews. Travaille comme si tu étais dans une équipe professionnelle.
30 octobre 2026, 15:59

Session 16 : Markdown : écris des notes qui ressemblent au web

Tu connais peut-être HTML par internet : <h1>, <p>, <a>. Mais pour des notes et de la documentation, HTML demande beaucoup trop de frappe. C’est pour ça que Markdown existe.

Markdown est un mini-langage que tu écris en texte normal. Ça reste lisible sans devoir d’abord le convertir. Et d’une seule pression sur un bouton, ça devient du HTML propre : des titres, des listes, des liens, des tableaux.

Dans cette session, tu apprends toute la base de Markdown. À la fin, tu écriras des notes qui ont l’air professionnelles, sur GitHub, dans Obsidian, ou dans n’importe quel autre programme qui comprend Markdown.

Ce que tu vas apprendre aujourd’hui

  • Faire des titres et des paragraphes
  • Mettre en forme du texte : gras, italique, barré
  • Les listes et les énumérations
  • Des liens vers d’autres pages et des sites web
  • Insérer des images
  • Faire des tableaux
  • Des lignes horizontales et des blocs de code

Pourquoi Markdown ?

Markdown est partout :

  • GitHub : chaque repo a un README.md en Markdown. Les issues, les pull requests, les wikis : tout est en Markdown.
  • Obsidian, Joplin, Logseq : des applis de notes qui enregistrent tes documents comme fichiers .md.
  • Discord, Slack, Reddit : ils supportent Markdown pour mettre en forme vite fait tes messages.
  • Hugo (ce site !) : toutes les pages de session que tu vois ici sont écrites en Markdown.
  • Jupyter Notebooks : les cellules de texte sont en Markdown.

Le grand avantage : tu écris du texte normal. Pas de tags compliqués. Et le résultat reste toujours lisible, même en texte brut.

Étape 0 : Créer un fichier Markdown

Les fichiers Markdown se terminent par .md. Crée-en un :

mkdir mijn-notities
cd mijn-notities
echo "# Ma première note" > test.md

Tu peux ouvrir des fichiers .md dans n’importe quel éditeur de texte : le Bloc-notes, VS Code, Thonny, Obsidian. VS Code a une preview intégrée : clique en haut à droite sur l’icône avec la loupe et le livre.

Étape 1 : Titres et paragraphes

Tu fais des titres avec #. Plus il y a de #, plus le titre est petit :

# Ceci est un titre (h1)

## Ceci est un sous-titre (h2)

### Ceci est un titre plus petit (h3)

#### Encore plus petit (h4)

Tu fais un paragraphe en tapant simplement du texte. Une ligne vide entre les deux commence un nouveau paragraphe :

Ceci est le premier paragraphe. Il continue comme ça.

Ceci est le deuxième paragraphe. Parce qu'il y a une ligne vide entre les deux.

Astuce : tu n’utilises # qu’une seule fois par document : pour le titre. Le reste commence à ##.

Étape 2 : Mettre en forme du texte

**Ceci est en gras**

*Ceci est en italique*

~~Ceci est barré~~

Tu peux aussi **mettre du *gras* et de l'italique ensemble** dans la même phrase.

Le résultat :

  • **gras** devient gras
  • *italique* devient italique
  • ~~barré~~ devient barré

Attention : pas d’espaces entre les astérisques et le texte. ** gras ** ne marche pas. **gras** oui.

Certains éditeurs acceptent aussi les underscores : __gras__ et _italique_. Mais les astérisques sont le standard : utilise-les.

Étape 3 : Lignes horizontales

Tu fais une ligne horizontale avec trois tirets (ou plus) :

---

Ou avec des astérisques :

***

Le résultat est une ligne sur toute la largeur. Utilise-le avec parcimonie : une ou deux par document, c’est assez. Trop de lignes rendent tes notes brouillonnes.

Étape 4 : Listes

Liste non numérotée

Utilise -, * ou + :

- Python
- Git
- Markdown
- GitHub

Tu peux imbriquer des listes en indentant (2 ou 4 espaces) :

- Langages de programmation
  - Python
  - JavaScript
- Gestion de versions
  - Git
  - GitHub

Liste numérotée

1. Ouvre Thonny
2. Écris ton code
3. Clique sur Run

Peu importe les numéros que tu tapes : Markdown numérote automatiquement. Ceci :

1. Étape un
1. Étape deux
1. Étape trois

…donne exactement le même résultat que 1, 2, 3. Pratique si tu veux ajouter une étape plus tard sans tout renuméroter.

Checklist (style GitHub)

- [x] Installer Git
- [x] Faire ton premier commit
- [ ] Apprendre les branches
- [ ] Ouvrir une pull request

[x] est coché, [ ] est ouvert. Ça marche dans les issues GitHub, les pull requests, et beaucoup d’applis de notes.

Étape 5 : Liens

Liens externes (vers des sites web)

[clique ici pour le site CoderDojo](https://python.coderdojohasselt.be)

Le mot entre [ ] est le texte cliquable. L’URL entre ( ) est la destination.

Liens internes (vers d’autres pages de ton projet)

[Voir la session 11](11-git-intro/)

Ça fait un lien vers le fichier 11-git-intro/_index.md dans le même dossier.

Lien rapide (montre l’URL directement)

<https://github.com>

Ça montre l’URL comme lien cliquable, sans texte séparé.

Étape 6 : Images

Une image, c’est presque la même chose qu’un lien, mais avec un ! devant :

![Une étoile dans Pygame Zero](/sessions/01-catch-the-stars/coordinaten.svg)

Le texte entre [ ] est le texte alt : il apparaît si l’image ne charge pas, ou il est lu par les screen readers.

Images et Git : Les petites images (SVG, petits PNG), tu peux les mettre dans Git. Les grosses images (>1 MB) et les vidéos, mieux vaut éviter, parce qu’elles ralentissent ton repo.

Étape 7 : Tableaux

| Commande | Ce qu'elle fait |
|----------|-------------|
| `git init` | Créer un nouveau dépôt |
| `git add` | Préparer des fichiers pour le commit |
| `git commit` | Enregistrer les modifications |
| `git push` | Envoyer les commits vers GitHub |

Les caractères | forment les colonnes. La ligne --- sépare l’en-tête des données. Le : dans la ligne de séparation détermine l’alignement :

| Aligné à gauche | Centré | Aligné à droite |
|:-----------------|:-----------:|------------------:|
| gauche           | milieu      | droite            |

Étape 8 : Code et blocs de code

Code inline

Utilise des backticks pour de courts bouts de code dans une phrase :

Utilise `git status` pour voir ce qui a changé.

Blocs de code

Pour plusieurs lignes de code, tu utilises trois backticks :

```python
def groet(naam):
    return f"Hallo {naam}!"
```

La langue (python) derrière les premiers backticks donne du syntax highlighting. Ça marche pour des dizaines de langues : bash, html, css, javascript, json, yaml, markdown.

Bloc de code sans langue

```
Ceci est juste du texte
sans syntax highlighting
```

Étape 9 : Blockquotes

Utilise > pour des citations ou des remarques importantes :

> Git n'est pas un back-up. Git est une machine à remonter le temps.
> Quelqu'un sur internet

Plusieurs lignes > à la suite forment un seul bloc. Une ligne > vide commence un nouveau paragraphe à l’intérieur de la citation.

Étape 10 : Tout ensemble : un vrai README

Un bon README.md combine tout ce que tu connais maintenant. Voici un exemple :

# Mon projet

Une courte description de ce que fait ce projet.

## Installation

```bash
git clone https://github.com/jouw-naam/mijn-project.git
cd mijn-project
```

## Utilisation

1. Ouvre `main.py` dans Thonny.
2. Clique sur **Run**.
3. Choisis un niveau et démarre.

## Ce que tu apprends

- [x] Bases de Pygame Zero
- [x] Collision detection
- [ ] Système de highscore
- [ ] Effets sonores

## Liens

- [CoderDojo Hasselt](https://coderdojohasselt.be)
- [Code source sur GitHub](https://github.com/jouw-naam/mijn-project)

Cheatsheet

QuoiMarkdown
Titre niveau 1# Titre
Titre niveau 2## Sous-titre
Titre niveau 3### Titre plus petit
Gras**gras**
Italique*italique*
Barré~~barré~~
Ligne horizontale--- ou ***
Liste (non ordonnée)- item
Liste (numérotée)1. item
Checklist- [ ] item ouvert
Lien[texte](url)
Image![texte alt](url)
Code inline`code`
Bloc de code```langue
Citation> citation
Tableau| colonne | colonne |

Showcase

Montre à un coach et à un buddy :

  1. Un document Markdown avec au moins un titre, une liste, un lien et du texte en gras.
  2. Un tableau avec au moins deux colonnes et trois lignes.
  3. Une checklist avec des items cochés et des items ouverts.

À la prochaine !

Markdown est simple, mais il est partout. Tes README sur GitHub, tes notes dans Obsidian, ta documentation : tout devient plus lisible avec Markdown. Utilise-le. N’en fais pas trop avec la mise en forme. De bonnes notes sont claires, pas chargées.

À emporter chez toi

  1. Facile : écris un README.md pour ton projet Python préféré. Utilise des titres, une liste et un bloc de code.
  2. Moyen : fais une note dans Obsidian (ou un autre éditeur Markdown) sur ce que tu as appris ce mois-ci. Utilise toute la mise en forme du cheatsheet au moins une fois.
  3. Difficile : construis une page « cheatsheet » en Markdown pour un sujet de ton choix (commandes Git, syntaxe Python, formules de maths). Utilise des tableaux et des listes imbriquées.
  4. Très difficile : fais un document Markdown avec une liste imbriquée qui va au moins sur trois niveaux de profondeur, un tableau avec de l’alignement, et un bloc de code avec du syntax highlighting.
30 octobre 2026, 15:59

Défis supplémentaires

Tu as terminé les dix sessions. Ici, tu trouves des jeux classiques à reconstruire toi-même. Pas de guide pas à pas, juste quelques repères et un fichier de départ. Écris le code toi-même. Jusqu’où vas-tu ?

Défis

  • Snake : Session 5 et plus. Grandis le plus longtemps possible. Mange des fruits, évite les murs et toi-même.
  • Space Invaders : Session 7 et plus. Abats la formation d’aliens avant qu’ils atterrissent.
30 octobre 2026, 15:59

Sous-sections de Défis supplémentaires

Snake

Remarque

Requis : session 5 terminée.

Le serpent avance tout seul. Toi, tu le diriges avec les flèches. Mange un fruit : le serpent grandit d’une case. Touche le mur ou toi-même : game over.

Démarrage

Télécharge le code de départ et décompresse le ZIP. Ouvre main.py dans Thonny et clique sur Run. Tu vois une grille vide. Les commandes et le chronométrage sont déjà en place. C’est toi qui remplis les fonctions nieuw_fruit(), zet_stap() et teken().

Comment ça marche ?

Snake se joue sur une grille. Le serpent est une liste de coordonnées (kolom, rij). À chaque pas, tu ajoutes une nouvelle tête à l’avant de la liste et tu supprimes le dernier élément. Si le serpent mange un fruit, tu laisses le dernier élément en place : c’est comme ça qu’il grandit.

TILE = 20          # taille d'une case en pixels
COLS = WIDTH // TILE
ROWS = HEIGHT // TILE

slang = [(10, 10), (9, 10), (8, 10)]  # liste de (kolom, rij)
dx, dy = 1, 0                          # direction : 1 pas vers la droite

Charger et redimensionner des images

Les images de fruits font 64×64 pixels. C’est trop grand pour une case de 20×20. Tu les charges avec pygame.image.load() et tu les redimensionnes ensuite avec pygame.transform.scale(). Tout ça est déjà écrit dans le code de départ.

surf = pygame.image.load('images/apple.png').convert_alpha()
fruit_images['apple'] = pygame.transform.scale(surf, (TILE, TILE))

convert_alpha() fait en sorte que la transparence de l’image fonctionne correctement. pygame.transform.scale() renvoie une nouvelle Surface à la taille demandée. L’original ne change pas.

Pour afficher une image redimensionnée à l’écran, tu utilises screen.blit() :

screen.blit(fruit_surf, (fruit_pos[0] * TILE, fruit_pos[1] * TILE))

✅ Basic

  • Remplis nieuw_fruit() : choisis un fruit au hasard, cherche une case libre et enregistre la position et la Surface.
  • Remplis zet_stap() : calcule la nouvelle tête, ajoute-la à l’avant de la liste, supprime le dernier élément.
  • Remplis teken() : dessine la grille (pygame.draw.line), le fruit (screen.blit) et chaque anneau du serpent (pygame.draw.circle). Affiche le score avec font.render() et screen.blit().
  • Fais apparaître un fruit quand le serpent en mange un : saute slang.pop() et appelle nieuw_fruit().

⭐ Stretch

  • Game over si la tête sort de la grille.
  • Game over si la tête touche un de ses propres segments (nieuw_hoofd in slang[1:]).
  • Affiche un écran de game over avec le score. Appuie sur R pour recommencer.

🔥 Expert

  • Augmente la vitesse à mesure que le score monte : baisse STAP_MS selon le score (max(60, BASISINTERVAL - score * 10)).
  • Enregistre le meilleur score et affiche-le à côté du score actuel, même après un redémarrage.
  • Fais en sorte qu’un fruit ne puisse jamais apparaître sur une case déjà occupée par le serpent.

Téléchargements

  • Code de départ : main.py avec les commandes et le chronométrage prêts ; c’est toi qui remplis les fonctions.
  • Images de fruits : si tu commences sans le code de départ (déjà inclus dans le ZIP de départ).

Fruits : Kenney Food Kit, CC0 (domaine public). kenney.nl

30 octobre 2026, 15:59

Space Invaders

Remarque

Requis : session 7 terminée.

Les aliens sont en formation de 4×9. Ils vont et viennent, descendent d’un cran à chaque bord et tirent au hasard en retour. Toi, tu as un seul vaisseau et trois vies. Abats-les tous avant qu’ils n’atterrissent.

Démarrage

Télécharge le code de départ et décompresse le ZIP. Ouvre main.py dans Thonny et clique sur Run. Tu vois le vaisseau et la formation d’aliens. Les commandes et les images sont déjà en place. C’est toi qui remplis le déplacement, les tirs et les collisions.

Comment ça marche ?

Tous les aliens sont des objets pygame.Rect dans une seule liste. À chaque frame, tu les déplaces tous du même nombre de pixels. Si la formation touche un bord, tu inverses la direction et tu fais descendre chaque alien de ALIEN_VAL pixels.

for alien in aliens:
    alien.x += snelheid * alien_richting

rechts = max(a.right for a in aliens)
links  = min(a.left  for a in aliens)
if rechts >= BREEDTE or links <= 0:
    alien_richting *= -1
    for alien in aliens:
        alien.y += ALIEN_VAL

Les projectiles sont aussi des objets pygame.Rect. Les projectiles du joueur montent (k.y -= KOGEL_SNL), ceux des aliens descendent (k.y += ALIEN_SNL). Tu vérifies les collisions avec k.colliderect(alien).

✅ Basic

  • Dessine l’arrière-plan (utilise random.seed(42) pour des étoiles fixes), le vaisseau et tous les aliens.
  • Déplace le vaisseau à gauche et à droite avec les flèches.
  • Fais aller et venir la formation et descends d’un cran quand elle touche un bord.
  • Tire un projectile vers le haut quand le joueur appuie sur espace. Utilise COOLDOWN_MS pour éviter de tirer à toute vitesse.

⭐ Stretch

  • Le projectile du joueur touche un alien : supprime les deux, score += 10.
  • Chaque alien tire au hasard en retour : if random.random() < SCHIET_KANS.
  • Un projectile alien touche le joueur : levens -= 1, à 0 vie → game over.
  • Affiche le score et les vies en haut à gauche.

🔥 Expert

  • La formation accélère à mesure qu’il reste moins d’aliens : 1 + 3 * (1 - restant). De 1 pixel/frame au début à 4 pixels/frame avec le dernier alien.
  • Game over si un alien atteint le bas (alien.bottom >= HOOGTE - 50).
  • Game over (gagné) si la liste est vide.
  • Redémarrage avec R : réinitialise toutes les variables avec une fonction reset().

Téléchargements

  • Code de départ : main.py avec la fenêtre, les images et la grille d’aliens prêtes ; c’est toi qui remplis la logique.
  • Images : ship.png, enemy.png et laser.png si tu commences sans le code de départ.

Images : Kenney Space Shooter Redux, CC0 (domaine public). kenney.nl

30 octobre 2026, 15:59

Pac-Man

Remarque

Requis : session 9 terminée.

Un labyrinthe de murs bleus. Des points blancs partout. Quatre fantômes colorés qui viennent vers toi. Mange tous les points pour gagner. Touche un fantôme et c’est game over.

Démarrage

Télécharge le code de départ et décompresse le ZIP. Ouvre main.py dans Thonny et clique sur Run. Le labyrinthe apparaît et Pac-Man est prêt. C’est toi qui ajoutes le déplacement, les collisions et les fantômes.

Comment ça marche ?

Pac-Man se déplace en pixels, pas en cases. À chaque frame, il avance de snelheid × dt pixels dans sa direction. dt est le temps (en secondes) qu’a duré la frame précédente. Comme ça, le jeu avance à la même vitesse sur un ordinateur lent et sur un ordinateur rapide.

nieuw_x = self.rect.x + self.dx * PACMAN_SNL * dt

Tu vérifies la collision avec un mur en créant un rect de test à la nouvelle position et en regardant s’il chevauche un bloc de mur :

test = self.rect.copy()
test.x = nieuw_x
test.y = nieuw_y
botsing = any(test.colliderect(m.rect) for m in muren)

✅ Basic

  • Fais avancer Pac-Man dans sa direction actuelle (les flèches sont déjà prêtes).
  • Ajoute la collision avec les murs : arrête-toi si la nouvelle position touche un mur.
  • Fais fonctionner le changement de direction : ne passe à la nouvelle direction que si elle est libre.

⭐ Stretch

  • Mange les points blancs : si Pac-Man touche un point, supprime-le et compte 10 points.
  • Mange les points jaunes de power : supprime, compte 50 points et mets self.powered_up = True.
  • Gagne quand tous les points sont mangés : mets self.staat = GEWONNEN.

🔥 Expert

  • Fais bouger les fantômes : essaie des directions et choisis-en une libre (sans collision avec un mur).
  • Fais poursuivre Pac-Man par les fantômes : choisis la direction qui réduit la distance à Pac-Man.
  • Si un fantôme touche Pac-Man et que powered_up vaut False : game over.
  • Si un fantôme touche Pac-Man et que powered_up vaut True : mange le fantôme (+200 points).

Téléchargements

  • Code de départ : main.py + les fichiers de sons ; c’est toi qui remplis le déplacement et les collisions.
30 octobre 2026, 15:59

Frogger

Remarque

Requis : session 5 (Breakout) terminée.

Une grenouille veut atteindre l’autre rive. Pour ça, elle doit traverser une route chargée et une rivière dangereuse. Les voitures roulent sur trois voies, des rondins flottent sur l’eau. Un faux pas et c’est fini.

Démarrage

Télécharge le code de départ et décompresse le ZIP. Ouvre main.py dans Thonny et clique sur Run. Tu vois le terrain de jeu mais la grenouille ne bouge pas encore. C’est toi qui remplis les fonctions.

Comment ça marche ?

L’écran est divisé en voies horizontales de 40 pixels :

  • En haut : 5 étangs où la grenouille doit arriver sans encombre
  • Rivière (3 voies) : des rondins passent en flottant. Sur un rondin, tu es en sécurité ; dans l’eau, tu te noies.
  • Berge en herbe : un coin tranquille au milieu
  • Route (3 voies) : les voitures roulent dans les deux sens. Être touché = mort.
  • En bas : position de départ de la grenouille
TEGEL = 40
KOLOMMEN, RIJEN = 13, 14

# Voies : (rij, richting, snelheid)
AUTO_BANEN = [
    (6,  1, 2),   # à droite, lent
    (7, -1, 4),   # à gauche, rapide
    (8,  1, 3),   # à droite, moyen
]

Les voitures et les rondins sont des objets pygame.Rect dans une liste. À chaque frame, tu les déplaces tous et tu les supprimes quand ils sortent de l’écran.

La grenouille se déplace par pas fixes de TEGEL pixels. Appuie sur une flèche et la grenouille saute d’une case dans cette direction.

Tu vérifies les collisions avec rect.colliderect(andere_rect).

✅ Basic

  • Déplacer la grenouille : intercepte les flèches dans KEYDOWN et adapte kikker.x et kikker.y avec TEGEL.
  • Faire apparaître les voitures : remplis spawn_auto(). Choisis une voie au hasard, crée un Rect juste en dehors de l’écran, ajoute-le à auto_lijst.
  • Bouger les voitures : dans update() : décale chaque voiture avec rect.x += richting * snelheid. Supprime les voitures sorties de l’écran. Garde au moins 6 voitures.
  • Faire apparaître les rondins : remplis spawn_hout(). Même principe, mais avec HOUT_BANEN et une largeur plus grande.
  • Bouger les rondins : dans update() : décale et supprime comme pour les voitures. Garde au moins 4 rondins.
  • Collision avec une voiture : si kikker.colliderect(auto) : appelle sterf().
  • Noyade : si la grenouille est dans la rivière (ligne 2, 3 ou 4) et pas sur un rondin : sterf().
  • Vérification des étangs : si la grenouille est près d’un étang vide : mets huizen_gevuld[i] = True, score += 10, réinitialise la grenouille. 5 étangs remplis = gagné.

C’est bon ? Tu as un Frogger qui fonctionne !

⭐ Stretch

  • Compteur de vies : le système de levens est déjà prêt. Fais en sorte que le jeu s’arrête si levens <= 0 et affiche « GAME OVER ».
  • Chronomètre : ajoute un chronomètre. Commence avec 30 secondes par niveau. Si le chronomètre arrive à zéro, tu perds une vie. Affiche le chronomètre dans le HUD. Chaque étang rempli te donne 5 secondes de plus.
  • Difficulté : augmente la vitesse des voitures et des rondins à mesure que le score monte (snelheid = basis + score // 50).

🔥 Expert

  • Mouche bonus : un insecte vert apparaît au hasard sur la carte et se déplace. Attrape-le pour 20 points bonus. Fais-le disparaître après 5 secondes.
  • High score : enregistre le meilleur score dans une variable high_score. Affiche-le à côté du score actuel. Mets-le à jour quand le joueur bat un nouveau record.
  • Véhicules différents : ajoute des camions (2 cases de large, plus lents) et des motos (1 case, plus rapides). Utilise une liste séparée ou un champ type.
  • Animation : fais clignoter la grenouille un instant quand elle meurt (dood_timer est déjà prêt). Dessine un petit plouf quand la grenouille se noie.

Téléchargements

  • Code de départ : main.py avec le terrain de jeu, la grenouille et tout le code de dessin prêts ; c’est toi qui remplis la logique.

Inspiré du classique Frogger (1981, Konami). Dessins avec pygame.draw.

30 octobre 2026, 15:59

Dojo Defender

Dojo Defender, c’est notre jeu maison : un survival shooter top-down qu’on construit ensemble sur plusieurs sessions.

Pour qui ?

Dojo Defender est pour les ninjas qui viennent régulièrement. Le jeu grandit sur 7 sessions, en même temps que les leçons normales. Tu ne viens qu’occasionnellement ? Pas de problème : fais le mini-jeu de cette session. Il est toujours complet en soi.

Ne compte pas sur un Dojo Defender complet si tu manques beaucoup de sessions. Mais le modèle et tous les snapshots sont sur ce site, donc tu peux toujours continuer à la maison.

Comment je participe ?

  • À partir de la leçon 2, tu reçois à la fin de chaque leçon un snapshot Dojo Defender : un fichier ZIP que tu peux télécharger depuis la page de la leçon.
  • Décompresse-le, ouvre-le dans Thonny, et la leçon suivante tu continues avec ça.
  • Tu manques une leçon ? Télécharge le snapshot de cette leçon, ou saute une leçon et reprends plus loin.

Je peux en faire mon propre truc ?

Oui ! Change le nom, le style graphique, l’histoire. Dojo Defender est un modèle, pas une obligation.

30 octobre 2026, 15:59

Sous-sections de Dojo Defender

Dojo Defender : Session 1

Ton vaisseau spatial a atterri dans l’espace sombre. Il est temps de le faire vivre. Dans cette session, tu ajoutes un vaisseau que tu contrôles et tu fais tomber des astéroïdes. Évite-les ou perds une vie. Combien de temps tu survis ?

Ce que tu vas apprendre aujourd’hui

  • Utiliser des listes pour garder plusieurs astéroïdes
  • Spawner des objets et les supprimer
  • Détecter des collisions avec colliderect
  • Tenir les vies à jour et afficher un effet d’explosion
  • Forcer le game over quand tes vies sont épuisées

Étape 0 : Installation

  1. Ouvre Thonny.
  2. Télécharge le starter Dojo Defender, décompresse le ZIP et ouvre main.py.
  3. Clique sur Run. Tu vois un écran bleu foncé avec ton vaisseau spatial en bas. Tu sais déjà le déplacer avec les flèches.
  4. Des problèmes ? Va voir Installer Thonny.

Étape 1 : Fais apparaître des astéroïdes

Un jeu sans danger, c’est ennuyeux. Ajoute une liste qui garde tous les astéroïdes, et une fonction qui crée de nouveaux astéroïdes :

# en haut, après WIDTH et HEIGHT :
asteroids = []

def spawn_asteroid():
    rock = Actor('asteroid_big')
    rock.x = random.randint(30, WIDTH - 30)
    rock.y = -30
    rock.speed = random.uniform(3, 5)
    asteroids.append(rock)

Tu as aussi besoin de import random en haut du fichier. Ajoute cette ligne.

Appelle la fonction dans update() avec un compteur pour qu’un astéroïde n’apparaisse pas à chaque frame :

# en haut, en dehors des fonctions :
timer = 0

def update():
    global timer
    timer += 1
    if timer % 60 == 0:   # chaque seconde (60 frames)
        spawn_asteroid()

Mets ça avant le code de mouvement du vaisseau.

Étape 2 : ✅ Basic : faire tomber les astéroïdes et les dessiner

Les astéroïdes doivent tomber vers le bas et disparaître quand ils sortent de l’écran :

def update():
    global timer
    timer += 1
    if timer % 60 == 0:
        spawn_asteroid()

    for rock in asteroids[:]:      # [:] = une copie pour supprimer sans risque
        rock.y += rock.speed
        if rock.y > HEIGHT + 30:
            asteroids.remove(rock)

N’oublie pas de dessiner les astéroïdes dans draw() :

def draw():
    screen.fill((10, 10, 30))
    for rock in asteroids:
        rock.draw()
    ship.draw()

Étape 3 : ⭐ Stretch : collision + vies

Quand un astéroïde touche ton vaisseau, tu perds une vie. Ajoute lives et game_over en haut :

lives = 3
game_over = False

Ajoute la détection de collision dans la boucle for :

    for rock in asteroids[:]:
        rock.y += rock.speed

        if rock.y > HEIGHT + 30:
            asteroids.remove(rock)
        elif rock.colliderect(ship):
            asteroids.remove(rock)
            global lives, game_over
            lives -= 1
            if lives <= 0:
                game_over = True

Affiche les vies et le score dans draw() :

    screen.draw.text(f"Score : {score}", (10, 10), color="white", fontsize=24)
    screen.draw.text(f"Vies : {lives}", (10, 40), color="red", fontsize=24)

Arrête le jeu quand game_over est True :

def update():
    if game_over:
        return
    ...

Affiche un écran de game over dans draw() :

    if game_over:
        screen.draw.text(
            "GAME OVER",
            center=(WIDTH / 2, HEIGHT / 2),
            color="red",
            fontsize=60,
        )
        screen.draw.text(
            f"Score final : {score}",
            center=(WIDTH / 2, HEIGHT / 2 + 60),
            color="white",
            fontsize=30,
        )

Étape 4 : 🔥 Expert : explosions + invisibilité

Quand un astéroïde te touche, tu veux voir une explosion au lieu de voir le vaisseau disparaître comme ça. Utilise les quatre frames d’explosion (explosion_1 à explosion_4) :

explosion = Actor('explosion_1')
explosion_active = False
explosion_frame = 0
explosion_timer = 0

En cas de collision : cache le vaisseau, lance l’explosion :

        elif rock.colliderect(ship):
            asteroids.remove(rock)
            global lives, game_over, explosion_active, explosion_frame, explosion_timer
            lives -= 1

            explosion.pos = (ship.x, ship.y)
            explosion.image = 'explosion_1'
            explosion_frame = 1
            explosion_timer = 5
            explosion_active = True
            ship.visible = False

            if lives <= 0:
                game_over = True

Fais jouer l’explosion dans update() :

    if explosion_active:
        explosion_timer -= 1
        if explosion_timer <= 0:
            explosion_frame += 1
            if explosion_frame > 4:
                explosion_active = False
                ship.visible = True
                ship.pos = (WIDTH / 2, HEIGHT - 50)
            else:
                explosion.image = f'explosion_{explosion_frame}'
                explosion_timer = 5

Ajoute ensuite une période d’invisibilité pour ne pas être touché à nouveau tout de suite :

invincible = False
invincible_timer = 0

Dans update() :

    if invincible:
        invincible_timer -= 1
        if invincible_timer <= 0:
            invincible = False
            ship.visible = True

Adapte la vérification de collision :

        elif rock.colliderect(ship) and not invincible and ship.visible:

Dessine l’explosion dans draw() :

    if explosion_active:
        explosion.draw()

Showcase

Montre ton Dojo Defender à un coach et à un buddy. Combien de temps tu survis ? Tu as des explosions ? Ça a de la gueule ?

À la prochaine !

« La prochaine fois : ton vaisseau RÉPLIQUE. Des ennemis en formation, et toi tu les exploses au laser. Ça va être épique. »

À emporter chez toi

Essaie une de ces extensions à la maison :

  1. Son — Ajoute sounds/explosion.wav quand un astéroïde explose (sounds.explosion.play()).
  2. Plus difficile — Fais tomber les astéroïdes plus vite à mesure que le score monte : rock.speed = random.uniform(3 + score // 10, 5 + score // 10).
  3. Power-up — Ajoute un power-up vert rare qui donne une vie en plus.
  4. Plus petit — Utilise asteroid_med ou asteroid_small pour varier la taille et la vitesse.

Télécharger Dojo Defender

30 octobre 2026, 15:59

Dojo Defender : Session 2

Ton vaisseau a maintenant une arme. Les ennemis arrivent. Abats-les avant qu’ils atteignent le fond. Tous les 10 ennemis, une nouvelle vague — et ça devient de plus en plus difficile.

Ce que tu vas apprendre aujourd’hui

  • Tirer avec la barre d’espace et un cooldown
  • Des listes pour les balles et les ennemis
  • La collision entre les balles et les ennemis
  • Des vagues qui deviennent de plus en plus difficiles
  • Des ennemis qui font des mouvements sinusoïdaux

Étape 0 : Ouvre le starter

  1. Ouvre Thonny.
  2. Télécharge le starter Dojo Defender d’aujourd’hui, décompresse le ZIP et ouvre main.py.
  3. Tu n’étais pas là la dernière fois ? Télécharge la solution de la session 1 et commence avec ça.
  4. Clique sur Run. Tu vois le même jeu que la dernière fois : vaisseau, astéroïdes, explosions.
  5. Des problèmes ? Va voir Installer Thonny.

Étape 1 : Tirer avec ESPACE

Ton vaisseau a un canon laser. Ajoute une liste pour les balles en haut :

bullets = []

Utilise on_key_down — elle n’est appelée qu’une seule fois quand tu appuies sur une touche (contrairement à update qui se répète) :

def on_key_down(key):
    if key == keys.SPACE:
        bullet = Actor('bullet')
        bullet.x = ship.x
        bullet.y = ship.y - 20
        bullets.append(bullet)

Fais monter les balles dans update() et supprime-les quand elles sortent de l’écran :

for bullet in bullets[:]:
    bullet.y -= 8
    if bullet.y < -10:
        bullets.remove(bullet)

N’oublie pas de dessiner les balles dans draw() :

for bullet in bullets:
    bullet.draw()

Étape 2 : ✅ Basic : cooldown de tir

Sans cooldown, tu tires des dizaines de balles par seconde. Ajoute un timer :

shoot_cooldown = 0

Dans update() :

if shoot_cooldown > 0:
    shoot_cooldown -= 1

Adapte on_key_down pour ne pouvoir tirer que quand le cooldown est à 0 :

def on_key_down(key):
    global shoot_cooldown
    if key == keys.SPACE and shoot_cooldown == 0:
        bullet = Actor('bullet')
        bullet.x = ship.x
        bullet.y = ship.y - 20
        bullets.append(bullet)
        shoot_cooldown = 15

Étape 3 : ⭐ Stretch : ajouter des ennemis

Les ennemis apparaissent en haut et tombent vers le bas. Ajoute une liste :

enemies = []

Une fonction de spawn :

def spawn_enemy():
    enemy = Actor('enemy_drone')
    enemy.x = random.randint(30, WIDTH - 30)
    enemy.y = -30
    enemy.speed = random.uniform(1, 3)
    enemies.append(enemy)

Appelle spawn_enemy() dans update() avec un intervalle de spawn :

# en haut :
spawn_counter = 0
spawn_interval = 120

# dans update() :
spawn_counter += 1
if spawn_counter >= spawn_interval:
    spawn_counter = 0
    spawn_enemy()

Dessine les ennemis dans draw() :

for enemy in enemies:
    enemy.draw()

Étape 4 : 🔥 Expert : collision + vagues

Une balle touche un ennemi : supprime les deux, +10 points :

for bullet in bullets[:]:
    bullet.y -= 8
    if bullet.y < -10:
        bullets.remove(bullet)
        continue
    for enemy in enemies[:]:
        if bullet.colliderect(enemy):
            bullets.remove(bullet)
            enemies.remove(enemy)
            global score
            score += 10
            break

Un ennemi touche le fond ou le vaisseau : tu perds une vie (comme pour un astéroïde).

Vagues : une nouvelle vague tous les 10 ennemis. Les ennemis apparaissent plus vite :

# en haut :
wave = 1
enemies_destroyed = 0

# à la destruction :
enemies_destroyed += 1
if enemies_destroyed % 10 == 0:
    wave += 1
    spawn_interval = max(60, spawn_interval - 10)

Affiche la vague actuelle dans draw() :

screen.draw.text(f"Vague : {wave}", (10, 70), color="yellow", fontsize=24)

Affiche « VAGUE N ! » en grand quand une nouvelle vague commence (utilise un timer).

Mouvement sinusoïdal : fais zigzaguer les ennemis de gauche à droite :

import math  # en haut

enemy.x = enemy.start_x + math.sin(timer * 0.03 + enemy.strafe_offset) * 50

Showcase

Montre ton Dojo Defender à un coach. Combien de vagues tu passes ? Tu as réussi le mouvement sinusoïdal ? Compare ton score avec un buddy.

À la prochaine !

« La prochaine fois : les POWER-UPS. Des boucliers, des speed-boosts et des tirs en éventail. Ton vaisseau devient de plus en plus fort à mesure que tu survis plus longtemps. »

À emporter chez toi

Essaie une de ces extensions à la maison :

  1. Variation d’ennemis — Utilise enemy_charger.png pour un ennemi plus rapide qui ne fait pas de sinus, mais qui fonce droit sur toi.
  2. Son — Ajoute sounds/laser.wav et sounds/explosion.wav.
  3. Mode difficile — Les ennemis apparaissent de plus en plus vite, jusqu’à un maximum toutes les 30 frames.
  4. Multiplicateur de score — Plus la vague est haute, plus tu marques de points par kill : score += 10 * wave.

Télécharger Dojo Defender

30 octobre 2026, 15:59

Dojo Defender : Session 3

Aujourd’hui, Dojo Defender déménage de pgzero vers le vrai pygame. Plus de pgzrun.go() — c’est toi qui écris la game loop. Le jeu reste le même, mais le moteur en dessous change. Et à la fin, tu ajoutes du SON.

Ce que tu vas apprendre aujourd’hui

  • La différence entre pgzero et raw pygame
  • Programmer la game loop toi-même : while running: clock.tick(60)
  • Convertir les Actors en Surface + Rect
  • Charger et jouer du son avec pygame.mixer
  • Faire tourner la musique de fond en boucle

Étape 0 : Télécharge le starter

Le starter d’aujourd’hui est un portage complet de Dojo Defender Session 2 vers raw pygame. Plus de pgzero, mais il se joue pareil.

  1. Télécharge le starter Dojo Defender d’aujourd’hui, décompresse et ouvre main.py.
  2. Tu n’étais pas là la dernière fois ? Télécharge la solution de la session 2 et essaie de la porter.
  3. Clique sur Run. Le jeu marche comme tu en as l’habitude : vaisseau, astéroïdes, balles, ennemis, vagues, explosions.

Qu’est-ce qui a changé ?

En pgzero, tu écrivais draw() et update() et pgzrun faisait le reste. En raw pygame, tu fais tout toi-même :

pgzero (avant) :

import pgzrun

def draw():
    screen.fill((10, 10, 30))
    ship.draw()

def update():
    if keyboard.left:
        ship.x -= 5

pgzrun.go()

raw pygame (maintenant) :

import pygame, sys
pygame.init()
screen = pygame.display.set_mode((800, 600))
clock = pygame.time.Clock()

running = True
while running:
    clock.tick(60)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit(); sys.exit()

    keys = pygame.key.get_pressed()
    if keys[pygame.K_LEFT]:
        ship.rect.centerx -= 5

    screen.fill((10, 10, 30))
    ship.draw(screen)
    pygame.display.flip()

Les différences les plus importantes :

pgzeroraw pygame
Actor('plaatje')GameObject('plaatje.png', x, y)
keyboard.leftkeys[pygame.K_LEFT]
on_key_down(key)event.type == pygame.KEYDOWN
screen.draw.text(...)font.render() + screen.blit()
rock.colliderect(ship)rock.rect.colliderect(ship.rect)
pgzrun.go()while running: ... clock.tick(60)

Étape 1 : Explore le code

Ouvre main.py et compare avec l’ancien code pgzero de la session 2. Cherche ces morceaux :

  1. Game loop — Cherche la boucle while running:. Tu vois clock.tick(60), pygame.display.flip() ?
  2. GameObject — Cherche la class GameObject. Comment une image est-elle chargée ? C’est quoi, rect ?
  3. Input — Cherche pygame.key.get_pressed() et pygame.KEYDOWN. Comment marche la barre d’espace ?

Change WIDTH en 1024. Qu’est-ce qui se passe ? (Tout devient plus large — le jeu marche encore.)

Étape 2 : ✅ Basic — Ajoute un restart avec la touche R

Dans la version pgzero, tu ne savais pas redémarrer après un game over. Ajoute-le maintenant :

# dans la boucle d'événements, à KEYDOWN :
if event.key == pygame.K_r and game_over:
    # tout réinitialiser
    ship.rect.center = (WIDTH / 2, HEIGHT - 50)
    ship.visible = True
    asteroids.clear()
    bullets.clear()
    enemies.clear()
    lives = 3
    score = 0
    wave = 1
    enemies_destroyed = 0
    spawn_counter = 0
    spawn_interval = 120
    wave_display_timer = 0
    game_over = False
    invincible = False
    ship.visible = True

Affiche aussi un indice sur l’écran de game over : appuie sur R pour rejouer.

Étape 3 : ⭐ Stretch — Ajoute du son

Le starter n’a pas encore de son. Ajoute des sons !

Crée un dossier sounds/ à côté de images/ et copie les fichiers audio de dojo-defender-assets/sounds/ (demande au coach). Ou télécharge la solution qui les contient déjà.

Ajoute en haut :

pygame.mixer.init()  # après pygame.init()

shoot_sound = pygame.mixer.Sound('sounds/shoot.wav')
explode_sound = pygame.mixer.Sound('sounds/explode.wav')
hit_sound = pygame.mixer.Sound('sounds/hit.wav')
pygame.mixer.music.load('sounds/bg_music.wav')
pygame.mixer.music.play(-1)  # -1 = répéter en boucle

Attention : le chemin doit être correct. Utilise os.path.join(_DIR, 'sounds/shoot.wav') comme le starter le fait aussi pour les images.

Joue les sons au bon moment :

  • shoot_sound.play() — quand tu tires
  • explode_sound.play() — quand un ennemi ou un astéroïde explose
  • hit_sound.play() — quand ton vaisseau est touché

Étape 4 : 🔥 Expert — Bouton mute et volume

Ajoute une touche M qui coupe et remet le son :

muted = False

# à KEYDOWN :
if event.key == pygame.K_m:
    muted = not muted
    pygame.mixer.music.set_volume(0 if muted else 1)

Chaque son doit alors être vérifié :

if not muted:
    shoot_sound.play()

Volume par son : Mets le son de tir plus bas que l’explosion :

shoot_sound.set_volume(0.3)
explode_sound.set_volume(0.7)

Showcase

Montre à un coach que :

  • Ton jeu marche en vrai pygame sans pgzero
  • Tu as ajouté du son (shoot, explode, hit, bg music)
  • Bonus : restart avec R ou mute avec M

À la prochaine !

« La prochaine fois : les POWER-UPS. Des boucliers, des speed-boosts et des tirs en éventail. Et ton vaisseau devient plus fort à mesure que tu survis plus longtemps. »

À emporter chez toi

Essaie une de ces extensions à la maison :

  1. Health bar — Remplace le texte « Vies : 3 » par une barre visuelle : dessine trois petits rectangles en haut.
  2. Pause — Ajoute une touche P qui met le jeu en pause. Mettre running = False ne suffit pas — utilise une variable paused séparée.
  3. Effet de particules — Fais gicler de petits points blancs autour d’une explosion (utilise une liste de particules qui rétrécissent de plus en plus).
  4. Ton propre skin — Remplace player_ship.png par ton propre design.

Télécharger Dojo Defender

30 octobre 2026, 15:59

Dojo Defender : Session 4

Aujourd’hui, Dojo Defender devient un vrai jeu avec un menu. Fini le démarrage sur un écran noir — tu obtiens un écran-titre, un écran de game over, et trois types d’ennemis qui ont chacun leur propre mouvement.

Ce que tu vas apprendre aujourd’hui

  • State machines : ton jeu a des états (MENU, PLAYING, GAME OVER)
  • IA des ennemis : chaque ennemi bouge autrement (droit, zigzag, charger)
  • Système de waves : des vagues de plus en plus difficiles avec des mélanges d’ennemis
  • Une fonction reset : tout remettre proprement en place sans redémarrer

Étape 0 : Télécharge le starter

Le starter est la solution de la session 3 — Dojo Defender en pygame brut avec du son.

  1. Télécharge le starter d’aujourd’hui, décompresse-le et ouvre main.py.
  2. Tu n’étais pas là ? Télécharge la solution de la session 3.
  3. Clique sur Run. Le jeu marche comme avant : vaisseau, astéroïdes, balles, drones, son.

Étape 1 : Ajoute une state machine

Une state machine retient dans quel « état » se trouve le jeu :

state = "MENU"  # peut valoir "MENU", "PLAYING" ou "GAME_OVER"

Place cette variable tout en haut, avec les autres variables globales.

Dessiner l’écran de menu : remplace le screen.fill et tout le dessin par un test sur state :

if state == "MENU":
    # Dessine le titre et les instructions
    screen.fill((10, 10, 30))
    titel = title_font.render("DOJO DEFENDER", True, (0, 200, 255))
    screen.blit(titel, (WIDTH // 2 - titel.get_width() // 2, HEIGHT // 2 - 60))
    sub = big_font.render("Appuie sur ESPACE pour commencer", True, (200, 200, 200))
    screen.blit(sub, (WIDTH // 2 - sub.get_width() // 2, HEIGHT // 2))

elif state == "PLAYING":
    # = tout ton code de jeu existant ici

elif state == "GAME_OVER":
    # Dessine "GAME OVER" + le score

Crée title_font et big_font tout en haut :

title_font = pygame.font.SysFont(None, 80)
big_font = pygame.font.SysFont(None, 60)

Maintenant, ESPACE doit faire ceci :

  • Si state == "MENU" : remets le jeu à zéro et passe à PLAYING
  • Si state == "GAME_OVER" : remets le jeu à zéro et passe à PLAYING
  • Si state == "PLAYING" et game_over == False : tire comme d’habitude

Adapte la logique KEYDOWN :

if event.key == pygame.K_SPACE:
    if state == "MENU":
        reset_game()
        state = "PLAYING"
    elif state == "GAME_OVER":
        reset_game()
        state = "PLAYING"
    elif state == "PLAYING" and shoot_cooldown == 0 and not game_over:
        # tire (code existant)

Étape 2 : ✅ Basic — Écris la fonction reset

Fais une fonction qui remet tout aux valeurs de départ :

def reset_game():
    global ship, asteroids, bullets, enemies
    global lives, score, game_over, timer
    global explosion_active, explosion_frame, explosion_timer
    global invincible, invincible_timer, shoot_cooldown
    global wave, wave_display_timer, enemies_destroyed
    global spawn_counter, spawn_interval

    ship.rect.center = (WIDTH / 2, HEIGHT - 50)
    ship.visible = True
    asteroids.clear()
    bullets.clear()
    enemies.clear()
    lives = 3
    score = 0
    game_over = False
    timer = 0
    explosion_active = False
    explosion_frame = 0
    explosion_timer = 0
    invincible = False
    invincible_timer = 0
    shoot_cooldown = 0
    wave = 1
    wave_display_timer = 0
    enemies_destroyed = 0
    spawn_counter = 0
    spawn_interval = 120

Mets state = "GAME_OVER" quand le joueur n’a plus de vies (lives <= 0) :

if lives <= 0:
    game_over = True
    state = "GAME_OVER"

Check : le jeu démarre maintenant sur un écran-titre bleu. ESPACE lance le jeu. Après un game over, tu vois GAME OVER et tu peux redémarrer avec ESPACE.

Étape 3 : ⭐ Stretch — Trois types d’ennemis

Remplace l’unique spawn_enemy() par trois fonctions :

def spawn_enemy_drone():
    enemy = GameObject('enemy_drone.png', random.randint(30, WIDTH - 30), -30)
    enemy.type = 'drone'
    enemy.speed = random.uniform(1, 3)
    enemies.append(enemy)


def spawn_enemy_zigzag():
    enemy = GameObject('enemy_zigzag.png', random.randint(30, WIDTH - 30), -30)
    enemy.type = 'zigzag'
    enemy.speed = random.uniform(2, 4)
    enemy.dx = random.choice([-2, 2])
    enemies.append(enemy)


def spawn_enemy_charger():
    enemy = GameObject('enemy_charger.png', random.randint(30, WIDTH - 30), -30)
    enemy.type = 'charger'
    enemy.speed = random.uniform(3, 5)
    enemies.append(enemy)

Mouvement par type

Dans la game loop, là où tu faisais enemy.rect.y += enemy.speed, tu dois maintenant ajouter un mouvement différent par type :

for enemy in enemies[:]:
    if enemy.type == 'drone':
        enemy.rect.y += enemy.speed

    elif enemy.type == 'zigzag':
        enemy.rect.x += enemy.dx
        enemy.rect.y += enemy.speed
        if enemy.rect.left <= 0 or enemy.rect.right >= WIDTH:
            enemy.dx = -enemy.dx

    elif enemy.type == 'charger':
        # Dirige vers la position x du joueur
        dx = ship.rect.centerx - enemy.rect.centerx
        if dx > 0:
            enemy.rect.centerx += min(enemy.speed, abs(dx))
        elif dx < 0:
            enemy.rect.centerx -= min(enemy.speed, abs(dx))
        enemy.rect.y += enemy.speed * 0.8

    # Ensuite : test hors écran, collision avec le vaisseau, etc.

Important : le charger doit descendre plus lentement (* 0.8) pour que le joueur ait le temps de réagir.

Étape 4 : 🔥 Expert — Waves améliorées

Fais un spawn_enemy() qui décide quel type apparaît selon la wave actuelle :

def spawn_enemy():
    if wave == 1:
        spawn_enemy_drone()
    elif wave <= 3:
        if random.random() < 0.5:
            spawn_enemy_drone()
        else:
            spawn_enemy_zigzag()
    else:
        r = random.random()
        if r < 0.3:
            spawn_enemy_drone()
        elif r < 0.65:
            spawn_enemy_zigzag()
        else:
            spawn_enemy_charger()

Comme ça, le jeu devient de plus en plus difficile :

  • Wave 1 : seulement des drones (échauffement)
  • Wave 2-3 : drones + zigzag (50/50)
  • Wave 4+ : les trois, avec plus de chargers (30 % drone, 35 % zigzag, 35 % charger)

Showcase

Montre à un coach que :

  • Tu as un écran de menu avec un titre et « Appuie sur ESPACE pour commencer »
  • Tu as trois types d’ennemis : drone (↓), zigzag (↘↗), charger (→ ton vaisseau)
  • Les waves deviennent de plus en plus difficiles (plus de zigzags, puis de chargers)
  • Le game over marche avec l’affichage du score et le restart

À la prochaine !

« La prochaine fois : les POWER-UPS. Des boucliers, des speed-boosts, des spread-shots. Et un vrai boss final. »

À emporter chez toi

Essaie une de ces extensions à la maison :

  1. High score — Garde le meilleur score dans un fichier et affiche-le dans le menu.
  2. Niveau de difficulté — Laisse le joueur choisir entre « Facile » et « Difficile » dans le menu.
  3. Boss wave — Toutes les 5 waves, un gros boss apparaît avec beaucoup de hits.
  4. Charger Warning — Dessine une ligne rouge sous un charger avant qu’il n’apparaisse.

Télécharge Dojo Defender

30 octobre 2026, 15:59

Dojo Defender : Session 5

Aujourd’hui, tu donnes à Dojo Defender un effet de profondeur avec un fond étoilé en parallaxe et des particules d’explosion. Les astéroïdes deviennent aussi destructibles : les grands se divisent en plus petits.

Ce que tu vas apprendre aujourd’hui

  • Calcul de parallaxe : plusieurs couches d’étoiles avec leur propre vitesse
  • Listes de particules : une liste de dictionnaires pour les particules
  • Effets basés sur la position : les particules apparaissent au bon endroit
  • Division récursive : grand astéroïde → 2 moyens → 2 petits → disparu

Étape 0 : Télécharge le starter

Le starter est la solution de la session 4 — Dojo Defender avec menu, trois types d’ennemis et waves.

  1. Télécharge le starter d’aujourd’hui, décompresse-le et ouvre main.py.
  2. Tu n’étais pas là ? Télécharge la solution de la session 4.
  3. Clique sur Run. Le jeu marche comme avant : vaisseau, astéroïdes, balles, drones, zigzags, chargers.

Étape 1 : 🌟 Fond étoilé en parallaxe

Un fond en parallaxe a plusieurs couches qui bougent à des vitesses différentes. Loin = lentement, près = vite. Ça donne de la profondeur.

Ajoute une liste stars = [] tout en haut du fichier, avec les autres variables globales :

stars = []

Fais une fonction init_stars() qui crée trois couches d’étoiles :

def init_stars():
    global stars
    stars = []
    layers = [
        (40, 0.3, 2, 120),   # loin : 40 étoiles, vitesse 0.3, taille 2, plus sombre
        (40, 0.7, 3, 180),   # milieu : 40 étoiles, vitesse 0.7, taille 3
        (30, 1.5, 4, 255),   # près : 30 étoiles, vitesse 1.5, taille 4, vif
    ]
    for count, speed, size, brightness in layers:
        for _ in range(count):
            stars.append({
                'x': random.randint(0, WIDTH),
                'y': random.randint(0, HEIGHT),
                'speed': speed,
                'size': size,
                'brightness': brightness,
            })

Les maths derrière : chaque étoile reçoit une vitesse y. Les étoiles lointaines (0.3 px/frame) ne bougent presque pas, les proches (1.5 px/frame) bougent plus vite. Ton cerveau interprète ça comme de la profondeur, exactement comme dans une voiture : les arbres au bord de la route défilent, les montagnes au loin restent immobiles.

Ajoute aussi la fonction d’update. Elle fait descendre les étoiles et les remet en haut quand elles passent sous l’écran :

def update_stars():
    for star in stars:
        star['y'] += star['speed']
        if star['y'] > HEIGHT + star['size']:
            star['y'] = -star['size']
            star['x'] = random.randint(0, WIDTH)

Et une fonction de dessin. Les petites étoiles, tu les dessines avec pygame.draw.rect (2×2), les plus grandes avec pygame.draw.circle :

def draw_stars(surface):
    for star in stars:
        c = (star['brightness'], star['brightness'], star['brightness'])
        if star['size'] <= 2:
            pygame.draw.rect(surface, c, (star['x'], star['y'], star['size'], star['size']))
        else:
            pygame.draw.circle(surface, c, (int(star['x']), int(star['y'])), star['size'] // 2)

Appeler : appelle init_stars() une fois (au démarrage, après toutes les fonctions), update_stars() à chaque frame (même dans le menu !), et draw_stars(screen) après screen.fill() dans TOUS les états.

Check

Tu vois trois couches d’étoiles défiler vers le bas, aussi dans le menu ? Les étoiles lointaines sont plus petites et bougent plus lentement.

Étape 2 : ✅ Basic — Système de particules

Une particule est un petit point qui bouge, s’estompe et disparaît. On utilise une liste de dictionnaires :

particles = []  # {x, y, vx, vy, life, max_life, color, size}

Fais une fonction pour faire apparaître des particules :

def spawn_particles(x, y, count, colors, speed_range, size_range, life_range):
    for _ in range(count):
        angle = random.uniform(0, 2 * math.pi)
        speed = random.uniform(speed_range[0], speed_range[1])
        particles.append({
            'x': x,
            'y': y,
            'vx': math.cos(angle) * speed,
            'vy': math.sin(angle) * speed,
            'life': random.randint(life_range[0], life_range[1]),
            'max_life': life_range[1],
            'color': random.choice(colors),
            'size': random.uniform(size_range[0], size_range[1]),
        })

Que se passe-t-il ? Chaque particule reçoit :

  • Une position (x, y)
  • Une vitesse en x et en y (vx, vy), calculée à partir d’un angle et d’une vitesse
  • Une durée de vie (life est diminué de 1 à chaque frame)
  • Une couleur et une taille

Fonction d’update (à chaque frame, déplacer chaque particule d’un pas et raccourcir sa durée de vie) :

def update_particles():
    for p in particles[:]:
        p['x'] += p['vx']
        p['y'] += p['vy']
        p['life'] -= 1
        if p['life'] <= 0:
            particles.remove(p)

Pourquoi [:] ? On modifie la liste pendant qu’on la parcourt (on supprime des particules). Sans [:], tu obtiens une erreur au runtime. La slice [:] fait une copie de la liste pour la parcourir en sécurité.

Fonction de dessin avec fondu (alpha-fade) : moins il reste de durée de vie, plus la particule est petite et sombre :

def draw_particles(surface):
    for p in particles:
        ratio = p['life'] / p['max_life']
        color = tuple(int(c * ratio) for c in p['color'])
        pygame.draw.circle(surface, color, (int(p['x']), int(p['y'])), int(p['size'] * ratio))

Le ratio est un nombre entre 1 (juste né) et 0 (presque mort). On multiplie la couleur et la taille par ce nombre, pour que la particule disparaisse lentement.

Vider la liste de particules dans le reset

Ajoute particles.clear() à la fonction reset_game(), sinon les particules mortes continuent de flotter après un restart.

Appelle update_particles() dans l’état PLAYING et draw_particles(screen) après draw_stars(screen) dans tous les états.

Check

Lance le jeu et appuie sur ESPACE. Rien de visible ne se passe encore — mais le système est prêt pour les étapes suivantes.

Étape 3 : ⭐ Stretch — Effets basés sur la position

Maintenant, on va faire apparaître des particules aux bons moments et aux bonnes positions.

Gaz d’échappement

Quand le vaisseau bouge, fais apparaître de petites particules rouge/orange sous le vaisseau. Ajoute ceci dans la section if not game_over, là où tu vérifies les flèches :

keys = pygame.key.get_pressed()
moving = False
if keys[pygame.K_LEFT] and ship.rect.centerx > 30:
    ship.rect.centerx -= 5
    moving = True
if keys[pygame.K_RIGHT] and ship.rect.centerx < WIDTH - 30:
    ship.rect.centerx += 5
    moving = True

if moving and ship.visible:
    spawn_particles(
        ship.rect.centerx, ship.rect.bottom,
        1,  # ou random.randint(1, 2)
        [(255, 100, 0), (255, 60, 0), (200, 50, 0)],
        (0.5, 1.5), (2, 4), (10, 20),
    )

Les particules apparaissent sous le vaisseau (ship.rect.bottom) et reçoivent une petite vitesse vers le haut (vy négatif à cause de l’angle).

Débris d’explosion

Quand un ennemi est touché par une balle, fais apparaître 8-12 particules dans toutes les directions. Ajoute ceci là où tu enlèves un ennemi de la liste après une collision avec une balle :

spawn_particles(
    enemy.rect.centerx, enemy.rect.centery,
    random.randint(8, 12),
    [(255, 140, 0), (255, 0, 0), (255, 255, 0), (255, 255, 255)],
    (1, 4), (2, 5), (20, 40),
)

Étincelles de mort d’ennemi

Quand un ennemi atteint le bas de l’écran, fais apparaître 3-5 étincelles blanches :

spawn_particles(
    enemy.rect.centerx, HEIGHT - 30,
    random.randint(3, 5),
    [(255, 255, 255), (200, 200, 255)],
    (1, 3), (1, 3), (15, 30),
)

Check

Bouge le vaisseau — tu vois les gaz d’échappement orange ? Tire sur un ennemi — tu vois 8-12 particules qui volent dans tous les sens ? Laisse un ennemi s’échapper — tu vois des étincelles blanches ?

Étape 4 : 🔥 Expert — Astéroïdes destructibles

Les astéroïdes peuvent maintenant être divisés de façon récursive :

  • asteroid_big.png → touché → 2× asteroid_med.png
  • asteroid_med.png → touché → 2× asteroid_small.png
  • asteroid_small.png → touché → disparu + particules

Adapte spawn_asteroid() pour que chaque astéroïde reçoive une asteroid_size :

def spawn_asteroid(size='big'):
    rock = GameObject(f'asteroid_{size}.png', random.randint(30, WIDTH - 30), -30)
    rock.speed = random.uniform(3, 5)
    rock.asteroid_size = size
    asteroids.append(rock)
    return rock

Fais une fonction split_asteroid() qui divise un astéroïde en deux plus petits :

def split_asteroid(rock):
    # D'abord : particules d'explosion
    spawn_particles(
        rock.rect.centerx, rock.rect.centery,
        random.randint(8, 12),
        [(255, 140, 0), (255, 0, 0), (255, 255, 0), (255, 255, 255)],
        (1, 4), (2, 5), (20, 40),
    )
    if rock.asteroid_size == 'big':
        for _ in range(2):
            r = spawn_asteroid('med')
            r.rect.center = rock.rect.center
            r.rect.x += random.randint(-20, 20)
            r.speed = random.uniform(2, 4)
    elif rock.asteroid_size == 'med':
        for _ in range(2):
            r = spawn_asteroid('small')
            r.rect.center = rock.rect.center
            r.rect.x += random.randint(-15, 15)
            r.speed = random.uniform(1, 3)
    asteroids.remove(rock)

Que se passe-t-il ici ?

  1. On fait apparaître des particules d’explosion à la position de l’astéroïde
  2. On vérifie la taille : ‘big’ → 2 ‘med’, ‘med’ → 2 ‘small’, ‘small’ → pas d’autre division
  3. Les nouveaux astéroïdes apparaissent près de l’ancienne position avec un léger décalage
  4. Les plus petits astéroïdes sont plus lents que les grands

Adapte la logique de collision : là où tu faisais astersoids.remove(rock) quand une balle touchait l’astéroïde, appelle maintenant split_asteroid(rock) :

for rock in asteroids[:]:
    if bullet.rect.colliderect(rock.rect):
        bullets.remove(bullet)
        explode_sound.play()
        split_asteroid(rock)
        score += 5
        break

Important : Tu joues le son (explode_sound.play()) avant split_asteroid() pour qu’il ne se joue pas deux fois par accident.

Check

Tire sur un grand astéroïde. Tu le vois se diviser en deux astéroïdes moyens ? Tire sur ceux-là — ils se divisent en deux petits. Tire sur les petits — ils disparaissent dans une belle explosion de particules.

Showcase

Montre à un coach que :

  • Fond étoilé en parallaxe avec trois vitesses
  • Système de particules avec fondu (alpha-fade)
  • Gaz d’échappement sous le vaisseau en mouvement
  • Débris d’explosion quand des ennemis et des astéroïdes sont détruits
  • Astéroïdes qui se divisent : big → med → small → disparu

À la prochaine !

« La prochaine fois : les POWER-UPS. Des boucliers, des speed-boosts, des spread-shots. Et un vrai boss final. »

À emporter chez toi

Essaie une de ces extensions à la maison :

  1. Facile : change la couleur des étoiles par couche (par exemple les étoiles lointaines bleutées, les proches jaunes).
  2. Moyen : ajoute une quatrième couche d’étoiles, encore plus rapide (vitesse 3.0), avec de grandes étoiles lumineuses.
  3. Difficile : fais changer la couleur des particules pendant leur durée de vie (du jaune au rouge puis au gris).
  4. Très difficile : ajoute un type de particule « comet » qui a une petite queue.

Télécharge Dojo Defender

30 octobre 2026, 15:59

Dojo Defender : Session 6

Aujourd’hui, tu ajoutes un boss final à Dojo Defender. Le boss apparaît toutes les 5 waves et a 3 phases avec leur propre comportement. Tu apprends à travailler avec une state machine maison, des barres de HP et des effets de screen shake.

Ce que tu vas apprendre aujourd’hui

  • State machine pour un boss : PHASE_1, PHASE_2, PHASE_3 et EXPLODING
  • Barre de HP à dessiner avec un dégradé de couleur (vert → jaune → rouge)
  • Balles qui cherchent leur cible : une balle qui se dirige vers le joueur
  • Screen shake : un décalage aléatoire sur les coordonnées de dessin
  • Transitions de phase avec des effets visuels

Étape 0 : Télécharge le starter

Le starter est la solution de la session 5 — Dojo Defender avec étoiles en parallaxe, particules et astéroïdes qui se divisent.

  1. Télécharge le starter d’aujourd’hui, décompresse-le et ouvre main.py.
  2. Tu n’étais pas là ? Télécharge la solution de la session 5.
  3. Clique sur Run. Le jeu marche comme avant. Tue 10 ennemis pour atteindre la wave 5 — et le boss apparaît !

Étape 1 : ✅ Basic — Variables du boss

Un boss a ses propres variables. Ajoute-les avec les autres variables globales :

boss = None
boss_active = False
boss_hp = 0
boss_hp_max = 50
boss_phase = "PHASE_1"
boss_timer = 0
boss_phase_transition_timer = 0
boss_defeated_timer = 0
boss_shoot_timer = 0
boss_minion_spawn_timer = 0
boss_bullets = []
boss_minions = []
screen_shake_x = 0
screen_shake_y = 0
boss_direction = 1

Ajoute aussi le vidage de boss_bullets et de boss_minions dans reset_game().

Pourquoi autant de variables ? Un boss est plus complexe que des ennemis ordinaires. Il doit bouger, tirer, faire apparaître des minions, avoir des phases et une animation de mort. Chaque variable est un aspect de ce comportement.

Check

Lance le jeu. Rien ne change encore — mais les variables sont prêtes.

Étape 2 : ⭐ Stretch — Faire apparaître et dessiner le boss

Fonction de spawn

Écris une fonction qui active le boss :

def start_boss():
    global boss_active, boss, boss_hp, boss_phase, boss_timer
    global boss_bullets, boss_minions, boss_shoot_timer
    global boss_minion_spawn_timer, boss_direction, screen_shake_x, screen_shake_y
    boss_active = True
    boss = GameObject('boss.png', WIDTH / 2, -80)
    boss_hp = boss_hp_max
    boss_phase = "PHASE_1"
    boss_timer = 0
    boss_shoot_timer = 0
    boss_minion_spawn_timer = 0
    boss_direction = 1
    screen_shake_x = 0
    screen_shake_y = 0
    boss_bullets.clear()
    boss_minions.clear()
    roar_path = os.path.join(_DIR, 'sounds/boss_roar.wav')
    if os.path.exists(roar_path):
        pygame.mixer.Sound(roar_path).play()

Détection de la wave du boss

Un boss apparaît toutes les 5 waves (à partir de la wave 5). Ajoute ceci là où la wave monte :

def check_boss_wave():
    if wave >= 5 and wave % 5 == 0 and not boss_active:
        start_boss()

Appelle check_boss_wave() après wave += 1.

Arrêter les ennemis pendant le boss

Fais en sorte que les ennemis ordinaires n’apparaissent pas pendant un boss fight. Entoure la logique de spawn :

if not boss_active:
    spawn_counter += 1
    if spawn_counter >= spawn_interval:
        spawn_counter = 0
        spawn_enemy()

Dessiner le boss

Dessine le boss quand il est actif, et dessine aussi la barre de HP en haut de l’écran :

if boss_active and boss is not None:
    boss.draw(screen)
    # Barre de HP
    bar_width = 300
    bar_height = 20
    bar_x = (WIDTH - bar_width) // 2
    bar_y = 10
    bar_bg = pygame.Rect(bar_x, bar_y, bar_width, bar_height)
    pygame.draw.rect(screen, (100, 20, 20), bar_bg)
    hp_ratio = max(0, boss_hp / boss_hp_max)
    fill_width = int(bar_width * hp_ratio)
    if hp_ratio > 0.5:
        color = (0, 255, 0)
    elif hp_ratio > 0.25:
        color = (255, 255, 0)
    else:
        color = (255, 0, 0)
    fill_rect = pygame.Rect(bar_x, bar_y, fill_width, bar_height)
    pygame.draw.rect(screen, color, fill_rect)
    pygame.draw.rect(screen, (255, 255, 255), bar_bg, 2)
    label = font.render(f"BOSS  {boss_hp}/{boss_hp_max}", True, (255, 255, 255))
    screen.blit(label, (bar_x + bar_width // 2 - label.get_width() // 2, bar_y - 5))

Check

Joue jusqu’à la wave 5. Tu vois le boss entrer avec une barre de HP ? Les ennemis ordinaires n’apparaissent plus.

Étape 3 : 🔥 Expert — IA du boss (3 phases)

Le boss a une state machine avec 3 phases. Chaque phase a un comportement différent.

Phase 1 (HP 34-50, 100-66 %)

Le boss dérive lentement vers la gauche et la droite et tire de temps en temps une balle qui cherche sa cible.

def fire_boss_bullet():
    dx = ship.rect.centerx - boss.rect.centerx
    dy = ship.rect.centery - boss.rect.centery
    dist = math.sqrt(dx * dx + dy * dy)
    if dist == 0:
        dist = 1
    speed = 3
    bullet = {
        'x': boss.rect.centerx,
        'y': boss.rect.centery + 30,
        'vx': dx / dist * speed,
        'vy': dy / dist * speed,
    }
    boss_bullets.append(bullet)

Maths : en divisant dx et dy par la distance (dist), tu obtiens un vecteur unitaire — une direction de longueur 1. Multiplie par speed pour avoir la vitesse voulue. Ça marche dans TOUTES les directions, pas seulement à l’horizontale ou à la verticale.

Ajoute l’update de l’IA dans la game loop (if boss_active and boss is not None) :

if boss.rect.centery < 80:
    boss.rect.centery += 2  # entre dans l'écran
else:
    if boss_phase == "PHASE_1":
        boss.rect.centerx += boss_direction * 1.5
        if boss.rect.centerx > WIDTH - 60:
            boss_direction = -1
        if boss.rect.centerx < 60:
            boss_direction = 1
        boss_shoot_timer += 1
        if boss_shoot_timer >= 60:
            boss_shoot_timer = 0
            fire_boss_bullet()

Transition de phase (HP ≤ 66 %)

Vérifie si le boss doit changer de phase. Appelle ceci après l’update du boss :

hp_ratio = boss_hp / boss_hp_max
if hp_ratio <= 0.66 and boss_phase == "PHASE_1":
    boss_phase = "PHASE_2"
    boss_phase_transition_timer = 20

Pendant une transition de phase, tu fais clignoter le boss :

if boss_phase_transition_timer > 0 and boss_phase_transition_timer % 4 < 2:
    flash_surf = pygame.Surface(boss.image.get_size(), pygame.SRCALPHA)
    flash_surf.fill((255, 255, 255, 180))
    screen.blit(flash_surf, (boss.rect.x, boss.rect.y))

Phase 2 (HP 17-33, 66-33 %)

Le boss bouge plus vite, tire plus souvent et fait apparaître des minions :

elif boss_phase == "PHASE_2":
    boss.rect.centerx += boss_direction * 3
    ...
    boss_shoot_timer += 1
    if boss_shoot_timer >= 40:
        boss_shoot_timer = 0
        fire_boss_bullet()
    boss_minion_spawn_timer += 1
    if boss_minion_spawn_timer >= 180:
        boss_minion_spawn_timer = 0
        spawn_boss_minion()

Faire apparaître un minion :

def spawn_boss_minion():
    minion = GameObject('boss_minion.png', random.randint(30, WIDTH - 30), -30)
    minion.speed = random.uniform(1, 2)
    boss_minions.append(minion)

Phase 3 (HP 0-16, 33-0 %)

Le boss est enraged (furieux) : il tire deux balles à la fois, fait apparaître des minions plus vite, et l’écran tremble :

elif boss_phase == "PHASE_3":
    boss.rect.centerx += boss_direction * 4
    ...
    boss_shoot_timer += 1
    if boss_shoot_timer >= 20:
        boss_shoot_timer = 0
        fire_boss_bullet()
        if boss_hp < boss_hp_max * 0.15:
            fire_boss_bullet()
    ...

Screen shake : ajoute un décalage aléatoire à TOUTES les coordonnées de dessin :

if boss_phase == "PHASE_3":
    screen_shake_x = random.randint(-3, 3)
    screen_shake_y = random.randint(-3, 3)
else:
    screen_shake_x = 0
    screen_shake_y = 0

Adapte toutes les fonctions draw pour qu’elles acceptent des paramètres offset_x et offset_y. Par exemple draw_stars(screen, screen_shake_x, screen_shake_y).

Check

Joue jusqu’à la wave 5. Tu vois le boss passer par 3 phases ? Phase 1 : lent, une balle de temps en temps. Phase 2 : plus vite + des minions. Phase 3 : l’écran tremble, une pluie de balles.

Étape 4 : 💀 Expert — Vaincre le boss

Quand le boss atteint 0 HP, l’exploding sequence démarre :

if boss_hp <= 0:
    boss_phase = "EXPLODING"
    boss_defeated_timer = 90
    boss_phase_transition_timer = 60
    score += 500
    explode_sound.play()

Pendant EXPLODING, tu fais apparaître une burst de particules toutes les 10 frames :

if boss_phase == "EXPLODING":
    if boss_phase_transition_timer > 0 and boss_phase_transition_timer % 10 == 0:
        spawn_particles(
            boss.rect.centerx + random.randint(-40, 40),
            boss.rect.centery + random.randint(-40, 40),
            random.randint(10, 20),
            [(255, 255, 0), (255, 100, 0), (255, 0, 0), (255, 255, 255)],
            (2, 6), (3, 7), (20, 40),
        )

Affiche « BOSS DEFEATED! » en haut de l’écran :

if boss_defeated_timer > 0:
    defeat_msg = big_font.render("BOSS DEFEATED!", True, (255, 255, 0))
    screen.blit(defeat_msg, (WIDTH // 2 - defeat_msg.get_width() // 2, HEIGHT // 2 - 100))

Attention : réactive le spawn des ennemis ordinaires après le boss. La wave continue vers la suivante.

Check

Bats le boss. Tu vois l’animation d’explosion, le texte « BOSS DEFEATED! » et +500 au score ? Les waves ordinaires continuent après ?

Showcase

Montre à un coach que :

  • Le boss apparaît toutes les 5 waves avec une barre de HP
  • 3 phases avec leur propre comportement (lent → minions → enraged)
  • Des balles qui cherchent leur cible et qui volent vers le joueur
  • Du screen shake en phase 3
  • Des minions qui apparaissent en phase 2 et 3
  • Boss defeated : explosion sequence, « BOSS DEFEATED! », +500 au score

À la prochaine !

« La prochaine fois : la version polie. Du son, un écran de menu, des high scores — et ta propre touche personnelle dans le jeu. »

À emporter chez toi

Essaie une de ces extensions à la maison :

  1. Facile : change la couleur ou la taille du boss via l’image.
  2. Moyen : ajoute une quatrième phase (HP < 10 %) dans laquelle le boss se téléporte.
  3. Difficile : fais tirer au boss des delay-bullets qui laissent une traînée.
  4. Très difficile : ajoute un deuxième type de boss qui apparaît dans une autre wave.

Télécharge Dojo Defender

30 octobre 2026, 15:59

Dojo Defender : Session 7

Aujourd’hui, c’est toi qui décides de ce qui se passe dans Dojo Defender. Pas d’instructions pas à pas — choisis une feature, planifie-la et construis-la.

Tu démarres avec le Dojo Defender complet, avec tout ce qu’il faut : vaisseau, astéroïdes, 3 types d’ennemis, waves, particules, étoiles en parallaxe, et un boss final avec 3 phases.

Ce jeu est le tien. Fais-en quelque chose.

Choisis ce que tu veux construire

Voici des idées. Choisis-en une — ou trouve ta propre feature.

Facile

  • Power-ups : les ennemis laissent parfois (20 %) tomber un power-up. Rouge = spread shot (3 balles), vert = bouclier, jaune = speed boost. Les power-ups marchent 5 secondes.
  • Niveau de difficulté : rends le jeu plus facile (plus de vies, ennemis plus lents) ou plus difficile (moins de vies, spawns plus rapides).
  • Son : ajoute un son de power-up (powerup.wav), un son de game over, ou une musique de fond qui accélère dans les waves hautes.

Moyen

  • High score : garde le meilleur score dans un fichier (highscore.txt). Affiche-le dans le menu et sur l’écran de game over. Ne l’écrase que si le nouveau score est plus haut.
  • Difficulté qui monte : rends le jeu un peu plus difficile à chaque wave — ennemis plus rapides, astéroïdes plus petits, spawns plus fréquents.
  • Ennemis toxiques : un nouveau type d’ennemi qui laisse une traînée de particules toxiques.
  • Animation du vaisseau : le vaisseau ne peut tirer que 3 balles à la fois. Charge un indicateur de « heat » ou fais un cooldown.

Difficile

  • Deuxième boss : fais un nouveau boss qui apparaît à une autre wave (par exemple wave 7). Autre apparence, autre comportement.
  • Étendre le système de power-ups : ajoute un 4e power-up (par exemple « time freeze » — les ennemis gèlent pendant 3 secondes).
  • Système de combo : plus tu tues vite, plus tu marques de points. Un « combo multiplier » qui monte.
  • Le boss a ses propres drops de power-up : le boss laisse tomber un power-up rare quand il est vaincu.

Ta propre idée

Tu as ta propre idée ? Top. Parles-en vite à un coach et commence à construire.

Astuces pour planifier ta feature

Avant de commencer à écrire du code, réponds à ces questions :

  1. Que doit voir le joueur ? (un nouveau power-up, un texte, une icône ?)
  2. Quand est-ce que ça arrive ? (quand tu appuies sur ESPACE, quand un ennemi meurt, quand la wave 10 commence ?)
  3. Combien de temps ça dure ? (5 secondes ? Pour toujours ? Jusqu’à la wave suivante ?)
  4. Qu’est-ce qui doit changer dans le code ? (de nouvelles variables ? une nouvelle liste ? un timer ?)
  5. Comment je sais que ça marche ? (c’est quoi le « check » — qu’est-ce que je dois voir pour savoir que c’est fini ?)

Écris tes réponses sur papier ou en commentaire en haut du fichier.

Cheatsheets des sessions précédentes

Tu ne te souviens plus de quelque chose ? Utilise les cheatsheets des fois précédentes :

Planification guidée par le coach

Cette partie, tu la remplis avec un coach avant de commencer à coder.

Ma feature : _________________________________________________

Je choisis :   Facile  /  Moyen  /  Difficile  /  Ma propre idée

Nouvelles variables dont j'ai besoin :
- __________________________________
- __________________________________
- __________________________________

Nouvelles images ou nouveaux sons :
- __________________________________
- __________________________________

Check : comment je sais que ça marche ?
- __________________________________

Showcase

À la fin de la session, tu montres à un coach et à ton buddy ce que tu as construit. Raconte en 30 secondes :

  • Ce que tu voulais faire
  • Si ça a marché
  • Ce qui a été le plus difficile

Plan d’étapes (pour quand tu n’y arrives pas tout seul)

  1. Ouvre main.py dans Thonny et clique sur Run — est-ce que ça marche encore ?
  2. Fais une copie du dossier du jeu au cas où tu bloquerais.
  3. Commence par le plus petit changement possible (par exemple ajouter une variable).
  4. Teste. Ça marche ? → Étape suivante. Ça ne marche pas ? → Demande à un coach.

À la prochaine !

« La prochaine fois : un jeu complètement nouveau. Ce sera quoi ? »

30 octobre 2026, 15:59

Progression par session

Session DDAprès le curriculumQuoi de neuf ?Snapshot
1S2Vaisseau spatial + astéroïdes + vie + explosions(à suivre)
2S3Tirer + ennemis + score + vagues(à suivre)
3S4 (Pygame)Reconstruit en Pygame avec sprites + son(à suivre)
4S5Menu + 3 types d’ennemis(à suivre)
5S6Étoiles en parallaxe + particules + astéroïdes qui se divisent(à suivre)
6S7Boss fight en 3 phases + barre de HP(à suivre)
7S8Ta propre version (power-ups, high score, …)(à suivre)
30 octobre 2026, 15:59

Ressources

(Contenu à venir ; cette section sera complétée plus tard.)

30 octobre 2026, 15:59

Sous-sections de Ressources

Assets gratuits

Avec de bons sprites, des effets sonores et de la musique, ton jeu a tout de suite l’air plus pro, et ça ne doit rien te coûter. Ci-dessous, tu trouves les meilleurs endroits pour chercher des assets gratuits, bien rangés par catégorie.

Sprites & tilesets

  • Kenney.nl : Le conseil par excellence. Kenney crée des centaines de packs de sprites, de tilesets et d’éléments d’interface, tous publiés en CC0 (domaine public). Tu n’as pas besoin d’attribution et tu peux tout utiliser, même dans des projets commerciaux. Commence ici.
  • OpenGameArt.org : Grande communauté avec des sprites, des tilesets et des animations dans tous les styles. Fais quand même attention à la licence de chaque asset : certains sont en CC0, d’autres en CC-BY ou CC-BY-SA. Filtre sur la licence pour éviter les surprises.
  • itch.io assets de jeux gratuits : Beaucoup d’artistes indé mettent des packs gratuits sur itch.io. La qualité varie, mais il y a de vraies pépites. Regarde toujours le texte de licence sur la page de l’auteur.

Effets sonores

  • Freesound.org : Énorme bibliothèque d’effets sonores du monde entier. Filtre les résultats sur « Creative Commons 0 » pour ne voir que les sons CC0 : là, tu n’as personne à créditer.
  • Kenney audio packs : Pour le son aussi, Kenney livre des packs CC0 prêts à l’emploi : sons rétro, clics d’interface, explosions, tout en un seul téléchargement.
  • sfxr.me : Génère tes propres effets sonores 8 bits dans le navigateur. Clique sur une catégorie (laser, explosion, powerup…), règle les curseurs comme tu veux et télécharge le .wav. Aucun souci de licence : c’est toi qui le génères.

Musique

  • Incompetech : Kevin MacLeod a composé des centaines de morceaux dans tous les genres, du chiptune à l’orchestre. La musique est gratuite sous CC-BY : tu mentionnes simplement « Music by Kevin MacLeod (incompetech.com) » quelque part dans tes crédits ou dans ton README.
  • Pixabay music : Des morceaux publiés en CC0 ou sous leur propre licence libre. Tu n’as personne à créditer et tu peux les utiliser dans n’importe quel projet.

Polices

  • Google Fonts : Des milliers de polices open source que tu peux télécharger et utiliser gratuitement, aussi dans des jeux. Tu cherches un look rétro ? Cherche « pixel » ou « monospace » pour des polices qui marchent bien dans Pygame (pygame.font.Font).

Les licences expliquées

Tous les assets « gratuits » ne se valent pas. Voici les trois licences que tu rencontres le plus souvent :

LicenceTu peux l’utiliser ?Attribution obligatoire ?Usage commercial ?
CC0OuiNonOui
CC-BYOuiOui, cite l’auteurOui
CC-BY-NCOuiOuiNon

Conseil pratique : en cas de doute, prends du CC0. Tu n’as pas besoin d’autorisation, tu n’as personne à créditer et tu ne risques jamais d’enfreindre les règles sans le vouloir. Kenney.nl est ton meilleur ami.


Regarde comment nous documentons les assets dans ce projet sur la page Licences des assets.

30 octobre 2026, 15:59

Licences des assets (ce projet)

La plupart des assets sont en CC0 (domaine public). Les exceptions sont indiquées dans le tableau avec la licence et le texte de crédit obligatoire.

Images

FichierSourceLicenceAuteurDate de téléchargement
basket.pngKenney Space Shooter ReduxCC0Kenney (kenney.nl)2026-05-11
star.pngKenney Space Shooter ReduxCC0Kenney (kenney.nl)2026-05-11
ship.pngKenney Space Shooter ReduxCC0Kenney (kenney.nl)2026-05-11
challenges/01-snake/fruits/*.png (9 fichiers)Kenney Food KitCC0Kenney (kenney.nl)2026-05-24

Les fichiers se trouvent dans static/_shared/images/ et sont disponibles sur le chemin d’URL publié /_shared/images/<nom-de-fichier>.

Sons

FichierSourceLicenceAuteurDate de téléchargement
shoot.wavCC02026-05-11
hit.wavCC02026-05-11
explosion.wavCC02026-05-11
pickup.wavCC02026-05-11
jump.wavCC02026-05-11
music.oggincompetech.comCC-BY 4.0Kevin MacLeod2026-05-17

Crédit obligatoire pour music.ogg

“Ethereal Relaxation” Kevin MacLeod (incompetech.com)
Licensed under Creative Commons: By Attribution 4.0
creativecommons.org/licenses/by/4.0

Comment ajouter des assets

  1. Télécharge depuis une source CC0 (kenney.nl, freesound.org avec le filtre Creative Commons 0).
  2. Place le fichier dans static/_shared/images/ ou static/_shared/sounds/.
  3. Mets à jour une ligne dans le tableau ci-dessus avec la source, la licence, l’auteur et la date.
  4. Pour un asset non CC0 (par ex. CC-BY) : mets le texte de crédit sous le tableau.
30 octobre 2026, 15:59

Publier avec pygbag

Tu as fait un jeu sympa et maintenant tu veux le partager avec le reste du monde. Avec pygbag, tu transformes ton jeu Pygame en une page web que tout le monde peut jouer dans le navigateur. Pas d’installation, pas d’embêtements. Tu envoies un lien et c’est tout !

Qu’est-ce que pygbag ?

Pygbag compile ton code Python en WebAssembly et l’emballe avec un petit runtime Pygame qui tourne dans le navigateur. Le joueur n’a rien à installer : il ouvre la page et il joue. C’est donc parfait pour partager ton jeu avec tes amis, ta famille ou sur itch.io.

Limitations

Pygbag ne fonctionne pas avec Pgzero (la bibliothèque simplifiée des premières sessions). Il te faut du vrai Pygame, donc c’est disponible à partir de la session 4 et après.

En plus, quelques choses ne marchent pas dans le navigateur :

  • Pas d’accès au disque : tu ne peux pas lire ni écrire de fichiers depuis le jeu.
  • Pas de threads : n’utilise pas threading ni multiprocessing.
  • Pas d’appels bloquants : tout doit se passer en asynchrone (voir ci-dessous).

Installation

Dans un projet uv :

uv add pygbag

Ou dans Thonny via le gestionnaire de paquets :

pip install pygbag

Préparer ton projet

Pygbag exige que ta boucle principale soit asynchrone. Ça veut dire : ta fonction main devient async def main(), et à chaque itération de frame tu ajoutes await asyncio.sleep(0). Cette seule ligne donne au navigateur la chance de respirer entre les frames.

Ci-dessous, tu trouves une structure de base prête à l’emploi : structure de main.py prête pour pygbag :

import asyncio
import pygame

pygame.init()
screen = pygame.display.set_mode((640, 480))
clock = pygame.time.Clock()

async def main():
    running = True
    while running:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
        screen.fill((30, 30, 60))
        pygame.display.flip()
        clock.tick(60)
        await asyncio.sleep(0)  # requis pour pygbag

asyncio.run(main())

Adapte le code de ton propre jeu pour que tout se trouve dans async def main(), et n’oublie pas await asyncio.sleep(0) en bas de la boucle while.

Compiler

Dans ton terminal, va dans le dossier avec main.py et lance :

uv run python -m pygbag --build main.py

Le résultat apparaît dans le dossier build/web/. Ce dossier contient tout ce qu’il faut pour héberger ton jeu.

Tester en local

Tu veux d’abord voir si ça marche avant de publier ? Utilise la même commande sans --build :

uv run python -m pygbag main.py

Pygbag démarre un serveur web local sur http://localhost:8000. Ouvre ce lien dans ton navigateur et tu joues à ton propre jeu, exactement comme les autres le verront.

Publier

Si tout fonctionne, il y a deux façons de partager ton jeu :

  1. Via le coach : zippe le dossier build/web/ et donne le fichier zip à ton coach. C’est lui qui s’occupe de l’hébergement.
  2. Via itch.io : crée un compte gratuit sur itch.io, crée un nouveau projet en jeu HTML et téléverse le zip de build/web/. En quelques minutes, ton jeu a sa propre page que tout le monde peut visiter !

Félicitations ! Tu viens de publier un vrai jeu web. 🎮

30 octobre 2026, 15:59

Guide de traduction

Ce site existe en néerlandais, en français et en anglais. Cette page explique comment les traductions sont organisées, pour que tu puisses les entretenir sans casser la structure.

Comment les langues sont enregistrées

Chaque page a un fichier par langue, dans le même dossier :

content/sessions/python/01-catch-the-stars/_index.md      ← Nederlands (standaardtaal)
content/sessions/python/01-catch-the-stars/_index.en.md   ← Engels
content/sessions/python/01-catch-the-stars/_index.fr.md   ← Frans
  • Le néerlandais est à la racine (/sessions/...), le français et l’anglais sous /fr/ et /en/ avec le même chemin.
  • S’il manque une traduction, le sélecteur de langue affiche quand même cette langue, mais il mène à la page d’accueil de cette langue. Jamais de lien mort.
  • Tu ajoutes une nouvelle page ? Crée alors tout de suite les trois fichiers. title, weight, hidden et description doivent figurer dans chaque langue ; weight et hidden restent identiques.

Ce que tu ne traduis pas

  • Les identifiants de code (basket, star, ship, score) restent en anglais, parce qu’ils sont dans le fichier Python.
  • Les noms de fichiers (star.png, boom.wav, starter.zip) restent neutres en langue.
  • Les noms de produits : Pygame, Pgzéro/Pgzero, Thonny, PyCharm, VS Code, uv, Python, Git, GitHub, pygbag.
  • Les termes dojo que nous utilisons comme emprunts : ninja, coach, dojo, cheatsheet, cliffhanger, starter, checkpoint, Dojo Defender.

Ce que tu traduis, par contre

  • Tout le texte en prose, les intertitres, les titres et les champs description.
  • Les commentaires et les docstrings dans les blocs de code ; les identifiants et les chaînes dont le programme a vraiment besoin restent tels quels.
  • Les libellés des démos interactives (curseurs, textes sur le canvas).
  • Les notes du coach et les suggestions « à emporter chez toi ».

Termes fixes

NéerlandaisAnglaisFrançais
sessiesessionsession
uitdagingchallengedéfi
werkbladworksheetfiche de travail
oplossingsolutionsolution
bronnenresourcesressources
installerensetupinstallation
coach-notitiescoach notesnotes du coach
Wat je vandaag leertWhat you’ll learn todayCe que tu vas apprendre aujourd’hui
Neem mee naar huisTake it homeÀ emporter chez toi
Vastgelopen?Stuck?Bloqué ?
Tot de volgende keer!See you next time!À la prochaine !

Ton : le néerlandais utilise « je », l’anglais « you », le français « tu » (tutoiement) — les textes sont pour des ninjas de 10 à 17 ans.

Liens et téléchargements

  • Pour les liens vers d’autres pages, tu utilises {{% relref "/sessions/python/01-catch-the-stars" %}}, pour qu’ils suivent automatiquement la bonne langue.
  • Les liens vers des fichiers dans static/ (images, JS des démos, ZIP) sont absolus et neutres en langue.
  • Les ZIP avec du code existent par langue : starter.zip (néerlandais), starter.en.zip et starter.fr.zip. Chaque page de langue renvoie vers son propre ZIP. Les packs d’assets sans code (images.zip, fruits.zip) n’ont pas de variante par langue.

Code par langue

Le code source se trouve dans code/. Les commentaires sont en néerlandais ; les traductions se trouvent à côté de l’original sous main.en.py et main.fr.py. Lors de la création des ZIP, <naam>.<taal>.py est renommé en <naam>.py et les variantes des autres langues sont retirées. make zips s’en occupe.

Démos interactives

Chaque démo JS dans static/sessions/ a en haut une table STRINGS avec le néerlandais, l’anglais et le français. La langue vient de l’attribut lang de la page ; sans table ou avec une langue inconnue, la démo retombe sur le néerlandais.

Vérification avant de pusher

make build

Le build échoue sur un relref cassé. Ensuite, vérifie les trois langues de la page modifiée : le titre, les intertitres, les liens et les téléchargements doivent fonctionner de la même façon dans les trois.