Plan du site  
pixel
pixel

Articles - Étudiants SUPINFO

Pymunk , un moteur physique 2D pour vos programmes python

Par Jérémy VILLET Publié le 18/07/2017 à 13:55:36 Noter cet article:
(0 votes)
Avis favorable du comité de lecture

Sommaire

Introduction

Lorsque vous programmez en python, il peut arriver que pour certains projets, vous soyez dans la nécessité d’utiliser un moteur physique. Que ce soit pour réaliser des jeux vidéo ou des simulations scientifiques, la résolution de problèmes de la mécanique classique tels que la chute de corps, les collisions ou encore la cinétique peut s’avérer compliquée surtout si nous ne sommes pas familiarisés avec le monde de la physique. Si vous ne souhaitez pas réinventer la roue, vous devrez donc impérativement utiliser une librairie particulière qui fera office de moteur physique pour votre programme. Nous allons ici nous intéresser à la bibliothèque ChipMunk, un moteur physique libre 2 dimensions. Cette dernière est adaptée aux langage C, C++, Ruby et Python pour ne citer que les langages les plus courant, mais il faut savoir qu’elle existe aussi pour d’autres langages plus spécifiques.

Nous allons ici nous intéresser à la version adaptée au Python, appelée plus communément Pymunk. Cette librairie à vue sa première version apparaitre en 2007 et est toujours développée et mise à jour actuellement. Cette dernière est relativement simple à utiliser et a pour avantage d’être multi-plateforme et non intrusive, c’est-à-dire qu’il est tout à fait possible d’utiliser en même temps d’autres librairies telles que Pygame et Pyglet par exemple.

Prérequis

Dans ce tutoriel nous allons nous pencher sur les bases de Pymunk. Cette librairie est relativement riche, c’est pourquoi nous n’aborderons que les aspects les plus élémentaires et dont leur utilisation est la plus récurrente. Vous serez donc largement à l’aise avec Pymunk à la fin de cet article, mais pour ceux souhaitant approfondir leurs connaissances en la matière, je vous mets ici le lien de la documentation officielle : http://www.pymunk.org

Pour pouvoir suivre ce tutoriel dans de bonnes conditions, il est nécessaire d’avoir de bonnes bases en python 3.X . Nous utiliserons également Pygame pour l’interface graphique, il est donc important d’être familiarisé avec cette librairie afin d’avoir les bases en tête. Cependant nous n’utiliserons que les rudiments de cette librairie, c’est pourquoi j’apporterai toujours des explications lors de l’utilisation des fonctionnalités de cette dernière.

Installation

Avant de commencer à coder, il est nécessaire d’installer Pymunk afin de pouvoir utiliser ses fonctionnalités au sein de votre projet. Je vais vous présenter deux méthodes ici, libre à vous de choisir la plus adaptée pour vous.

Via PIP

Pour procéder à cette méthode, assurez-vous de bien avoir installé la dépendance PIP. Pour les versions 3.4 et + de python, PIP est fourni dès l’installation de ce dernier. Pour les versions inférieures, je vous invite à l’installer par vos propres moyens où alors opter pour une autre méthode d’installation. Revenons donc à notre installation. Rendez-vous dans l’emplacement de votre exécutable python. Dans le dossier où se situe le programme python.exe, effectuez un Clic droit + shift et sélectionnez « ouvrir un invité de commande ici » . Ainsi dans l’invité de commande, tapez la commande suivante : « pip install pymunk »

Via l’IDE Pycharm

Cette méthode s’adresse exclusivement pour ceux qui dispose de l’IDE Pycharm . En effet cette IDE permet d’installer toute sorte de librairie facilement et rapidement. Pour ce faire , je vous invite donc à aller dans « File » => « Default setting » => « Project interpreter »

Vous trouverez alors l’interpréteur utilisé pour votre projet ainsi que toutes les librairies installées juste en dessous. Cliquez sur la croix verte pour accéder à un annuaire référençant toutes les librairies disponibles pour Python . Cherchez-y Pymunk et cliquez sur « Install Package »

Voilà pour l’installation, rien de très compliqué donc . Nous allons pouvoir rentrer dans le vif du sujet.

