/**
Article / Note
2015/08/06

Pérégrinations avec physicsJS

Cet article répond au double objectif de tester l'embarcation de scripts dans les articles de ce blog et de découvrir la librairie javascript physicsJS dont le but est de réaliser une simulation numérique de la dynamique de corps soumis à des champs de forces dans un espace à deux dimensions.

Audience: expérience en programmation javascript.
version de physicsJS : 0.0.7

Les explications sur le site de cette libraire sont suffisamment claires, je ne rentrerai donc pas dans le détail de chaque concept, tout au plus donnerai-je rapidement quelques informations à leur sujet, en laissant la place aux démonstrations d'utilisation.

Vous trouverez le code de ces démos à la fin de l'article.

Pour se mettre en jambe

Le premier exemple est la réalisation quasi à l'identique du premier tutoriel proposé sur le site de physicsJS.

Il s'agit de mettre en place le gestionnaire de rendu sur canvas, puis d'ajouter les corps et les comportements physiques de base :

  • Un champ d'accélération uniforme (ConstantAccelerationBehavior) correspondant aux champ d'attraction gravitationnel d'une planète. Celui-ci est considéré comme constant car la scène est de dimension bien inférieure au rayon de la planète et suffisamment éloignée de son centre.
  • Un détecteur de collision avec les bords (EdgeCollisionDetectionBehavior) Ce comportement est responsable de la détection des collisions des corps avec les bords d'une région rectangulaire donnée, région alignée sur les axes x et y, ce qui sert principalement à empêcher les corps de quitter la scène.
  • Un détecteur de collisions entre les corps (BodyCollisionDetectionBehavior). Plus complexe et gourmand que le comportement précédent il nécessite l'utilisation d'
  • Un comportement-optimiseur pour la détection de collisions des corps (SweepPruneBehavior) qui permet d'éviter un test de détection couteux pour la plupart des couples de corps qui sont de manière triviale trop éloignés l'un de l'autre pour être possiblement en collision (voir sweep and prune sur wikipedia).
  • Et finalement un comportement qui répond aux collisions entre corps en leur appliquant une impulsion adéquate en réponse (BodyImpulseResponseBehavior), de sorte que la collision soit effectivement suivi des effets qu'on peut attendre d'un tel événement sur leurs dynamiques.

Les conditions initiales concernant les corps sont données : positions, vitesses initiales. La démo suivante ne spécifie pas la masse des corps, utilisant les masses par défaut, mais on peut la spécifier.

tutorial

Les comportements de bases exploités ici sont simples à utiliser et permettent de montrer rapidement cet exemple déjà fort sympathique.

La section suivante est une ensemble de démonstrations plus sommaires se concentrant chacune sur un objectif précis.


Petites expérimentations

"None shall pass"

L'objectif est ici de réaliser une impossibilité physique (ça commence bien) : un corps éternellement immobile. Les autres corps entrent en collision avec lui sans le faire bouger. PhysicsJS nous offre la solution sur un plateau : Body.treatment, avec la valeur static.

Dans cette démo il n'y pas de champ de gravitation. Tout se passe donc comme si la scène se passait dans une région très isolée de l'espace, ou si nous regardions par en haut une table ou glisserait sans frottement notre petit corps mobile.

expe1

On voit bien que le petit carré mobile repart dans le sens opposé après la collision avec la même vitesse qu'avant l'impact. En effet peu importe la masse du disque immuable, puisque sa vitesse ne peut être altérée la quantité de mouvement du système, initialement apportée uniquement par le carré, n'est pas transmise au cercle, même en partie, et se retrouve intégralement dans le carré.

Sentinelle fantôme

Comme précédemment, le corps ne peut se déplacer mais maintenant il est traversable par les autres corps, autrement dit il n'est jamais l'objet d'un événement de collision.

expe2

L'objectif est atteint grâce à la fonction Behavior.applyTo() qui permet de n'appliquer un comportement que sur un ensemble restreint de corps. Ainsi seuls les carrés sont sujets à collision si l'on ne passe que ces corps à la fonction applyTo.

Le code de cette démo vous montrera également les points suivants :

  • l'utilisation des Layers du CanvasRenderer, qui permettent ici que les carrés s'affichent par dessus le cercle immuable et
  • le styling des corps, référence directe à l'API Canvas

Edit : l'utilisation des Layers n'est en fait pas nécéssaire, l'ordre dans lequel sont ajoutés les corps à la scène implique l'ordre de rendu, il suffit donc d'ajouter le cercle avant les carrés.

La pente savonneuse

Les démos suivantes sont des variations sur le thème de la friction dans physicsJS. La friction est responsable de la conversion d'une partie de l'énergie cinétique d'un système en une autre forme d'énergie (en chaleur par exemple). Dans physicsJS seule existe l'énergie cinétique. Cette energie dissipée sera donc simplement "perdue" : le seul effet visible sera une perte de l'energie cinétique des corps en friction.

La friction s'exprime via l'option cof (Coefficient Of Friction) du comportement EdgeCollisionDetectionBehaviorévoqué dans la première démo et via l'option cof des corps eux-mêmes (Body). Le cof est utilisé par le comportement BodyImpulseResponseBehavior.

Un COF de 0 correspond à aucun frottement (super glissade), 1 correspond à une absorption complète de l'énergie cinétique (super glue).

Le paramètre "edge restitution" est la part d'énergie restituée à un corps lors d'une collision avec les bords.

Première illustration : un corps se déplace en contact avec le bord inférieur :

expe3

Il a été nécessaire de remettre en scène le comportement "accélération constante" pour simuler la pesanteur (sans laquelle deux objets en glissement ne peuvent pas faire friction).

Voyons la friction entre deux corps maintenant :

expe4

Jouez avec les paramètres COF en les abaissant lorsque le carré est à l'arrêt sur la pente, vous arriverez à un point ou la friction de contact (le produit des deux COF) n'est plus assez forte pour empêcher le carré de glisser.

Code

Plutôt que de montrer l'intégralité du code ici je vous propose de le télécharger.

Il ne me reste plus qu'à vous remercier pour votre lecture, j'espère que vous lirez mon prochain article sur ce thème (ou autre chose).

>> Réagir à cet article