Compte le nombre d'occurrences de segments dans une chaîne
Dans ce tutoriel, nous explorerons comment développer des applications en adoptant une approche orientée objet avec le framework de simulation physique 2D Pymunk
Pymunk, une bibliothèque Python pour la simulation de la physique 2D, offre une facilité d'utilisation remarquable. Elle se révèle particulièrement utile chaque fois que vous avez besoin de simuler des objets rigides en deux dimensions dans votre projet Python, que ce soit un jeu, une démonstration ou une simulation. Cette bibliothèque repose solidement sur Chipmunk, une bibliothèque de physique 2D puissante.
Depuis sa première version lancée en 2007, Pymunk continue d'évoluer activement et est maintenu jusqu'à aujourd'hui, cumulant ainsi plus de 15 années de développement continu.
Pymunk a déjà fait ses preuves dans de nombreux projets, qu'ils soient de grande ou petite envergure. Par exemple, elle a été utilisée par les créateurs de trois jeux lauréats du concours Pyweek, par des dizaines de chercheurs ayant publié des articles scientifiques, et même dans le cadre d'une simulation de voiture autonome ! Vous pouvez consulter la section "Vitrines" sur la page Web de Pymunk pour découvrir quelques exemples concrets de son utilisation.
Pour l'installation, dans la plupart des cas, vous pouvez simplement utiliser pip pour récupérer Pymunk depuis PyPI :
pip install pymunk
Si vous préférez utiliser conda, Pymunk est également disponible sur le canal conda-forge et peut être installé ainsi :
conda install -c conda-forge pymunk
Avant de commencer, familiarisez-vous avec certaines conventions utilisées dans ce tutoriel. Afin de rendre les programmes simples et courts, nous utiliserons des noms de variables courts.
Une classe importante est la classe Vec2d, qui indique soit la position absolue d'un point dans l'espace, soit le vecteur de direction entre deux points.
Nous pourrions définir un vecteur comme la différence entre deux points dans l'espace :
v = p1 - p0
Enfin, s sert de marqueur au pluriel.
Nous pouvons utiliser le marqueur au pluriel dans une structure de boucle comme ceci :
for b in bs: print(b)
Le corps statique est fréquemment utilisé, donc nous lui donnons le nom court b0
b0 = space.static_body
Avant de commencer, familiarisez-vous avec certaines conventions utilisées dans ce tutoriel. Afin de rendre les programmes simples et courts, nous utiliserons des noms de variables courts.
Une classe importante est la classe Vec2d, qui indique soit la position absolue d'un point dans l'espace, soit le vecteur de direction entre deux points.
Nous pourrions définir un vecteur comme la différence entre deux points dans l'espace :
v = p1 - p0
Enfin, s sert de marqueur au pluriel.
Nous pouvons utiliser le marqueur au pluriel dans une structure de boucle comme ceci :
for b in bs: print(b)
Le corps statique est fréquemment utilisé, donc nous lui donnons le nom court b0
b0 = space.static_body
La classe Body décrit les aspects physiques d'un objet. Ces aspects ne peuvent pas être vus, mais décrivent comment il se déplace. Six propriétés décrivent l'état d'un corps :
Nous commençons ce tutoriel avec une simple simulation de balle rebondissante. La première chose que nous devons faire est d'importer les modules pymunk et pygame :
import pymunk import pymunk.pygame_util import pygame
Ensuite, nous initialisons le module Pygame et définissons la surface de l'écran où nous allons dessiner le résultat de la simulation. Pymunk propose une option de dessin simple qui peut être utilisée pour un prototypage rapide :
pygame.init() size = 640, 240 screen = pygame.display.set_mode(size) draw_options = pymunk.pygame_util.DrawOptions(screen)
La simulation de physique en 2D se déroule dans un objet Space. Nous définissons l'espace comme une variable globale et lui attribuons un vecteur de gravité :
space = pymunk.Space() space.gravity = 0, -900
Pour créer un sol fixe pour notre objet, nous créons une forme Segment attachée au corps statique b0. Afin de faire rebondir la balle, nous lui donnons une élasticité de 1 :
b0 = space.static_body segment = pymunk.Segment(b0, (0, 0), (640, 0), 4) segment.elasticity = 1
Ensuite, nous créons un corps dynamique et lui attribuons une masse, un moment et une position :
body = pymunk.Body(mass=1, moment=10) body.position = 100, 200
Ensuite, nous créons une forme de cercle et l'attachons au corps :
circle = pymunk.Circle(body, radius=20) circle.elasticity = 0.95
Enfin, nous ajoutons le corps, le cercle et le segment à l'espace. Maintenant, nous sommes prêts pour la simulation :
space.add(body, circle, segment
Dans la dernière partie, nous démarrons la boucle d'événements Pygame. Le seul événement que nous allons détecter est l'événement QUIT :
running = True while running: for event in pygame.event.get(): if event.type == pygame.QUIT: running = False
Dans la dernière partie de la boucle d'événements, nous dessinons les objets. Tout d'abord, nous remplissons l'écran avec une couleur de fond grise. Ensuite, nous dessinons les deux objets avec la fonction space.debug_draw(), appelons la fonction de mise à jour de l'affichage, et enfin, faisons progresser la simulation de 0,01 unités de temps :
screen.fill(GRAY) space.debug_draw(draw_options) pygame.display.update() space.step(0.01)
pygame.quit()
Pour simplifier les exemples du tutoriel, nous allons créer une classe App réutilisable qui exécutera la simulation. Cette classe effectuera les opérations suivantes :
Import des bibliothèques nécessaires
import pymunk # PyMunk pour la simulation physique import pymunk.pygame_util # Module d'intégration PyMunk avec Pygame import pygame # Pygame pour la création de la fenêtre d'affichage import math # Module math pour les calculs mathématiques
# Couleurs utilisées
GRAY = (220, 220, 220) # Couleur grise pour le fond de la fenêtre
# Initialisation de l'espace de simulation
space = pymunk.Space() # Crée un espace de simulation PyMunk space.gravity = 0, 900 # Définit la gravité (accélération verticale)
Voici la définition de la classe avec la méthode du constructeur :
# Création de la fenêtre d'affichage class App: size = 700, 240 # Taille de la fenêtre (largeur x hauteur) def __init__(self): pygame.init() # Initialise le module Pygame self.screen = pygame.display.set_mode(self.size) # Crée la fenêtre d'affichage self.draw_options = pymunk.pygame_util.DrawOptions(self.screen) # Options de dessin pour PyMunk self.running = True # Variable pour contrôler l'exécution self.clock = pygame.time.Clock() # Crée une horloge pour limiter le FPS
La classe App possède une méthode run() qui exécute la boucle d'événements de Pygame :
def run(self): while self.running: # Boucle principale for event in pygame.event.get(): # Gère les événements Pygame if event.type == pygame.QUIT: # Si l'utilisateur ferme la fenêtre self.running = False # Met fin à la boucle self.screen.fill(GRAY) # Remplit l'écran avec la couleur grise space.debug_draw(self.draw_options) # Affiche la simulation PyMunk pygame.display.update() # Met à jour l'affichage space.step(1.0 / 60.0) # Avance la simulation d'un pas de temps (60 FPS) self.clock.tick(60) # Limite le FPS à 60 images par seconde pygame.quit() # Ferme Pygame à la fin de la boucle
Nous avons enregistrer la classe dans un fichier python "app_class.py" dans le même répértoite que le fichier de notre application.
Nous pouvons maintenant importer pymunk, space et la classe App :
Bloc de code Python pour l'importation de la classe
from app_class import *
Définissons maintenant un segment incliné et attribuons-lui du frottement :
Bloc de code Python pour la définition du segment
# Création du plan incliné b0 = space.static_body segment = pymunk.Segment(b0, (100, 100), (600, 200), 4) segment.elasticity = 0.5 segment.friction = 0.5 space.add(segment)
La forme du cercle a également besoin de frottement pour pouvoir rouler. Sans frottement, il glisserait simplement sur la pente :
Bloc de code Python pour la définition du cercle
# Création du corps de la balle et position initiale ball_body = pymunk.Body(mass=1, moment=10) ball_body.position = (110, 90) # Position initiale en haut du plan incliné # Création de la balle attachée au corps ball = pymunk.Circle(ball_body, radius=20) ball.elasticity = 0.5 ball.friction = 0.5 space.add(ball_body, ball)
Enfin, nous instancions l'application et appelons la méthode run() :
Bloc de code Python pour l'instanciation de l'application
App().run()
La classe dispose d’une méthode pour créer des formes de boîte. Sans élasticité, il glisse le long de la pente:Poly
Exemple : Copier le code
# Importer les modules nécessaires depuis le fichier app_class.py from app_class import pymunk, space, App # Créer un segment statique (un mur) avec deux points de départ (20, 120) et d'arrêt (400, 50) segment = pymunk.Segment(space.static_body, (20, 120), (400, 50), 1) # Créer un corps (body) avec une masse de 1 et un moment d'inertie de 10 body = pymunk.Body(mass=1, moment=10) # Positionner le corps à la position (350, 50) dans l'espace body.position = (350, 50) # Créer un polygone en forme de boîte (box) attaché au corps (body) avec une taille de (40, 40) box = pymunk.Poly.create_box(body, (40, 40)) # Ajouter le corps (body), le polygone (box) et le segment (mur) à l'espace (space) space.add(body, box, segment) # Créer une instance de la classe App et exécuter l'application App().run()
Si l'on ajoute maintenant de l'élasticité à la forme de la boîte, celle-ci dévale la pente.
Exemple : Copier le code
# Importation des modules et des classes nécessaires depuis le fichier app_class.py from app_class import pymunk, space, App # Création d'un segment statique (mur ou sol) avec des points de début (20, 200) et de fin (400, 100), et une épaisseur de 5 segment = pymunk.Segment(space.static_body, (20, 200), (400, 100), 5) segment.elasticity = 0.95 # Coefficient d'élasticité du segment, ici 0.95 # Création d'un corps physique avec une masse de 1 et un moment d'inertie de 10 body = pymunk.Body(mass=1, moment=10) body.position = (350, 50) # Position initiale du corps # Création d'une boîte attachée au corps avec une taille de (40, 40) box = pymunk.Poly.create_box(body, (40, 40)) box.elasticity = 0.95 # Coefficient d'élasticité de la boîte, ici 0.95 # Ajout du corps et de la boîte au monde physique (espace) space.add(body, box, segment) # Initialisation et exécution de l'application (peut-être une fenêtre de simulation) App().run()
Pour dessiner une boîte fermée dans laquelle des objets peuvent rebondir, nous devons déterminer les 4 points d'angle. À partir de ceux-ci, nous pouvons créer 4 segments. Nous leur donnons une élasticité de 0,999 car une valeur de 1 ou plus peut conduire à un système instable :
Exemple : Copier le code
# Définition des points pour créer un polygone en forme de rectangle pts = [(10, 10), (690, 10), (690, 230), (10, 230)] # Boucle pour créer les segments du polygone for i in range(4): # Création d'un segment statique avec des points de début et de fin seg = pymunk.Segment(space.static_body, pts[i], pts[(i+1)%4], 2) seg.elasticity = 0.999 # Coefficient d'élasticité du segment, ici 0.999 space.add(seg) # Ajout du segment à l'espace physique # Définition de la gravité, ici nulle (les objets ne tombent pas) space.gravity = 0, 0
Afin de donner à la balle un mouvement latéral initial, nous lui appliquons un vecteur d'impulsion de (100, 0) à l'initialisation :
Exemple : Copier le code
# Boucle pour créer des corps dynamiques avec des cercles for i in range(40): # Création d'un corps physique avec une masse de 1 et un moment d'inertie de 10 body = pymunk.Body(mass=1, moment=10) # Positionnement aléatoire du corps dans une zone définie body.position = randint(40, 660), randint(40, 200) # Application d'une impulsion aléatoire au corps impulse = randint(-100, 100), randint(-100, 100) body.apply_impulse_at_local_point(impulse) # Création d'un cercle attaché au corps avec un rayon de 5 circle = pymunk.Circle(body, radius=5) circle.elasticity = 0.999 # Coefficient d'élasticité du cercle, ici 0.999 circle.friction = 0.5 # Coefficient de frottement du cercle, ici 0.5 space.add(body, circle) # Ajout du corps et du cercle à l'espace physique # Initialisation et exécution de l'application (peut-être une fenêtre de simulation) App().run()
Pour simuler un grand nombre de particules dans une boîte, nous commençons par désactiver la gravité. Ensuite, nous créons un grand nombre de particules à des endroits aléatoires et nous leur donnons des impulsions aléatoires comme mouvement de départ
Exemple : Copier le code
# Importation des modules et des classes nécessaires depuis le fichier app_class.py from app_class import pymunk, space, App from random import randint # Définition des points pour créer un polygone en forme de rectangle pts = [(10, 10), (690, 10), (690, 230), (10, 230)] # Boucle pour créer les segments du polygone for i in range(4): # Création d'un segment statique avec des points de début et de fin seg = pymunk.Segment(space.static_body, pts[i], pts[(i+1)%4], 2) seg.elasticity = 0.999 # Coefficient d'élasticité du segment, ici 0.999 space.add(seg) # Ajout du segment à l'espace physique # Définition de la gravité, ici nulle (les objets ne tombent pas) space.gravity = 0, 0 # Boucle pour créer des corps dynamiques avec des cercles for i in range(40): # Création d'un corps physique avec une masse de 1 et un moment d'inertie de 10 body = pymunk.Body(mass=1, moment=10) # Positionnement aléatoire du corps dans une zone définie body.position = randint(40, 660), randint(40, 200) # Application d'une impulsion aléatoire au corps impulse = randint(-100, 100), randint(-100, 100) body.apply_impulse_at_local_point(impulse) # Création d'un cercle attaché au corps avec un rayon de 5 circle = pymunk.Circle(body, radius=5) circle.elasticity = 0.999 # Coefficient d'élasticité du cercle, ici 0.999 circle.friction = 0.5 # Coefficient de frottement du cercle, ici 0.5 space.add(body, circle) # Ajout du corps et du cercle à l'espace physique # Initialisation et exécution de l'application (peut-être une fenêtre de simulation) App().run()
b0 = espace.space.static_body
Pour le corps dynamique, nous plaçons une sphère à (100, 10) :
body = pymunk.Body(mass=1, moment=10) body.position = (100, 100) circle = pymunk.Circle(body, radius=20)
La méthode prend 2 corps et leurs positions locales en argument. Nous plaçons l'ancrage du corps statique à (200, 200) et laissons le corps dynamique à son ancrage par défaut de (0, 0). Cela crée une épingle entre le point statique (200, 200) et le point dynamique (100, 100):PinJointb0body
joint = pymunk.constraint.PinJoint(b0, body, (200, 20))
Sous l'effet de la gravité, le pendule commence à se balancer.
Et voici le code complet:
Exemple : Copier le code
from app_class import pymunk, space, App b0 = space.static_body body = pymunk.Body(mass=1, moment=10) body.position = (100, 10) circle = pymunk.Circle(body, radius=20) joint = pymunk.PinJoint(b0, body, (200, 20)) space.add(body, circle, joint) App().run()
Bienvenue dans ce tutoriel sur Pymunk
Contenu :