Création d'un environnement de base

Avant toutes choses, nous allons initialiser un environnement de base : tout simplement une fenêtre Pygame rattachée à un espace physique géré par Pymunk

Nous commençons par importer les modules nécessaires au développement de notre projet.

import pygame
import pymunk 
from pygame.locals import *
import Vec2d import pymunk.pygame_util
from pymunk import Vec2d

Nous créons ensuite une fenêtre basique de jeu avec Pygame ainsi qu'un espace physique avec Pymunk . Nous allons pouvoir dès lors définir une gravité pour notre espace physique qui affectera tous les objets rattachés à ce même espace physique .

pygame.init()
maFenetre= pygame.display.set_mode((1250,700))   # fenêtre de dimensions   1250X700

monEspacePhysique=pymunk.Space() # Création de l’objet représentant l’espace physique 
monEspacePhysique.gravity=x,y  #On donne ici un couple de valeur à l’attribut gravity de notre objet monEspacePhysique 
draw_options = pymunk.pygame_util.DrawOptions(maFenetre) #Permet l'affichage des objets Pymunk dans la fenêtre Pygame

Petit point sur le fonctionnement de la gravité. Nous voyons ici qu’un couple de deux valeurs est attendu. x représente la force de gravité horizontale. Ainsi, la gravité appliquera une force d’attraction vers la gauche pour tout objet se trouvant dans notre espace physique si x prend une valeur positive. Au contraire, ce sera une force d’attraction vers la droite si x prend une valeur négative.

Dans un même esprit, y représente la force de gravité verticale. Ce sera donc une force d’attraction vers le haut si y prend une valeur positive, et une force d’attraction vers le bas pour une valeur négative .

Par exemple, si nous voulons une gravité ressemblant à celle exercée sur Terre , nous ferions :

monEspacePhysique.gravity=0,-900

Nous allons ensuite intégrer une boucle élémentaire de jeu avec un évènement permettant à l’utilisateur de fermer le programme à l’aide de la croix rouge .

jeuEnCours=True # Tant que ce booléen est à True , on reste dans la boucle de jeu

while jeuEnCours :
    for event in pygame.event.get() :
       if event.type == QUIT :    # Si l’utilisateur clique sur la croix rouge
             jeuEnCours=False

Pour finir avec les bases, il nous faut encore faire en sorte que l’affichage et l’état physique de nos futurs objets soient tous deux mise à jour à chaque tour de la boucle, bref à chaque fois que leurs propriétés changent durant le déroulement de notre programme.

# mise à jour des aspects physiques et de l’affichage des objets Pymunk
dt = 1.0 / 60.0 / 5.
for x in range(5):
  monEspacePhysique.step(dt)
maFenetre.fill(0) # On nettoie la fenêtre pygame a chaque tour de boucle
monEspacePhysique.debug_draw(draw_options)

#mise à jour de l’affichage des éléments Pygame
pygame.display.flip
pygame.time.Clock().tick(60) #On fixe à 60 , le nombre de rafraichissement par seconde

Si vous avez bien suivit cette partie, voici le code que vous devriez maintenant avoir :

Si vous l’exécutez, vous devriez obtenir … une belle fenêtre noire ! Et oui comme dit au début de cette partie, nous n’avons fait que créer notre environnement de base qui servira de fondation pour notre futur programme. Rien de très intéressant pour le moment donc mais rassurez-vous, nous allons dès maintenant apprendre comment créer des objets capables d’interagir les uns avec les autres au sein de notre environnement de base.

Elèments de base

Voici donc le moment d’apprendre à créer nos premiers objets. Pymunk propose des méthodes permettant de créer diverses formes capables d’interagir les unes avec les autres du moment qu’elles sont rattachées au même espace physique.

Le système de coordonnées Pymunk

Avant toutes choses, j’aimerai faire une petite mise au point quant au système de coordonnées utilisé par Pymunk. Vous allez en effet en avoir besoin afin de créer et placer vos objets. Il existe en effet une petite particularité sur Pymunk qui vous causera bien des soucis si vous n’en n’avez pas été averti au préalable.

