OUJOOD.COM
Introduction : Découvrez la puissance de Pymunk
Pymunk est une bibliothèque Python de simulation physique 2D qui se distingue par sa facilité d'utilisation et sa puissance. Idéale pour créer des jeux vidéo, des simulations scientifiques ou des démonstrations éducatives, elle permet de simuler des objets rigides en deux dimensions avec un réalisme impressionnant. Pymunk s'appuie sur Chipmunk, un moteur physique 2D reconnu pour ses performances et sa stabilité.
Lancée en 2007, Pymunk bénéficie d'un développement actif continu depuis plus de 18 ans, garantissant compatibilité, stabilité et fonctionnalités modernes. Cette longévité témoigne de la robustesse du projet et de la confiance de la communauté.
Pymunk a fait ses preuves dans des projets de toutes envergures. Elle a notamment été utilisée par les lauréats de trois éditions du concours Pyweek, adoptée par des dizaines de chercheurs pour leurs publications scientifiques, et même intégrée dans des simulations de véhicules autonomes pour l'apprentissage par renforcement. Consultez la section "Showcases" sur le site officiel de Pymunk pour découvrir des cas d'usage inspirants et des démonstrations interactives.
Installation de Pymunk : Méthodes recommandées
L'installation de Pymunk est simple et rapide. Dans la majorité des cas, pip (le gestionnaire de paquets Python) suffit pour récupérer la dernière version stable depuis PyPI :
pip install pymunk
Si vous utilisez Anaconda ou Miniconda pour gérer vos environnements Python, Pymunk est également disponible sur le canal conda-forge. Cette méthode est particulièrement recommandée pour les projets scientifiques nécessitant des dépendances complexes :
conda install -c conda-forge pymunk
Note importante : Assurez-vous d'avoir Python 3.7 ou supérieur installé sur votre système. Pour vérifier votre version Python, utilisez la commande python --version dans votre terminal.
Conventions de nommage des variables dans ce tutoriel
Pour rendre les exemples de code concis et lisibles, nous adoptons des conventions de nommage courtes inspirées des standards de la communauté Pymunk. Cette approche facilite la compréhension rapide du code tout en respectant les bonnes pratiques.
- b = Body (Corps) - représente un objet physique avec masse et vélocité
- c = Constraint (Contrainte) - définit les relations entre les corps
- s = Shape (Forme) - détermine la géométrie visible et les collisions
La classe Vec2d est fondamentale dans Pymunk. Elle représente soit une position absolue dans l'espace 2D, soit un vecteur directionnel entre deux points :
- p = position (point dans l'espace)
- v = vector (vecteur de direction)
Un vecteur se définit mathématiquement comme la différence entre deux positions :
v = p1 - p0 # Vecteur allant du point p0 vers le point p1
Pour les collections d'objets, nous ajoutons un s pour indiquer le pluriel :
- bs = liste de Bodies (corps)
- ps = liste de positions
- vs = liste de vecteurs
Ces conventions s'intègrent naturellement dans les boucles d'itération Python :
for b in bs:
print(b.position, b.velocity) # Affiche position et vitesse de chaque corps
Le corps statique (static body) étant omniprésent dans les simulations Pymunk, nous lui attribuons l'identifiant court b0 :
b0 = space.static_body # Corps statique de l'espace (immobile et de masse infinie)
Le Body : Fondement de la simulation physique
La classe Body (corps) encapsule les propriétés physiques d'un objet dans la simulation. Contrairement aux formes (shapes) qui définissent l'apparence visuelle, le Body décrit comment l'objet se comporte sous l'effet des forces et du mouvement.
Un Body possède huit propriétés essentielles qui définissent son état physique :
- mass - la masse du corps en kilogrammes (affecte l'inertie)
- moment - le moment d'inertie (résistance à la rotation angulaire)
- position - coordonnées (x, y) dans l'espace de simulation
- angle - orientation angulaire en radians
- velocity - vecteur de vitesse linéaire (direction et magnitude)
- angular_velocity - vitesse de rotation angulaire (rad/s)
- force - force résultante appliquée au centre de masse
- torque - couple (moment de force) causant la rotation
Astuce importante : Le moment d'inertie doit être calculé en fonction de la forme et de la masse. Pymunk fournit des fonctions helper comme pymunk.moment_for_circle() pour faciliter ces calculs.
Exemples pratiques : Apprenez par la pratique
Première simulation : Une balle rebondissante
Commençons par un exemple simple mais complet : une balle qui tombe et rebondit sur le sol. Cette simulation illustre les concepts fondamentaux de Pymunk.
Étape 1 : Importation des modules
import pymunk # Moteur physique import pymunk.pygame_util # Intégration avec Pygame import pygame # Bibliothèque graphique
Étape 2 : Initialisation de Pygame et création de la surface d'affichage
Pymunk propose un système de rendu intégré via DrawOptions, idéal pour le prototypage rapide :
pygame.init() size = 640, 240 screen = pygame.display.set_mode(size) draw_options = pymunk.pygame_util.DrawOptions(screen)
Étape 3 : Création de l'espace de simulation
L'objet Space est le conteneur de toute simulation physique 2D. Il gère les collisions, applique la gravité et fait évoluer le système dans le temps :
space = pymunk.Space() space.gravity = 0, -900 # Gravité dirigée vers le bas (900 pixels/s²)
Étape 4 : Création du sol statique
Un segment statique sert de sol. L'élasticité de 1.0 produit un rebond parfait sans perte d'énergie :
b0 = space.static_body segment = pymunk.Segment(b0, (0, 0), (640, 0), 4) # De (0,0) à (640,0), épaisseur 4 segment.elasticity = 1 # Rebond parfait
Étape 5 : Création d'un corps dynamique (la balle)
Un corps dynamique réagit aux forces. La masse et le moment d'inertie déterminent son comportement :
body = pymunk.Body(mass=1, moment=10) body.position = 100, 200 # Position initiale en haut à gauche
Étape 6 : Ajout d'une forme circulaire
La forme (Shape) définit la géométrie visible et les zones de collision :
circle = pymunk.Circle(body, radius=20) circle.elasticity = 0.95 # Légère perte d'énergie à chaque rebond
Étape 7 : Enregistrement dans l'espace
space.add(body, circle, segment) # Ajoute tous les objets à la simulation
Étape 8 : Boucle d'événements principale
Cette boucle gère l'affichage et fait progresser la simulation :
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
screen.fill(GRAY) # Efface l'écran
space.debug_draw(draw_options) # Dessine la simulation
pygame.display.update() # Rafraîchit l'affichage
space.step(0.01) # Avance de 0.01 seconde
pygame.quit()
Création d'une classe App réutilisable
Pour éviter la répétition de code, créons une classe App générique qui encapsule toute la logique commune des simulations Pymunk. Cette approche favorise la réutilisabilité et la maintenabilité.
Fonctionnalités de la classe App :
- Initialisation automatique de Pygame
- Création de la fenêtre avec dimensions paramétrables
- Configuration de l'espace physique Pymunk
- Gestion des options de rendu (DrawOptions)
- Boucle d'événements avec limitation FPS
- Rendu automatique des objets physiques
Importation des dépendances
import pymunk # Moteur physique 2D import pymunk.pygame_util # Outils de rendu Pygame import pygame # Bibliothèque graphique import math # Calculs mathématiques
Définition des constantes
GRAY = (220, 220, 220) # Couleur de fond (gris clair)
Initialisation de l'espace de simulation global
space = pymunk.Space() # Espace physique partagé space.gravity = 0, 900 # Gravité vers le bas (900 px/s²)
Définition de la classe App
class App:
size = 700, 240 # Dimensions par défaut de la fenêtre
def __init__(self):
pygame.init() # Initialise tous les modules Pygame
self.screen = pygame.display.set_mode(self.size)
self.draw_options = pymunk.pygame_util.DrawOptions(self.screen)
self.running = True # Flag de contrôle de la boucle
self.clock = pygame.time.Clock() # Horloge pour réguler les FPS
Méthode run() : Boucle principale de simulation
def run(self):
while self.running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
self.running = False # Arrêt propre de l'application
self.screen.fill(GRAY) # Nettoyage de l'écran
space.debug_draw(self.draw_options) # Rendu de la physique
pygame.display.update() # Mise à jour de l'affichage
space.step(1.0 / 60.0) # Pas de temps fixe (60 FPS)
self.clock.tick(60) # Limite à 60 images/seconde
pygame.quit() # Libération des ressources Pygame
Balle roulant sur un plan incliné
Cet exemple démontre l'importance du frottement (friction) dans les simulations physiques. Sans friction, la balle glisserait ; avec friction, elle roule naturellement.
Enregistrez d'abord la classe App dans un fichier app_class.py dans le même répertoire que votre script principal.
Importation de la classe App personnalisée
from app_class import * # Importe pymunk, space, et App
Création du plan incliné avec friction
b0 = space.static_body segment = pymunk.Segment(b0, (100, 100), (600, 200), 4) # Plan incliné segment.elasticity = 0.5 # Rebond modéré segment.friction = 0.5 # Friction nécessaire pour le roulement space.add(segment)
Création d'une balle avec propriétés de roulement
ball_body = pymunk.Body(mass=1, moment=10) ball_body.position = (110, 90) # Positionnée en haut du plan ball = pymunk.Circle(ball_body, radius=20) ball.elasticity = 0.5 # Légère perte d'énergie ball.friction = 0.5 # ESSENTIEL : sans friction, la balle glisse space.add(ball_body, ball)
Lancement de la simulation
App().run()
Un bloc glissant sur une pente
Contrairement aux cercles, les formes polygonales peuvent glisser sans rouler. La classe Poly permet de créer des boîtes rectangulaires facilement.
Exemple : 📋 Copier le code
from app_class import pymunk, space, App # Création d'un segment statique (mur incliné) segment = pymunk.Segment(space.static_body, (20, 120), (400, 50), 1) # Corps dynamique : boîte rectangulaire body = pymunk.Body(mass=1, moment=10) body.position = (350, 50) # Forme polygonale (boîte de 40x40 pixels) box = pymunk.Poly.create_box(body, (40, 40)) # Ajout à l'espace space.add(body, box, segment) App().run()
Un bloc dévalant une pente avec rebonds
En ajoutant de l'élasticité au bloc, celui-ci rebondit spectaculairement en dévalant la pente. L'élasticité de 0.95 conserve 95% de l'énergie cinétique à chaque collision.
Exemple : 📋 Copier le code
from app_class import pymunk, space, App # Segment statique avec haute élasticité segment = pymunk.Segment(space.static_body, (20, 200), (400, 100), 5) segment.elasticity = 0.95 # Corps et forme avec haute élasticité body = pymunk.Body(mass=1, moment=10) body.position = (350, 50) box = pymunk.Poly.create_box(body, (40, 40)) box.elasticity = 0.95 # Rebonds énergiques space.add(body, box, segment) App().run()
Simulation de particules dans une boîte fermée
Cette simulation crée un conteneur fermé où plusieurs balles peuvent rebondir indéfiniment. L'élasticité proche de 1 (0.999) minimise la perte d'énergie, créant un mouvement quasi-perpétuel.
Création du conteneur rectangulaire
Exemple : 📋 Copier le code
# Définition des 4 coins de la boîte
pts = [(10, 10), (690, 10), (690, 230), (10, 230)]
# Création des 4 murs (segments statiques)
for i in range(4):
seg = pymunk.Segment(space.static_body, pts[i], pts[(i+1)%4], 2)
seg.elasticity = 0.999 # Quasi-parfait (évite l'instabilité de 1.0)
space.add(seg)
# Désactivation de la gravité pour mouvement horizontal
space.gravity = 0, 0
Création d'une balle avec impulsion initiale
Exemple : 📋 Copier le code
from random import randint
# Création de 40 particules avec positions et vitesses aléatoires
for i in range(40):
body = pymunk.Body(mass=1, moment=10)
body.position = randint(40, 660), randint(40, 200)
# Application d'une impulsion initiale aléatoire
impulse = randint(-100, 100), randint(-100, 100)
body.apply_impulse_at_local_point(impulse)
circle = pymunk.Circle(body, radius=5)
circle.elasticity = 0.999
circle.friction = 0.5 # Légère friction pour interaction réaliste
space.add(body, circle)
App().run()
Simulation avancée : Gaz de particules
Cette simulation modélise un gaz idéal avec de nombreuses particules en mouvement brownien. C'est un excellent exemple pour comprendre la thermodynamique computationnelle.
Exemple : 📋 Copier le code
from app_class import pymunk, space, App
from random import randint
# Construction du conteneur fermé
pts = [(10, 10), (690, 10), (690, 230), (10, 230)]
for i in range(4):
seg = pymunk.Segment(space.static_body, pts[i], pts[(i+1)%4], 2)
seg.elasticity = 0.999
space.add(seg)
# Environnement sans gravité
space.gravity = 0, 0
# Génération de 40 particules avec vélocités aléatoires
for i in range(40):
body = pymunk.Body(mass=1, moment=10)
body.position = randint(40, 660), randint(40, 200)
# Impulsion aléatoire pour mouvement chaotique
impulse = randint(-100, 100), randint(-100, 100)
body.apply_impulse_at_local_point(impulse)
circle = pymunk.Circle(body, radius=5)
circle.elasticity = 0.999
circle.friction = 0.5
space.add(body, circle)
App().run()
Contraintes et articulations : Le pendule simple
Les joints (articulations) permettent de relier des corps entre eux. Le PinJoint crée une liaison pivot, idéale pour simuler des pendules, des chaînes ou des mécanismes articulés.
Toutes les articulations statiques utilisent le corps statique de l'espace comme point d'ancrage fixe :
b0 = space.static_body # Point d'ancrage immobile
Création du corps dynamique (masse du pendule)
body = pymunk.Body(mass=1, moment=10) body.position = (100, 100) circle = pymunk.Circle(body, radius=20)
Le PinJoint accepte deux corps et leurs positions locales d'ancrage. L'ancrage statique est placé à (200, 20), créant un pendule de longueur variable :
joint = pymunk.PinJoint(b0, body, (200, 20))
Sous l'effet de la gravité, le pendule oscille naturellement selon les lois de la mécanique.
Code complet du pendule simple
Exemple : 📋 Copier le code
from app_class import pymunk, space, App # Point d'ancrage statique b0 = space.static_body # Masse du pendule body = pymunk.Body(mass=1, moment=10) body.position = (100, 10) circle = pymunk.Circle(body, radius=20) # Articulation à broche (PinJoint) joint = pymunk.PinJoint(b0, body, (200, 20)) space.add(body, circle, joint) App().run()
Table des matières complète du tutoriel
Bienvenue dans ce guide complet sur Pymunk, le moteur physique 2D de référence en Python !
Contenu :
- Introduction et installation de Pymunk
- Conventions de nommage des variables
- Le corps abstrait (Body)
- Exemple : Une balle rebondissante
- Création d'une classe App
- Balle roulant sur une pente
- Bloc glissant sur une pente
- Bloc dévalant une pente
- Une balle dans une boîte
- Plusieurs particules dans une boîte
- Articulation à broche : pendule
- Les formes (Shapes)
- La classe des boîtes
- Une forme composée simple
- La classe des segments
- Un segment mobile
- Segment en forme de L
- La classe des polygones
- Triangles
- Courroie transporteuse
- Articulation à pivot
- Ressort amorti
- Contraintes et articulations
- Articulation à broche
- Articulation à pivot
- Moteurs
- Articulation à glissière
- Joint à rainure
- Joint à ressort rotatif amorti et joint à limite rotative
- Joint d'engrenage
- Autogéométrie
- Utiliser la souris et le clavier
Par carabde | Mis à jour le 8 novembre 2024