Pygame
Créer des jeux 2D en Python — fenêtre, boucle de jeu, sprites, collisions, sons, HUD, et architecture avec système de scènes. Prérequis : POO Python.
Introduction & installation
Pygame est une bibliothèque Python pour créer des jeux 2D. Elle fournit tout le nécessaire : fenêtre graphique, gestion des événements clavier/souris, affichage d'images et de formes, sons, et horloge pour contrôler le framerate. Elle est idéale pour apprendre les bases du développement de jeux.
# Installation via pip
pip install pygame
# Vérifier l'installation
python -m pygame.examples.aliens # jeu de démo inclus
# Dans VS Code — terminal intégré
pip install pygame --upgrade
| Module Pygame | Rôle |
|---|---|
pygame.display | Fenêtre et surface d'affichage |
pygame.event | File d'événements clavier/souris/fenêtre |
pygame.sprite | Sprites et groupes de sprites |
pygame.image | Chargement d'images |
pygame.draw | Dessin de formes géométriques |
pygame.font | Rendu de texte |
pygame.mixer | Sons et musique |
pygame.time | Horloge et FPS |
pygame.math | Vecteurs 2D et 3D |
Fenêtre & boucle de jeu
import pygame
from pygame.locals import *
# ── Initialisation ──────────────────────────
pygame.init()
pygame.mixer.init()
WIDTH, HEIGHT = 800, 600
FPS = 60
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Mon Jeu")
clock = pygame.time.Clock()
# ── Couleurs ─────────────────────────────────
BLACK = (0, 0, 0 )
WHITE = (255, 255, 255)
RED = (220, 50, 50 )
# ── Boucle principale ────────────────────────
running = True
while running:
# 1. Événements
for event in pygame.event.get():
if event.type == QUIT:
running = False
# 2. Mise à jour de la logique
# ... (déplacements, collisions…)
# 3. Dessin
screen.fill(BLACK)
# ... (draw calls)
pygame.display.flip() # afficher le frame
# 4. Limiter le FPS
clock.tick(FPS)
pygame.quit()
La boucle de jeu tourne 60 fois par seconde. À chaque itération, elle suit toujours le même ordre :
clavier, souris, quitter…
déplacements, IA, physique…
screen.fill → sprites → HUD
display.flip + clock.tick
clock.tick(60) retourne le nombre de millisecondes écoulées depuis le dernier appel (delta time). Pour des mouvements indépendants du FPS : dt = clock.tick(60) / 1000, puis multiplier les vitesses par dt.
Événements & clavier
for event in pygame.event.get():
# Fermer la fenêtre
if event.type == QUIT:
running = False
# Touche appuyée (une seule fois)
if event.type == KEYDOWN:
if event.key == K_ESCAPE:
running = False
if event.key == K_SPACE:
player.jump()
if event.key == K_r:
game.reset()
# Touche relâchée
if event.type == KEYUP:
if event.key == K_SPACE:
player.stop_jump()
# Clic souris
if event.type == MOUSEBUTTONDOWN:
if event.button == 1: # bouton gauche
pos = event.pos # (x, y)
player.shoot(pos)
# Touches maintenues enfoncées (mouvement continu)
keys = pygame.key.get_pressed()
if keys[K_LEFT]: player.move(-1)
if keys[K_RIGHT]: player.move( 1)
if keys[K_UP]: player.move_y(-1)
if keys[K_DOWN]: player.move_y( 1)
event.key — code de la toucheevent.mod — modificateurs (Shift, Ctrl…)event.unicode — caractère tapéevent.pos — (x, y) du clicevent.button — 1=gauche, 2=milieu, 3=droitevent.button — 4/5 = moletteevent.pos — position actuelleevent.rel — déplacement relatifevent.buttons — boutons enfoncésK_LEFT K_RIGHT K_UP K_DOWNK_SPACE K_RETURN K_ESCAPEK_a … K_z — lettresK_F1 … K_F12 — fonctionsDifférence clé : KEYDOWN se déclenche une seule fois à l'appui (idéal pour tirer, sauter). key.get_pressed() retourne l'état continu (idéal pour le déplacement).
Dessin & couleurs
# Rectangle surface, couleur, (x, y, w, h), [épaisseur]
pygame.draw.rect(screen, RED, (100, 50, 80, 40))
pygame.draw.rect(screen, WHITE, (100, 50, 80, 40), 2) # contour
# Cercle surface, couleur, centre, rayon, [épaisseur]
pygame.draw.circle(screen, (0,200,255), (400, 300), 30)
pygame.draw.circle(screen, WHITE, (400, 300), 30, 2)
# Ligne surface, couleur, départ, arrivée, [épaisseur]
pygame.draw.line(screen, WHITE, (0, 300), (800, 300), 1)
# Polygone surface, couleur, [(x1,y1), (x2,y2), …]
pygame.draw.polygon(screen, (255,200,0), [(400,100),(450,200),(350,200)])
# Surface avec transparence
surf = pygame.Surface((200, 100), pygame.SRCALPHA)
surf.fill((255, 0, 0, 100)) # RGBA — alpha=100
screen.blit(surf, (100, 200))
# Rect utilitaire (très pratique)
rect = pygame.Rect(100, 200, 80, 40)
rect.center # → (140, 220)
rect.centerx # → 140
rect.move(10, 0) # retourne un nouveau Rect déplacé
# blit = "block image transfer" = coller une surface sur une autre
screen.blit(image, (x, y)) # coin haut-gauche
screen.blit(image, image.get_rect( # centré
center=(WIDTH//2, HEIGHT//2)))
# Créer une surface de couleur unie
bg = pygame.Surface((WIDTH, HEIGHT))
bg.fill((20, 20, 40))
screen.blit(bg, (0, 0))
# Transformer une image
img = pygame.image.load("player.png").convert_alpha()
img_scaled = pygame.transform.scale(img, (64, 64))
img_rot = pygame.transform.rotate(img, 45) # degrés
img_flip = pygame.transform.flip(img, True, False) # miroir H
Toujours appeler .convert() ou .convert_alpha() après pygame.image.load() — cela convertit l'image au format de la surface d'affichage et accélère considérablement le rendu.
Sprites & images
class Player(pygame.sprite.Sprite):
def __init__(self, x, y):
super().__init__()
# image et rect sont obligatoires pour pygame.sprite
self.image = pygame.image.load("player.png").convert_alpha()
self.image = pygame.transform.scale(self.image, (48, 48))
self.rect = self.image.get_rect(center=(x, y))
# Vecteur de vitesse (recommandé : pygame.math.Vector2)
self.vel = pygame.math.Vector2(0, 0)
self.speed = 5
self.health = 3
def update(self):
keys = pygame.key.get_pressed()
self.vel.x = 0
if keys[K_LEFT]: self.vel.x = -self.speed
if keys[K_RIGHT]: self.vel.x = self.speed
self.rect.x += self.vel.x
# Garder dans les limites de l'écran
self.rect.clamp_ip(screen.get_rect())
def draw(self, surface):
surface.blit(self.image, self.rect)
class Bullet(pygame.sprite.Sprite):
def __init__(self, x, y):
super().__init__()
# Image créée par le code (pas de fichier)
self.image = pygame.Surface((6, 14), pygame.SRCALPHA)
pygame.draw.rect(self.image, (255, 220, 0), (0,0,6,14), border_radius=3)
self.rect = self.image.get_rect(centerx=x, bottom=y)
self.speedy = -8
def update(self):
self.rect.y += self.speedy
if self.rect.bottom < 0:
self.kill() # retire du groupe automatiquement
class AnimatedSprite(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
sheet = pygame.image.load("walk.png").convert_alpha()
# Découper 4 frames de 48×48 sur une ligne
self.frames = [
sheet.subsurface((48*i, 0, 48, 48))
for i in range(4)
]
self.frame_idx = 0
self.anim_timer = 0
self.image = self.frames[0]
self.rect = self.image.get_rect()
def animate(self, dt):
self.anim_timer += dt
if self.anim_timer > 120: # changer frame toutes les 120ms
self.anim_timer = 0
self.frame_idx = (self.frame_idx + 1) % len(self.frames)
self.image = self.frames[self.frame_idx]
Groupes de sprites
# Créer les groupes
all_sprites = pygame.sprite.Group()
bullets = pygame.sprite.Group()
enemies = pygame.sprite.Group()
# Ajouter un sprite à un ou plusieurs groupes
player = Player(400, 500)
all_sprites.add(player)
# Créer plusieurs ennemis
for i in range(10):
e = Enemy(i * 70 + 50, 80)
all_sprites.add(e)
enemies.add(e)
# Dans la boucle — update et draw en une ligne
all_sprites.update() # appelle .update() sur tous
all_sprites.draw(screen) # blit de tous les .image sur .rect
# Tirer une balle
def shoot():
b = Bullet(player.rect.centerx, player.rect.top)
all_sprites.add(b)
bullets.add(b)
# Supprimer un sprite de tous ses groupes
enemy.kill()
Un sprite peut appartenir à plusieurs groupes simultanément. On utilise généralement un groupe all_sprites pour le rendu, et des groupes spécialisés (bullets, enemies) pour les collisions et la logique.
# Group — groupe standard, sprites dans un set
g = pygame.sprite.Group()
# GroupSingle — un seul sprite (joueur, curseur…)
player_group = pygame.sprite.GroupSingle(player)
# LayeredUpdates — rendu par couches (z-index)
layers = pygame.sprite.LayeredUpdates()
layers.add(background, layer=0)
layers.add(player, layer=1)
layers.add(hud, layer=2)
Collisions
# ── Collision entre deux sprites ──────────────
# Rect vs Rect (la plus rapide)
if pygame.sprite.collide_rect(player, enemy):
player.take_damage()
# Cercle vs Cercle (besoin de radius sur le sprite)
if pygame.sprite.collide_circle(bullet, enemy):
enemy.kill()
# Pixel vs Pixel (précise mais lente — utiliser avec masques)
mask_p = pygame.mask.from_surface(player.image)
mask_e = pygame.mask.from_surface(enemy.image)
# ── Collision sprite vs groupe ─────────────────
# Un sprite contre tous dans un groupe
hits = pygame.sprite.spritecollide(
player, enemies, False # False = ne pas tuer les ennemis
)
for hit in hits:
player.health -= 1
# Tuer le sprite touché
pygame.sprite.spritecollide(player, enemies, True)
# Groupe vs Groupe (ex: balles vs ennemis)
hits = pygame.sprite.groupcollide(
bullets, enemies,
True, # tuer la balle
True # tuer l'ennemi
)
score += len(hits) * 100
class Player(pygame.sprite.Sprite):
def __init__(self, x, y):
super().__init__()
self.image = pygame.image.load("ship.png").convert_alpha()
self.rect = self.image.get_rect(center=(x, y))
# Masque basé sur les pixels non-transparents
self.mask = pygame.mask.from_surface(self.image)
# Collision masque vs masque dans spritecollide
hits = pygame.sprite.spritecollide(
player, enemies, True,
collided=pygame.sprite.collide_mask # ← précision pixel
)
| Méthode | Précision | Coût CPU |
|---|---|---|
collide_rect | Rectangle entourant | ⚡ Très rapide |
collide_circle | Cercle englobant | ⚡ Rapide |
collide_mask | Pixel par pixel | 🐢 Lent |
Stratégie courante : utiliser collide_rect pour filtrer rapidement, puis collide_mask uniquement sur les candidats proches.
Physique & mouvements
class PlatformPlayer(pygame.sprite.Sprite):
GRAVITY = 0.5
JUMP_SPEED = -12
def __init__(self, x, y):
super().__init__()
self.image = pygame.Surface((32, 48))
self.image.fill((100, 180, 255))
self.rect = self.image.get_rect(topleft=(x, y))
self.vel = pygame.math.Vector2(0, 0)
self.on_ground = False
def jump(self):
if self.on_ground:
self.vel.y = self.JUMP_SPEED
self.on_ground = False
def update(self, platforms):
# Gravité
self.vel.y += self.GRAVITY
self.vel.y = min(self.vel.y, 15) # vitesse max de chute
# Déplacement horizontal
keys = pygame.key.get_pressed()
self.vel.x = 0
if keys[K_LEFT]: self.vel.x = -5
if keys[K_RIGHT]: self.vel.x = 5
self.rect.x += self.vel.x
self._collide_platforms_h(platforms)
self.rect.y += self.vel.y
self._collide_platforms_v(platforms)
def _collide_platforms_v(self, platforms):
self.on_ground = False
for plat in platforms:
if self.rect.colliderect(plat.rect):
if self.vel.y > 0: # tombait vers le bas
self.rect.bottom = plat.rect.top
self.vel.y = 0
self.on_ground = True
from pygame.math import Vector2
class Enemy(pygame.sprite.Sprite):
def __init__(self, x, y):
super().__init__()
self.pos = Vector2(x, y)
self.vel = Vector2(0, 0)
self.speed = 2
def update(self, target):
# Se diriger vers la cible
direction = Vector2(target.rect.center) - self.pos
if direction.length() > 0:
direction = direction.normalize()
self.vel = direction * self.speed
self.pos += self.vel
self.rect.center = (int(self.pos.x), int(self.pos.y))
Texte & HUD
# Initialiser le moteur de polices (dans __init__)
pygame.font.init()
# Police système ou fichier .ttf
font_sm = pygame.font.SysFont("Arial", 20)
font_lg = pygame.font.SysFont("Arial", 48, bold=True)
font_px = pygame.font.Font("assets/pixel.ttf", 24) # .ttf custom
# Rendre du texte → Surface
# render(texte, antialias, couleur, [fond])
score_surf = font_sm.render(f"Score : {score}", True, WHITE)
score_rect = score_surf.get_rect(topleft=(10, 10))
screen.blit(score_surf, score_rect)
# Centrer un texte
title = font_lg.render("GAME OVER", True, RED)
screen.blit(title, title.get_rect(center=(WIDTH//2, HEIGHT//2)))
class HUD:
def __init__(self):
self.font = pygame.font.SysFont("monospace", 20, bold=True)
def draw(self, surface, score, lives, health, level):
# Score en haut à gauche
self._text(surface, f"SCORE {score:06d}", WHITE, (10, 10))
# Vies en haut à droite
hearts = "♥ " * lives + "♡ " * (3 - lives)
self._text(surface, hearts, RED, (0, 10), right=True)
# Barre de vie
pygame.draw.rect(surface, (60,60,60), (10, 35, 150, 10))
w = int(150 * health / 100)
color = (80,200,80) if health > 50 else (220,80,80)
pygame.draw.rect(surface, color, (10, 35, w, 10))
# Niveau centré en bas
self._text(surface, f"NIVEAU {level}", (180,130,255),
(WIDTH//2, HEIGHT-20), center=True)
def _text(self, surface, txt, color, pos,
right=False, center=False):
surf = self.font.render(txt, True, color)
rect = surf.get_rect()
if right: rect.topright = (WIDTH - 10, pos[1])
elif center: rect.midbottom = pos
else: rect.topleft = pos
surface.blit(surf, rect)
Sons & musique
# Initialiser le mixer (dans le démarrage du jeu)
pygame.mixer.init(frequency=44100, size=-16, channels=2)
# Charger les sons (WAV ou OGG recommandé)
class SoundManager:
def __init__(self):
self.sounds = {
"shoot": pygame.mixer.Sound("assets/shoot.wav"),
"explode": pygame.mixer.Sound("assets/explode.wav"),
"pickup": pygame.mixer.Sound("assets/pickup.ogg"),
}
# Régler le volume (0.0 → 1.0)
self.sounds["shoot"].set_volume(0.3)
self.sounds["explode"].set_volume(0.7)
def play(self, name):
if name in self.sounds:
self.sounds[name].play()
# Utilisation
sfx = SoundManager()
sfx.play("shoot")
sfx.play("explode")
# Charger et jouer (MP3 ou OGG)
pygame.mixer.music.load("assets/theme.mp3")
pygame.mixer.music.set_volume(0.5)
pygame.mixer.music.play(-1) # -1 = boucle infinie
# Contrôles
pygame.mixer.music.pause()
pygame.mixer.music.unpause()
pygame.mixer.music.stop()
pygame.mixer.music.fadeout(2000) # fade en 2 secondes
# Changer de musique (ex: menu → jeu)
def play_music(path, volume=0.5):
pygame.mixer.music.stop()
pygame.mixer.music.load(path)
pygame.mixer.music.set_volume(volume)
pygame.mixer.music.play(-1)
# Détecter la fin de la musique
pygame.mixer.music.set_endevent(pygame.USEREVENT + 1)
for event in pygame.event.get():
if event.type == pygame.USEREVENT + 1:
play_music("assets/next_track.mp3")
Formats recommandés : .ogg pour les effets sonores (petit, libre), .mp3 ou .ogg pour la musique. Éviter les .wav non compressés pour les longues pistes — ils prennent beaucoup de mémoire.
Caméra & scrolling
class Camera:
def __init__(self, world_w, world_h):
self.offset = pygame.math.Vector2(0, 0)
self.world_w = world_w
self.world_h = world_h
def update(self, target):
# Centrer la caméra sur la cible
self.offset.x = target.rect.centerx - WIDTH // 2
self.offset.y = target.rect.centery - HEIGHT // 2
# Empêcher de sortir du monde
self.offset.x = max(0, min(self.offset.x, self.world_w - WIDTH))
self.offset.y = max(0, min(self.offset.y, self.world_h - HEIGHT))
def apply(self, entity):
# Retourne la position à l'écran
return entity.rect.move(-self.offset)
def draw_group(self, surface, group):
for sprite in group:
surface.blit(sprite.image, self.apply(sprite))
# Utilisation dans la boucle
camera = Camera(3200, 1200) # monde 4× plus large que l'écran
# Update + Draw
camera.update(player)
camera.draw_group(screen, all_sprites)
class ParallaxLayer:
def __init__(self, image_path, speed_factor):
self.image = pygame.image.load(image_path).convert()
# Image doit être au moins 2× la largeur de l'écran
self.rect = self.image.get_rect()
self.speed = speed_factor # 0.1 = lent (loin), 1.0 = rapide (proche)
self.scroll = 0.0
def update(self, camera_x):
self.scroll = -(camera_x * self.speed) % WIDTH
def draw(self, surface):
x = int(self.scroll)
surface.blit(self.image, (x, 0))
surface.blit(self.image, (x - WIDTH, 0)) # tuile suivante
# Créer 3 couches (ciel, nuages, montagnes)
layers = [
ParallaxLayer("bg_sky.png", 0.1),
ParallaxLayer("bg_clouds.png", 0.3),
ParallaxLayer("bg_mountains.png", 0.6),
]
Système de scènes
class Scene:
"""Classe de base pour toutes les scènes."""
def __init__(self, manager):
self.manager = manager # référence au gestionnaire
def handle_events(self, events): pass
def update(self): pass
def draw(self, screen): pass
def on_enter(self): pass # appelé à l'arrivée dans la scène
def on_exit(self): pass # appelé au départ de la scène
class SceneManager:
def __init__(self):
self.scenes = {}
self.current = None
self.stack = [] # pile pour pause/retour
def add(self, name, scene):
self.scenes[name] = scene
def switch(self, name):
# Changer de scène (remplace la courante)
if self.current:
self.current.on_exit()
self.current = self.scenes[name]
self.current.on_enter()
def push(self, name):
# Empiler (ex: ouvrir le menu pause sans détruire le jeu)
if self.current:
self.stack.append(self.current)
self.current.on_exit()
self.current = self.scenes[name]
self.current.on_enter()
def pop(self):
# Retourner à la scène précédente
if self.stack:
self.current.on_exit()
self.current = self.stack.pop()
self.current.on_enter()
class MenuScene(Scene):
def on_enter(self):
pygame.mixer.music.load("assets/menu.mp3")
pygame.mixer.music.play(-1)
self.font = pygame.font.SysFont("Arial", 48, bold=True)
def handle_events(self, events):
for e in events:
if e.type == KEYDOWN and e.key == K_RETURN:
self.manager.switch("game")
if e.type == KEYDOWN and e.key == K_ESCAPE:
pygame.quit(); exit()
def draw(self, screen):
screen.fill((10, 10, 30))
title = self.font.render("SPACE SHOOTER", True, (249,115,22))
screen.blit(title, title.get_rect(center=(WIDTH//2, 200)))
class PauseScene(Scene):
def handle_events(self, events):
for e in events:
if e.type == KEYDOWN and e.key == K_p:
self.manager.pop() # revenir au jeu
def draw(self, screen):
# Superposer un voile semi-transparent
overlay = pygame.Surface((WIDTH, HEIGHT), pygame.SRCALPHA)
overlay.fill((0, 0, 0, 150))
screen.blit(overlay, (0, 0))
# ── Boucle principale avec SceneManager ───────
manager = SceneManager()
manager.add("menu", MenuScene(manager))
manager.add("game", GameScene(manager))
manager.add("over", GameOverScene(manager))
manager.add("pause", PauseScene(manager))
manager.switch("menu")
while running:
events = pygame.event.get()
for e in events:
if e.type == QUIT: running = False
if e.type == KEYDOWN and e.key == K_p:
manager.push("pause")
manager.current.handle_events(events)
manager.current.update()
manager.current.draw(screen)
pygame.display.flip()
clock.tick(FPS)
Mini-projet — Space Shooter
Ce mini-projet intègre tous les concepts vus : boucle de jeu, sprites, groupes, collisions, sons, HUD et système de scènes. Structure en 6 fichiers.
space_shooter/
├── main.py ← point d'entrée, boucle + SceneManager
├── settings.py ← constantes (WIDTH, HEIGHT, FPS, couleurs)
├── scenes/
│ ├── __init__.py
│ ├── menu.py ← MenuScene
│ ├── game.py ← GameScene (logique principale)
│ └── gameover.py ← GameOverScene
├── entities/
│ ├── __init__.py
│ ├── player.py ← Player(Sprite)
│ ├── enemy.py ← Enemy(Sprite)
│ └── bullet.py ← Bullet(Sprite)
└── assets/
├── player.png
├── enemy.png
├── shoot.wav
└── theme.mp3
import pygame, random
from pygame.locals import *
from scenes.base import Scene
from entities.player import Player
from entities.enemy import Enemy
from entities.bullet import Bullet
from settings import WIDTH, HEIGHT
class GameScene(Scene):
def on_enter(self):
self.all_sprites = pygame.sprite.Group()
self.bullets = pygame.sprite.Group()
self.enemies = pygame.sprite.Group()
self.player = Player(WIDTH // 2, HEIGHT - 80)
self.all_sprites.add(self.player)
self.score = 0
self.wave = 1
self.spawn_timer = 0
self.shoot_cooldown = 0
self.sfx_shoot = pygame.mixer.Sound("assets/shoot.wav")
self.sfx_explode = pygame.mixer.Sound("assets/explode.wav")
pygame.mixer.music.load("assets/theme.mp3")
pygame.mixer.music.play(-1)
def handle_events(self, events):
for e in events:
if e.type == KEYDOWN and e.key == K_p:
self.manager.push("pause")
def update(self):
self.all_sprites.update()
# Tir automatique maintenu
keys = pygame.key.get_pressed()
self.shoot_cooldown -= 1
if keys[K_SPACE] and self.shoot_cooldown <= 0:
b = Bullet(self.player.rect.centerx,
self.player.rect.top)
self.all_sprites.add(b)
self.bullets.add(b)
self.sfx_shoot.play()
self.shoot_cooldown = 12
# Spawn d'ennemis
self.spawn_timer += 1
if self.spawn_timer > 60 - self.wave * 5:
self.spawn_timer = 0
e = Enemy(random.randint(30, WIDTH-30), -30)
self.all_sprites.add(e)
self.enemies.add(e)
# Collisions balles ↔ ennemis
hits = pygame.sprite.groupcollide(
self.bullets, self.enemies, True, True)
for _ in hits:
self.score += 100
self.sfx_explode.play()
# Collision joueur ↔ ennemis
if pygame.sprite.spritecollide(
self.player, self.enemies, True):
self.player.health -= 1
if self.player.health <= 0:
self.manager.switch("over")
# Monter de vague tous les 1000 points
self.wave = 1 + self.score // 1000
def draw(self, screen):
screen.fill((5, 5, 20))
self.all_sprites.draw(screen)
# HUD
font = pygame.font.SysFont("monospace", 20, bold=True)
s = font.render(f"SCORE {self.score:06d} VAGUE {self.wave}",
True, (249,115,22))
screen.blit(s, (10, 10))
h = font.render(f"♥ {self.player.health}", True, (239,68,68))
screen.blit(h, h.get_rect(topright=(WIDTH-10, 10)))
Cheat Sheet Pygame
🪟 Fenêtre & boucle
pygame.init() | Initialiser tous les modules |
display.set_mode((w,h)) | Créer la fenêtre |
display.flip() | Afficher le frame |
clock.tick(fps) | Limiter et mesurer le temps |
event.get() | Lire les événements |
key.get_pressed() | État continu des touches |
🖼️ Sprites & groupes
Sprite.__init__ | Appeler super().__init__() |
self.image | Surface du sprite (obligatoire) |
self.rect | Position et hitbox (obligatoire) |
group.add(sprite) | Ajouter au groupe |
group.update() | Appeler update() sur tous |
sprite.kill() | Retirer de tous les groupes |
💥 Collisions
collide_rect(a, b) | Deux sprites |
spritecollide(s, g, kill) | Sprite vs groupe |
groupcollide(g1,g2,k1,k2) | Groupe vs groupe |
collide_mask | Précision pixel (lent) |
rect.colliderect(r) | Rect vs Rect |
rect.clamp_ip(r) | Garder dans les limites |
🎵 Sons & médias
mixer.Sound("f.wav") | Charger un effet |
sound.play() | Jouer une fois |
mixer.music.load() | Charger la musique |
mixer.music.play(-1) | Jouer en boucle |
image.load().convert_alpha() | Charger une image |
transform.scale(img, (w,h)) | Redimensionner |
# pygame.Rect(x, y, width, height)
rect = pygame.Rect(100, 200, 64, 64)
# Coins
rect.topleft # (100, 200) rect.topright # (164, 200)
rect.bottomleft # (100, 264) rect.bottomright # (164, 264)
# Centres
rect.center # (132, 232)
rect.centerx # 132 rect.centery # 232
rect.midtop # (132, 200) rect.midbottom # (132, 264)
# Dimensions
rect.width # 64 rect.height # 64 rect.size # (64, 64)
# Créer un rect centré (très utile)
image.get_rect(center=(WIDTH//2, HEIGHT//2))
image.get_rect(topleft=(10, 10))
image.get_rect(midbottom=(WIDTH//2, HEIGHT-20))