La plupart du temps en informatique, nous avons l’habitude de travailler sur un repère orthonormé avec pour origine le point le plus à gauche et le plus en haut de la fenêtre de notre programme. Nous avançons ainsi vers les positifs en allant vers la droite pour l’axe des abscisses et vers le bas pour l’axe des ordonnées. Le système de coordonnées marche de cette façon pour Pygame, mais est un peu différent pour Pymunk. En effet, Pymunk utilise un repère n’ayant pas la même origine pour l’axe des abscisses que pour l’axe des ordonnées. Ainsi, si l’axe des abscisses s’utilisent de la même façon que pour Pygame, c’est-à-dire, point d’origine tout à gauche de la fenêtre et positif vers la droite de ce dernier, l’utilisation de l’axe des ordonnées est un peu différente . En effet, ici le point d’origine se trouve au point le plus en bas de la fenêtre et l’on se déplace dans les valeurs positives en remontant vers le haut de la fenêtre.

Voici une petite illustration de mes propos , un schéma étant toujours plus clair à comprendre qu’un million de mots :

Création de segments

Le premier objet Pymunk que nous allons voire est un segment. Ceci peut être très utile pour définir des obstacles simples pour votre balle par exemple, ou encore définir les hit boxes du décors de votre jeu .

Nous commençons déjà par instancier l’objet grâce à la classe Segment de Pymunk :

monSegment=pymunk.Segment(monEspacePhysique.static_body, (x,y),(t,z),epaisseurDeMonSegment)

Les deux couples de coordonnées (x,y) et (t,z) correspondent à la position des deux extrémités de notre segments dans la fenêtre Pygame . N’oubliez pas bien utiliser le système de coordonnées propre à Pymunk que nous avons vu précédemment lorsque vous manipulez des objets Pymunk afin de ne pas avoir de mauvaises surprises ! L’argument epaisseurDeMonSegment attend quant à lui un nombre entier ou flottant selon vos besoins.

Pymunk vous propose également diverses méthodes afin de personnaliser un peu votre segment. Nous ne verrons cependant ici que les plus utiles.

Vous pouvez par exemple changer l’élasticité de votre segment. C’est la valeur de cet attribut qui définira la puissance du rebond lorsqu’un objet viendra rebondir sur votre segment

monSegment.elasticity=x

Les valeurs qui sont les plus cohérentes pour x sont comprises entre 0.0 et 1.9. Plus on se rapproche de 1.9, plus le rebond sera puissant

Voici également une méthode vous permettant de changer la couleur de votre segment. Nous allons ici nous servir en plus d’un module de Pygame afin de nous affranchir des codes rgb contraignant et manquant de lisibilité. Je vous invite donc à importer ce module au début de votre programme comme ceci :

from pygame.color import *

Ainsi vous allez pouvoir attribuer une couleur a votre segment de la façon suivante :

monSegment.color=pygame.color.THECOLORS["nomCouleur"]

A la place de nomCouleur est attendu bien évidemment le nom de la couleur souhaitée en anglais , l’auto complétion vous aidera bien sûr à effectuer votre choix .

Dernière point de la création de notre segment , l’intégration de ce dernier à notre espace physique . Pour ceci , rien de plus simple grâce à la méthode add()

monEspacePhysique.add(monSegment)

Voilà pour ce qui est de la création d’un segment. Ce code est à placé à l’intérieur de la boucle de jeu au tout debut , tout en faisant bien attention de le placer avant le code mettant à jour les aspects physiques et l’affichage des objets Pymunk ,sans quoi votre segment ne sera pas pris en compte . Voici un petit exemple de ce que vous pourriez obtenir :

Dernier point avant de passer à des formes plus complexes, la suppression de mon segment. Il peut en effet être intéressant de réaliser ceci dans certain évent si vous souhaitez par exemple ouvrir une zone de votre jeu qu’à partir d’un certain moment de la partie. Si avec Pygame, on redessine sur la zone à modifier ou à supprimer, avec Pymunk , on utilise tout simplement la méthode remove() sur l’objet concerné de la façon suivante :

monEspacePhysique.remove(monSegment)

