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
- Ouvre Thonny.
- Télécharge le starter Dojo Defender, décompresse le ZIP et ouvre
main.py. - 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.
- 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 :
- Son — Ajoute
sounds/explosion.wav quand un astéroïde explose (sounds.explosion.play()). - 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). - Power-up — Ajoute un power-up vert rare qui donne une vie en plus.
- Plus petit — Utilise
asteroid_med ou asteroid_small pour varier la taille et la vitesse.
Télécharger Dojo Defender
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
- Ouvre Thonny.
- Télécharge le starter Dojo Defender d’aujourd’hui, décompresse le ZIP et ouvre
main.py. - Tu n’étais pas là la dernière fois ? Télécharge la solution de la session 1 et commence avec ça.
- Clique sur Run. Tu vois le même jeu que la dernière fois : vaisseau, astéroïdes, explosions.
- 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 :
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 :
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 :
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 :
- Variation d’ennemis — Utilise
enemy_charger.png pour un ennemi plus rapide qui ne fait pas de sinus, mais qui fonce droit sur toi. - Son — Ajoute
sounds/laser.wav et sounds/explosion.wav. - Mode difficile — Les ennemis apparaissent de plus en plus vite, jusqu’à un maximum toutes les 30 frames.
- Multiplicateur de score — Plus la vague est haute, plus tu marques de points par kill :
score += 10 * wave.
Télécharger Dojo Defender
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.
- Télécharge le starter Dojo Defender d’aujourd’hui, décompresse et ouvre
main.py. - Tu n’étais pas là la dernière fois ? Télécharge la solution de la session 2 et essaie de la porter.
- 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 :
| pgzero | raw pygame |
|---|
Actor('plaatje') | GameObject('plaatje.png', x, y) |
keyboard.left | keys[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 :
- Game loop — Cherche la boucle
while running:. Tu vois clock.tick(60), pygame.display.flip() ? - GameObject — Cherche la
class GameObject. Comment une image est-elle chargée ? C’est quoi, rect ? - 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 tiresexplode_sound.play() — quand un ennemi ou un astéroïde explosehit_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 :
- Health bar — Remplace le texte « Vies : 3 » par une barre visuelle : dessine trois petits rectangles en haut.
- Pause — Ajoute une touche P qui met le jeu en pause. Mettre
running = False ne suffit pas — utilise une variable paused séparée. - 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).
- Ton propre skin — Remplace
player_ship.png par ton propre design.
Télécharger Dojo Defender
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.
- Télécharge le starter d’aujourd’hui, décompresse-le et ouvre
main.py. - Tu n’étais pas là ? Télécharge la solution de la session 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 :
- High score — Garde le meilleur score dans un fichier et affiche-le dans le menu.
- Niveau de difficulté — Laisse le joueur choisir entre « Facile » et « Difficile » dans le menu.
- Boss wave — Toutes les 5 waves, un gros boss apparaît avec beaucoup de hits.
- Charger Warning — Dessine une ligne rouge sous un charger avant qu’il n’apparaisse.
Télécharge Dojo Defender
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.
- Télécharge le starter d’aujourd’hui, décompresse-le et ouvre
main.py. - Tu n’étais pas là ? Télécharge la solution de la session 4.
- 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 :
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.pngasteroid_med.png → touché → 2× asteroid_small.pngasteroid_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 ?
- On fait apparaître des particules d’explosion à la position de l’astéroïde
- On vérifie la taille : ‘big’ → 2 ‘med’, ‘med’ → 2 ‘small’, ‘small’ → pas d’autre division
- Les nouveaux astéroïdes apparaissent près de l’ancienne position avec un léger décalage
- 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 :
- Facile : change la couleur des étoiles par couche (par exemple les étoiles lointaines bleutées, les proches jaunes).
- Moyen : ajoute une quatrième couche d’étoiles, encore plus rapide (vitesse 3.0), avec de grandes étoiles lumineuses.
- Difficile : fais changer la couleur des particules pendant leur durée de vie (du jaune au rouge puis au gris).
- Très difficile : ajoute un type de particule « comet » qui a une petite queue.
Télécharge Dojo Defender
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.
- Télécharge le starter d’aujourd’hui, décompresse-le et ouvre
main.py. - Tu n’étais pas là ? Télécharge la solution de la session 5.
- 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 :
- Facile : change la couleur ou la taille du boss via l’image.
- Moyen : ajoute une quatrième phase (HP < 10 %) dans laquelle le boss se téléporte.
- Difficile : fais tirer au boss des delay-bullets qui laissent une traînée.
- Très difficile : ajoute un deuxième type de boss qui apparaît dans une autre wave.
Télécharge Dojo Defender
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 :
- Que doit voir le joueur ? (un nouveau power-up, un texte, une icône ?)
- Quand est-ce que ça arrive ? (quand tu appuies sur ESPACE, quand un ennemi meurt, quand la wave 10 commence ?)
- Combien de temps ça dure ? (5 secondes ? Pour toujours ? Jusqu’à la wave suivante ?)
- Qu’est-ce qui doit changer dans le code ? (de nouvelles variables ? une nouvelle liste ? un timer ?)
- 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)
- Ouvre
main.py dans Thonny et clique sur Run — est-ce que ça marche encore ? - Fais une copie du dossier du jeu au cas où tu bloquerais.
- Commence par le plus petit changement possible (par exemple ajouter une variable).
- 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 ? »
Progression par session
| Session DD | Après le curriculum | Quoi de neuf ? | Snapshot |
|---|
| 1 | S2 | Vaisseau spatial + astéroïdes + vie + explosions | (à suivre) |
| 2 | S3 | Tirer + ennemis + score + vagues | (à suivre) |
| 3 | S4 (Pygame) | Reconstruit en Pygame avec sprites + son | (à suivre) |
| 4 | S5 | Menu + 3 types d’ennemis | (à suivre) |
| 5 | S6 | Étoiles en parallaxe + particules + astéroïdes qui se divisent | (à suivre) |
| 6 | S7 | Boss fight en 3 phases + barre de HP | (à suivre) |
| 7 | S8 | Ta propre version (power-ups, high score, …) | (à suivre) |