Création de balles

Passons maintenant à la création d’un objet un peu plus dynamique : les balles

Effectivement, il peut arriver d’avoir besoin de balles pour vos programmes notamment si vous réalisez des jeux tels qu’un flipper ou encore un pong. Il est alors peut évident de créer une balle à partir de rien qui soit suffisamment réaliste, et l’on peut très vite se perdre dans tout un tas d’équations de mouvements surtout si on ne s’y connait que très peu en physique. Heureusement, Pymunk est là et nous propose un méthode très utile qui va nous permettre de créer la balle que nous souhaitons facilement . Une fois cette dernière créé via un évent , elle se déplacera toute seule dans notre espace physique , soumise aux conditions physiques que nous avons instauré et aux interactions que nous pourrons établir avec elle , point que nous aborderons plus tard dans ce cours .

Voici donc comment procéder pour créer la balle : Avant toute chose , nous créons un événement Pygame permettant la création de la balle. Ainsi dans le for event in pygame.event.get() : , nous ajoutons notre event :

if event.type==KEYDOWN and event.key==k_b : # Si l’utilisateur appuie sur la touche b , il créera ainsi une balle

Nous placerons dans ce if tout le code permettant la création de notre balle.

Nous allons dans un premier temps dans un objet que nous appellerons corpsBalle , définir les aspects physiques de notre balle , c’est-à-dire sa taille , sa masse , son inertie c’est-à-dire la façon dont la balle va conserver la vitesse tout au long de sa progression

inertie=pymunk.moment_for_circle(masse,0,rayonBalle,(0,0))
corpsBalle=pymunk.Body(masse,inertie)

Nous définissons ensuite la position initiale toujours en respectant, rappelons-le le système de coordonnées de Pymunk

corpsBalle.position=x,y

Ensuite nous créons notre objet balle grâce à la classe Circle de pymunk

balle=pymunk.Circle(corpsBall,rayonBalle,(0,0))

Nous pouvons là aussi personnaliser un peu notre balle grâce à quelques méthodes que nous avons déjà vues ensemble :

balle.elasticity=x  # Façon dont la balle va rebondir lors d’une collision avec un autre objet Pymunk

A noter que x , pour avoir une valeur cohérente , devrait prendre une valeur entre 0.0 et 1.9. Plus on se rapproche de la valeur de 1.9 , plus le rebond sera fort .

Nous pouvons aussi changer la couleur de la balle de cette façon :

ball.color=THECOLORS["nomCouleur"] # Avec toujours nom de la couleur en anglais en guise d’ argument

Dernière étape de création de notre balle , il nous faut encore ajouter à notre espace physique nos deux objets balle et corpsBalle . Pour ceci nous utiliserons encore la méthode add()

monEspacePhysique.add(balle,balleCorps)

Voilà pour ce qui est de la création de la balle. Je vous présente ici un bref aperçu de ce que l’on pourrait obtenir avec ce que nous avons vu jusqu’à présent :

La méthode remove() peut également être utiliser pour supprimer la balle de notre programme à un moment donner . Imaginons par exemple que nous souhaitions supprimer la balle si elle se retrouver sur les coordonnées (50,100) à un moment dans la partie.

Il nous faudrait donc déjà récupérer l’emplacement actuel de la balle à chaque fois que l’on passe dans notre boucle de jeu. Pour ceci, rien de plus facile encore une fois grâce à Pymunk :

x=int(balle.body.position[0]) # Abscisse de la position de la balle
y=int(balle.body.position[1]) # Ordonnée de la position de la balle

A noter qu’il est important de convertir la valeur en Integer grâce à int() si nous voulons exploiter correctement cette dernière par la suite .

Nous pouvons donc maintenant facilement établir le code afin de repondre à notre souhait cité dans notre exemple. Nous aurions donc :

if int(balle.body.position[0])==50 and int(balle.body.position[1])==100 :
    monEspacePhysique.remove(balle,corpsBalle)

Création de formes quelconques statiques

Regardons maintenant comment utiliser la méthode Poly() de Pymunk . Cette dernière va nous permettre de créer des formes quelconques statiques. Ceci peut être très utile dans le cas où vous désiriez introduire des obstacles plus complexes que des murs dans votre jeu , ou encore des bumpers dans le cas où vous développeriez un flipper.

Commençons déjà par créer notre objet :

maForme=pymunk.Body(body_type=pymunk.Body.KINEMATIC)

Nous allons maintenant définir l’aspect qu’aura notre forme une fois introduite dans notre jeu. Il s’agit d’un autre aspect un peu particulier propre à Pymunk , c’est pourquoi nous allons nous y attarder un peu afin que vous soyez capable de créer la forme que vous souhaitez .

Pour définir votre forme, vous allez devoir concevoir que le centre de votre future forme constitue l’origine d’un repère orthonormé. Ainsi, vous allez devoir construire une liste de tuples de coordonnées, où chaque tuple représentera un des sommets de votre forme. Il faudra veiller à les inscrire dans la liste dans l’ordre dans lequel ces sommets se suivent dans votre forme, sinon quoi vous n’obtiendrez pas du tout la forme attendue. Tout ceci peut vous semblez un peu théorique, c’est pourquoi nous allons passer à la pratique avec un schéma qui va clarifier tout ceci !

Nous récupérons ainsi dans une liste les tuples de coordonnées dans leur ordre de succession, dans un sens ou dans un autre :

coordonneeForme=[(40,40),(40,-40),(-40,-40),(-40,40)]

Nous savons désormais comment construire une forme quelconque avec Pymunk . Revenons à notre code. Nous définissons maintenant l’objet qui définira tous les aspects physiques de notre forme, c’est-à-dire son aspect, sa couleur, son élasticité, etc. ..

maForme_object=pymunk.Poly(maForme,coordonneForme)
maForme_object.color= THECOLORS[‘nomCouleur’] # Avec toujours nom de la couleur en anglais en guise d’ argument
maForme_object.elasticity=x  # Façon dont les objets vont rebondir sur notre forme après collision

A noter que x , pour avoir une valeur cohérente , devrait prendre une valeur entre 0.0 et 1.9. Plus on se rapproche de la valeur de 1.9 , plus le rebond sera fort . Il nous reste encore à placer notre forme dans notre jeu . Pour ceci rien de plus simple :

maForme.position=x,y

A noter que cette position représentera le milieu de notre forme , et représentera donc l’origine du repère orthonormé cité auparavant .

Il ne nous reste plus qu’à ajouter ces objets à notre espace physique

monEspacePhysique.add(maForme, maForme_object)

Voici ce que l'on pourrait donc obtenir :

Notions avancées pymunk

Avant la fin de ce tutoriel, nous allons voir quelques notions plus avancées qui peuvent s’avérer très utile pour vos projets.

Une impulsion pour votre balle

Nous avons vu précédemment comment créer une balle. Cependant, une fois cette dernière introduite dans notre jeu , nous n’avions plus aucun moyen d’interagir avec elle . Nous allons donc voir comment créer un évènement permettant de propulser la balle vers le haut par exemple , mais nous verrons qu’il est en réalité possible de la propulser dans n’importe quelle direction en fonction de nos besoins . Pour ce faire, nous allons utiliser le module Vec2d de Pymunk que je vous ai fait importer au début de ce tutoriel .

Nous créons donc un événement dans lequel , dès que nous appuierons sur la barre espace de notre clavier , une impulsion verticale sera donnée à notre balle .

Ce code doit être placé dans le for event in pygame.event.get() :

if event.type==KEYDOWN and event.key==K_SPACE :
     ball.apply_impulse_at_local_point(Vec2d((x,y)))

x représente une force d’impulsion horizontale . Une valeur positive applique une impulsion vers la droite à notre balle plus ou moins forte selon sa valeur tandis qu’une valeur négative applique une impulsion vers la gauche.

y représente une force d’impulsion verticale . Une valeur positive applique une impulsion vers le haut à notre balle plus ou moins forte selon sa valeur tandis qu’une valeur négative applique une impulsion vers le bas.

Une image avec des propriétés physiques ?

Lors de l’élaboration de votre jeu, il se peut que vous ayez besoin d’y introduire un décors issus d’une image capable d’interagir avec vos objets Pymunk. La façon la plus simple est d’établir une forme Pymunk la plus fidèle possible à notre image, puis de recouvrir cette dernière par l’image en question grâce à Pygame. De nos yeux d’utilisateurs, nous ne verrons que notre image à l’écran, tandis que les objets Pymunk ne « verrons » que la forme Pymunk se trouvant en dessous et pourront interagir avec.

Pour réaliser ceci vous commencerez donc par établir une forme Pymunk comme je vous l’ai enseigné précédemment. Il vous faudra ensuite grâce à Pygame placer une image par-dessus . Pour ceci , vous allez devoir vous placer après le morceau de code suivant pour afficher votre image :

# mise à jour des aspects physiques et de l’affichage des objets Pymunk
    dt = 1.0 / 60.0 / 5.
    for x in range(5):
monEspacePhysique.step(dt)

Voyons donc le code permettant d’afficher une image avec Pygame. On commence par charger l’image de la façon suivante :

monImage=pygame.image.load(‘cheminImage’).convert_alpha()

A noter que le convert_alpha() n’est nécessaire que si votre image contient de la transparence .

Nous plaçons ensuite notre image dans notre fenêtre de jeu :

maFenetre.blit(monImage,(x,y))
pygame.display.flip() # Pour prendre en compte le blit de l’image

x et y représentent les coordonnées où le coin en haut à gauche de l’image va être positionné selon le système de coordonnées Pygame . Arrangez-vous donc pour que l’image vienne recouvrir votre forme Pymunk .

Conclusion

Nous avons donc vu ici comment utiliser les aspects les plus basiques de Pymunk. Vous êtes donc censé savoir vous débrouiller avec cette librairie. Néanmoins sachez qu’il existe encore de nombreux points que nous n’avons pas pu aborder au sein de ce tutoriel. Si cela vous intéresse, je vous invite donc à vous rendre à l’adresse suivante afin d’y consulter la documentation :

http://www.pymunk.org/en/pymunk-4.0.0/tutorials/SlideAndPinJoint.html

A propos de SUPINFO | Contacts & adresses | Enseigner à SUPINFO | Presse | Conditions d'utilisation & Copyright | Respect de la vie privée | Investir
Logo de la société Cisco, partenaire pédagogique de SUPINFO, la Grande École de l'informatique, du numérique et du management Logo de la société IBM, partenaire pédagogique de SUPINFO, la Grande École de l'informatique, du numérique et du management Logo de la société Sun-Oracle, partenaire pédagogique de SUPINFO, la Grande École de l'informatique, du numérique et du management Logo de la société Apple, partenaire pédagogique de SUPINFO, la Grande École de l'informatique, du numérique et du management Logo de la société Sybase, partenaire pédagogique de SUPINFO, la Grande École de l'informatique, du numérique et du management Logo de la société Novell, partenaire pédagogique de SUPINFO, la Grande École de l'informatique, du numérique et du management Logo de la société Intel, partenaire pédagogique de SUPINFO, la Grande École de l'informatique, du numérique et du management Logo de la société Accenture, partenaire pédagogique de SUPINFO, la Grande École de l'informatique, du numérique et du management Logo de la société SAP, partenaire pédagogique de SUPINFO, la Grande École de l'informatique, du numérique et du management Logo de la société Prometric, partenaire pédagogique de SUPINFO, la Grande École de l'informatique, du numérique et du management Logo de la société Toeic, partenaire pédagogique de SUPINFO, la Grande École de l'informatique, du numérique et du management Logo du IT Academy Program par Microsoft, partenaire pédagogique de SUPINFO, la Grande École de l'informatique, du numérique et du management

SUPINFO International University
Ecole d'Informatique - IT School
École Supérieure d'Informatique de Paris, leader en France
La Grande Ecole de l'informatique, du numérique et du management
Fondée en 1965, reconnue par l'État. Titre Bac+5 certifié au niveau I.
SUPINFO International University is globally operated by EDUCINVEST Belgium - Avenue Louise, 534 - 1050 Brussels