p5.js (p5js.org) est une bibliothèque JavaScript qui reprend les concepts de l'excellentissime Processing (processing.org). p5.js va donc nous permettre de dessiner, de travailler sur des images, de travailler avec du texte, de faire des animations, de travailler sur des données...tout cela dans un navigateur web.

Avant d'entrer dans le vif du sujet, mettons en place notre environnement de travail :

À faire vous même 1.1

Placez-vous dans votre dossier personnel et créez un nouveau dossier que vous nommerez "p5". Dans ce dossier "p5", créez un autre dossier nommé "ex0".

Placez-vous dans le dossier "ex0" et créez 3 fichiers :

  • index.html
  • script.js
  • style.css

Toujours dans le dossier "ex0", créez un dossier "asset"

Vous devriez donc avoir ceci dans votre dossier "ex0" :


À faire vous même 1.2

À l'aide d'un éditeur de texte (scite par exemple), ouvrez le fichier "index.html" et saisissez le code suivant :

index.html


<!DOCTYPE html>
<html lang="fr">
<head>
    <meta charset="utf-8">
    <title>p5.js</title>
    <link rel="stylesheet" href="style.css">
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.4.23/p5.min.js"></script>
    <script src="script.js"></script>
</head>
<body>
</body>
</html>
        

De temps en temps, consulter ce site pour vérifier que vous utilisez bien la dernière version de p5js. Dans le code ci-dessus, nous utilisons la version "0.4.23". Si une nouvelle version est disponible, n'hésitez pas à modifier l'url (https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.4.23/p5.min.js) dans le fichier html ci-dessus.


La structure de base qui vous permettra d'utiliser p5.js est en place, par la suite, il suffira de "copier-coller" le dossier "ex0" et de le renommer à chaque fois que vous aurez besoin de créer un nouvel exemple.

ATTENTION : si l'ordinateur que vous utilisez n'est pas connecté à internet, la méthode décrite ci-dessus ne fonctionnera pas. Veuillez alors suivre les instructions données ici.

 

À faire vous même 2.1

"Copier-coller" le dossier "ex0" et renommez-le en "p5_a2_1". Vous allez travailler avec ce dossier "p5_a2_1". Dans la suite, vous devrez effectuer ce "copier-coller-renommer" pour chaque nouvel exemple sans que j'ai besoin de le préciser.

À l'aide d'un éditeur de texte, saisissez le code suivant dans le fichier "script.js"

script.js


function setup() {
    
}

function draw() {
  
}
        

Si vous testez cet exemple en cliquant sur le fichier "index.html", votre navigateur par défaut devrait se lancer, mais vous devriez obtenir une page blanche. Ceci est tout à fait normal, nous avons bien notre premier programme p5.js, mais celui-ci ne fait strictement rien.

Pourtant, la structure de base est déjà en place.

Nous avons 2 fonctions :

  • la fonction "setup" qui sera exécutée une seule fois au "démarrage" du programme
  • la fonction "draw" qui sera exécutée à chaque fois qu'une nouvelle image sera affichée par le navigateur

Pour l'instant, nous allons uniquement utiliser la fonction "setup". Nous reviendrons sur la fonction "draw" quand nous nous intéresserons aux animations.

La première instruction que nous allons voir, va nous permettre de créer une surface de dessin (canvas en anglais) :


createCanvas(300,200)
        

permet de créer une surface où nous allons pouvoir dessiner de 300 pixels de large et de 200 pixels de haut.

À faire vous-même 2.2

Saisissez et testez ce programme (en cliquant sur "index.html")

script.js


function setup() {
    createCanvas(800,600);
}

function draw() {
  
}
        

Comme vous pouvez le constater, cela ne change rien. En fait, la surface de dessin a bien été créée, mais comme sa couleur de fond est blanche...nous ne la voyons pas.

Nous allons modifier la couleur de fond pour la faire apparaitre (la gestion des couleurs sera vue un peu plus tard).

À faire vous-même 2.3

Saisissez et testez ce programme (en cliquant sur "index.html")

script.js


function setup() {
    createCanvas(800,600);
    background(240);
}

function draw() {
  
}
        

Comme vous pouvez le constater, la fenêtre de dessin est bien présente (encore une fois, nous reviendrons sur la fonction "background" et la gestion des couleurs un peu plus tard).

Afin de bien distinguer la surface de dessin du reste de la page, nous laisserons (au moins dans un premier temps) cette couleur de fond.

La fonction "point" va nous permettre de dessiner un point (pixel) sur l'écran


point(200,100)
        

Que représente le "(200,100)" dans "point (200,100)" ?

Tout simplement les coordonnées du point que nous voulons dessiner.

Qui dit coordonnées, dit axe x, axe y et origine O :

À faire vous-même 2.4

Saisissez et testez ce programme (en cliquant sur "index.html")

script.js


function setup() {
    createCanvas(800,600);
    background(240);
    point(400,300);
}

function draw() {
  
}
        

Observez bien, vous devriez voir un point apparaitre au milieu de la surface de dessin.

À faire vous-même 2.5

Modifiez les coordonnées du point créé dans le "À faire vous-même 2.4" comme bon vous semble, vérifiez le résultat.


À faire vous-même 2.6

En vous aidant d'une boucle, tracez un segment de droite. Vous devez obtenir ce résultat :


À faire vous-même 2.7

Tracez un segment de droite, vous devez obtenir ce résultat :


À faire vous-même 2.8

Tracez un segment de droite. Vous devez obtenir ce résultat :


À faire vous-même 2.9

Écrivez un programme permettant d'obtenir une "ligne en pointillée" comme ci-dessous :


Il est possible de modifier la couleur d'un point grâce à la fonction stroke

À faire vous-même 2.10

Saisissez, analysez et testez ce programme :


function setup() {
    createCanvas(800,600);
    background(240);
    stroke(255,0,0);
    point(400,300);
}

function draw() {
  
}
        

Comme vous pouvez le constater le point est toujours situé au centre de l'écran mais maintenant, il est de couleur rouge.

Que signifie le (255,0,0) du stroke ?

  • Chaque pixel (chaque point) est constitué de 3 éléments (appelé aussi canal): un rouge, un vert et un bleu. C'est la somme de ces 3 couleurs qui permet d'obtenir un grand nombre de couleurs (synthèse additive)
  • Classiquement, à chaque canal, on associe un nombre binaire codé sur 8 bits (soit donc 24 bits par pixel)
  • Pour chaque pixel, on aura donc une valeur pour le rouge (comprise entre 0 et 255 puisque codé sur 8 bits), une valeur pour le vert (comprise entre 0 et 255) et une valeur pour le bleu (comprise entre 0 et 255). Quelques exemples : (0,0,0)=> noir ; (255,0,0)=> rouge ; (255,255,255)=> blanc ; (0,255,0)=> vert...

Toutes les combinaisons sont possibles, vous trouverez sur ce site un nuancier qui vous indiquera les valeurs des canaux Rouge, Vert et Bleu (RVB ou RGB en anglais).

À faire vous-même 2.11

Écrivez un programme permettant d'obtenir une "ligne bicolore" comme ci-dessous :

Processing

Vous devrez utiliser une boucle "for" et un "if/else".


À faire vous-même 2.12

Écrivez un programme permettant d'obtenir un drapeau tricolore comme ci-dessous :

Processing

Dans cette activité, nous allons découvrir d'autres fonctions qui vont nous permettre de dessiner différentes figures géométriques.

La fonction "line" permet de dessiner une ligne. Cette fonction prend 4 paramètres :


line(x1,y1,x2,y2);
        

avec :

  • x1 coordonnée x du point de départ de la ligne
  • y1 coordonnée y du point de départ de la ligne
  • x2 coordonnée x du point d'arrivée de la ligne
  • y2 coordonnée y du point d'arrivée de la ligne

À faire vous-même 3.1

Saisissez et testez ce code


function setup(){
    createCanvas(400,400);
    background(240);
    line(200,0,200,400);
}
function draw(){
    
}
        

À faire vous-même 3.2

Codez un programme permettant d'obtenir ceci :

N.B. La fenêtre a pour dimension 200 par 200


À faire vous-même 3.3

Codez un programme permettant d'obtenir ceci :

processing

N.B. La fenêtre a pour dimension 200 par 200


La fonction "ellipse" permet de dessiner des... ellipses. La fonction "ellipse" prend 4 paramètres.


ellipse(x,y,a,b);
        

avec :

processing

(x,y) les coordonnées du centre de l'ellipse, a la "largeur horizontale" et b la "largeur verticale".

À faire vous-même 3.4

Saisissez et testez ce code


function setup(){
    createCanvas(400,400);
    background(240);
    ellipse(200,200,100,50);
}
function draw(){
    
}
        

À faire vous-même 3.5

Codez un programme permettant d'obtenir un cercle au centre de la fenêtre.


La fonction "triangle", permet d'obtenir un... triangle. Cette fonction prend 6 paramètres :


triangle(x1,y1,x2,y2,x3,y3);
        

avec :

(x1,y1) les coordonnées du point 1, (x2,y2) les coordonnées du point 2 et (x3,y3) les coordonnées du point 3.

À faire vous-même 3.6

Saisissez et testez ce code


function setup(){
    createCanvas(400,400);
    background(240);
    triangle(100,100,150,200,220,150);
}
function draw(){
    
}
        

À faire vous-même 3.7

Codez un programme permettant d'afficher un triangle rectangle. La position et la taille du triangle devront être aléatoires.


Pour afficher un quadrilatère, il faut utiliser la fonction "quad". Cette fonction prend 8 paramètres.


quad(x1,y1,x2,y2,x3,y3,x4,y4);
        

Ces 8 paramètres sont les coordonnées des 4 points.

À faire vous-même 3.8

Saisissez et testez ce code


function setup(){
    createCanvas(400,400);
    background(240);
    quad(100,100,150,200,220,230,300,120);
}
function draw(){
    
}
        

La fonction "rect" permet de tracer des rectangles. Cette fonction prend 4 paramètres :


rect(x,y,a,b);
        

(x,y) les coordonnées du coin supérieur-gauche, a la "largeur horizontale" et b la "largeur verticale".

À faire vous-même 3.9

Saisissez et testez ce code


function setup(){
    createCanvas(400,400);
    background(240);
    rect(200,200,100,60);
}
function draw(){
    
}
        

À faire vous-même 3.10

Codez un programme permettant d'afficher un carré de taille aléatoire. Le centre du carré devra se trouver au centre de la fenêtre


La fonction "arc" permet de dessiner un "morceau d'ellipse". La fonction arc prend 6 paramètres.


arc(x,y,a,b,angle_dep,angle_arr);
        

les 4 premiers paramètres sont les mêmes que pour la fonction "ellipse".

angle_dep correspond à "l'angle de départ" et angle_arr correspond à l'angle d'arrivée.

processing

Attention, les angles doivent être donnés en radian, si vous désirez exprimer vos angles en degrés, il faudra utiliser la fonction "radians" :


angle_radian=radians(angle_degré);
        

Pour les angles, il faut considérer le sens horaire (et pas le sens anti-horaire comme le sens trigonométrique).

À faire vous-même 3.11

Saisissez et testez ce code


function setup(){
    createCanvas(400,400);
    background(240);
    arc(200,200,100,50,radians(45),radians(270));
}
function draw(){
    
}
        

À faire vous-même 3.12

Codez un programme permettant d'afficher ceci :

processing


La dernière fonction de dessin est beaucoup plus complexe à utiliser. La fonction "bezier" permet de dessiner une courbe de Bésier. Si le coeur vous en dit, vous en apprendrez plus sur les courbes de Bézier ici (je vous préviens, c'est très compliqué).

La fonction "bezier" prend 8 paramètres :


bezier(x1,y1,x2,y2,x3,y3,x4,y4);
        

(x1,y1) et (x4,y4) sont les coordonnées des points situés aux 2 extrémités de la courbe de Bézier. (x2,y2) et (x3,y3) sont les coordonnées des 2 points de contrôles.

À faire vous-même 3.13

Saisissez et testez ce code


function setup(){
    createCanvas(400,400);
    background(240);
    bezier(100,100,250,50,220,230,250,120);
}
function draw(){
    
}
        

Si vous voulez essayez de comprendre le fonctionnement de cette fonction "bezier", le plus simple est de modifier les paramètres et observer le résultat après chaque modification.

Dans cette activité, nous allons faire du "coloriage".

Pour chaque figure dessinée, il y a 2 choses à considérer :

  • la couleur du contour
  • la couleur de "remplissage"

Le contour sera géré par la fonction "stroke", le "remplissage" sera géré par la fonction "fill".

Ces 2 fonctions prennent en paramètre les 3 canaux rouge, vert, bleu.

À faire vous-même 4.1

Saisissez et testez ce code


function setup(){
    createCanvas(400,400);
    background(240);
    stroke(255,0,0);
    fill(0,0,0);
    ellipse(200,200,50,50);
}
function draw(){
    
}
        

Vous pouvez vérifier que le contour du cercle est rouge et que "l'intérieur" du cercle est noir.

Comme vu précédemment, si les 3 canaux R,V,B sont identiques, il est possible de mettre un seul paramètre (mettre fill(0) à la place de fill(0,0,0).

La fonction "noStroke" permet de supprimer le contour, la fonction "noFill" permet de rendre l'intérieur d'une figure incolore (comme si on ne coloriait pas l'intérieur de la figure).

À faire vous-même 4.2

Saisissez et testez ce code


function setup(){
    createCanvas(400,400);
    background(240);
    stroke(255,0,0);
    noFill();
    ellipse(200,200,50,50);
    noStroke();
    fill(0);
    rect(30,30,30,30);
}
function draw(){
    
}
        

Il est possible de jouer sur l'épaisseur du contour avec la fonction "strokeWeight" qui prend en paramètre l'épaisseur du trait en pixel.

À faire vous-même 4.3

Saisissez et testez ce code


function setup(){
    createCanvas(400,400);
    background(240);
    strokeWeight(5);
    stroke(255,0,0);
    fill(0,0,0);
    ellipse(200,200,50,50);
}
function draw(){
    
}
        

Il est possible de modifier la transparence d'une figure en ajoutant un 4e paramètre à la fonction "fill". Plus ce paramètre sera grand et plus la figure sera opaque.

À faire vous-même 4.4

Saisissez et testez ce code


function setup(){
    createCanvas(400,400);
    background(240);
    noStroke();
    fill(0,255,0);
    rect(200,200,50,50);
    fill(255,0,0,200);
    ellipse(200,200,50,50);
}
function draw(){
    
}
        

À faire vous-même 4.5

Créez un programme permettant d'afficher 100 disques à l'écran. La taille de chaque disque devra être aléatoire (mais comprise entre 20 et 50). La couleur et la transparence de chaque disque devront aussi être aléatoires. Pour obtenir un nombre aléatoire, il faut utiliser la fonction "random" :


random(20,50);
        

permet d'obtenir un aléatoire compris entre 20 et 50 (les 2 inclus).

La fonction "floor" permet d'arrondir un nombre :


floor(4.6);
        

donnera 5

processing

 

 

p5js propose 3 fonctions très importantes (mais relativement complexes à prendre en main) :

  • la fonction "translate" qui permet de translater les axes de coordonnées.
  • la fonction "rotate" qui permet de faire faire une rotation aux axes de coordonnées.
  • la fonction "scale" qui permet de modifier l'échelle.

Il faut bien que vous compreniez que ces fonctions agissent sur le système de coordonnées et pas directement sur les dessins.

Commençons par la fonction "rotate" qui permet de "tourner" le système de coordonnées d'un certain angle. Cette fonction prend un seul paramètre : l'angle de rotation (en radian, la fonction "radians" permet de convertir les degrés en radian).

Au départ nous avons :

repere

après avoir appliqué la fonction "rotate" :


rotate(α);
        

nous obtenons ceci :

repere

À faire vous-même 5.1

Saisissez et testez ce code


function setup(){
    createCanvas(200,200);
    background(240);
    rotate(radians(20));
    rect(60,50,20,20);
}
function draw(){
    
}
        

sans le "rotate"

repere

avec le "rotate"

repere

À faire vous-même 5.2

Saisissez et testez ce code


function setup(){
    createCanvas(200,200);
    background(240);
    rect(60,50,20,20);
    rotate(radians(20));
}
function draw(){
    
}
        

Comme vous pouvez le constater, le "rotate" n'a aucune action sur un élément déjà dessiné au moment de son application.

À faire vous-même 5.3

Créez un programme permettant d'obtenir ceci :

repere

La fonction "translate" permet de faire faire une translation au système de coordonnées :

avant

repere

après un :


translate(dx,dy);
        

on obtient ceci

repere

À faire vous-même 5.4

Saisissez et testez ce code


function setup(){
    createCanvas(200,200);
    background(240);
    translate(80,30);
    rect(60,50,20,20);
}
function draw(){
    
}
        

sans le "translate"

repere

avec le translate

repere

La fonction "scale" ne devrait pas vous poser de difficultés :

À faire vous-même 5.5

Saisissez et testez ce code


function setup(){
    createCanvas(200,200);
    background(240);
    scale(2);
    rect(60,50,20,20);
}
function draw(){
    
}
        

"scale" est l'équivalent d'un zoom (ou d'une loupe) si son argument est supérieur à un. Je vous laisse deviner l'effet d'un argument compris entre 0 et 1.

Il est possible de combiner "rotate", "translate" et "scale" (attention l'ordre d'application à son importance) :

repere

À faire vous-même 5.6

Créez un programme permettant d'obtenir ceci : (le programme doit faire moins de 10 lignes).

repere


La fonction "push" permet d'effectuer une "sauvegarde" de l'état du système de coordonnées au moment où cette fonction est exécutée. "pop" restaure cette sauvegarde

À faire vous-même 5.7

Saisissez et testez ce code


function setup(){
    createCanvas(200,200);
    background(240);
    translate(80,30);
    fill(255,0,0);
    rect(60,50,20,20);
    push();
    translate(0,50);
    fill(0,255,0);
    rect(60,50,20,20);
    pop();
    fill(0,0,255);
    rect(80,50,20,20);
}
function draw(){
    
}
        

Comme vous devez le constater le carré bleu n'a pas "bénéficié" de la même "translation vers le bas" que le carré vert. Le "pop" a en effet "annulé" cette "translation vers le bas" (toutes les transformations comprises entre un "push" et un "pop" sont annulées au moment du "pop").

 

Dans cette activité, nous allons commencer à nous intéresser aux animations.

Comme déjà évoqué précedement, la fonction "draw" est appelée à chaque image

Qu'est-ce que j'entends par "appelée à chaque image" ?

Quand vous jouez à un jeu sur votre ordinateur (et que votre ordinateur manque de "puissance"), il arrive parfois que l'affichage saccade (on parle de "lag"), pourquoi ?

Il faut savoir que "l'ordinateur" doit, plusieurs dizaines de fois par seconde (le nombre d'images affichées par seconde est souvent désigné par l'acronyme FPS (Frames per second)), afficher une nouvelle image à l'écran.

Cela demande beaucoup de calculs (complexes) au microprocesseur central (CPU).

Petite parenthèse : c'est d'ailleurs pour cela qu'aujourd'hui, cette tâche est très souvent laissée à un microprocesseur spécialisé dans ce genre de calcul : le GPU (Graphics Processing Unit, ce microprocesseur spécialisé se trouve sur la carte graphique de votre ordinateur). Quand ni le CPU, ni le GPU n'arrivent à afficher suffisamment d'images par seconde, votre jeu saccade.

En matière de programmation, il faut, une fois que la nouvelle image est prête à être à afficher (après par exemple avoir bougé de quelques pixels le personnage principal), envoyer l'ordre au CPU d'afficher cette nouvelle image (après avoir fait tous les calculs nécessaires).

On retrouve ici le principe du dessin animé : l'ordinateur affiche à l'écran une succession d'images fixes, si la fréquence d'affichage est assez importante (30 FPS pour que cela paraisse fluide), l'utilisateur aura l'illusion du mouvement.

p5js propose donc la fonction "draw", cette fonction "draw" sera appelée à chaque image.

À faire vous-même 6.1

Saisissez, analysez et testez ce code


var r;
var v;
function setup(){
    createCanvas(400,400);
    noStroke();
    fill(0);
    r=2;
    v=2;
}
function draw(){
  background(240);
  ellipse(200,200,2*r,2*r);
  if (r>200 || r<2){
    v=-v;
  }
  r=r+v;
}
        

Cette partie du code :


background(240);
ellipse(200,200,2*r,2*r);
if (r>200 || r<2){
    v=-v;
}
r=r+v;
        

se trouve dans la fonction "draw". Le code ci-dessus sera donc exécuté à chaque image.

Le "background(240)" permet d'effacer l'écran à chaque nouvelle image (juste avant de redessiner le disque avec le "ellipse(200,200,2*r,2*r);". Le principe est donc simple : à chaque image, on efface tout et on redessine.

N.B. Remarquez que les déclarations des variables r et v ("var r;" et "var v;") ont été faites en dehors de la fonction "setup". Si ces déclarations avaient été faites dans la fonction "setup" nous aurions alors eu des variables locales à la fonction "setup", r et v n'auraient donc pas pu être utilisées dans la fonction "draw".

Par défaut, p5js essaye de maintenir 60 FPS ("essaye" car si les éléments à afficher sont trop complexes, le nombre de FPS diminue).

La fonction "frameRate" permet d'imposer le nombre de FPS. Cette fonction prend un paramètre, le nombre de FPS désiré.

À faire vous-même 6.2

Ajouter un


frameRate(5);
        

dans la fonction "setup" du programme écrit dans le "À faire vous-même 6.1"


Comme vous pouvez le constater, l'animation est maintenant beaucoup moins fluide.

À faire vous-même 6.3

Créez un programme permettant d'avoir une balle rouge (créée avec la fonction "ellipse") qui traverse la fenêtre de gauche à droite (cliquez sur pour relancer l'animation).


À faire vous-même 6.4

Repartez du code du "À faire vous-même 6.3". Désormais, la balle doit rebondir contre les bords de la fenêtre


À faire vous-même 6.5

Créez un programme permettant d'obtenir ceci :

Il est recommandé d'écrire une ou des fonctions afin de rendre le code plus clair.

 


À faire vous-même 6.6

En vous inspirant du programme créé dans le "À faire vous-même 6.4", écrivez un programme permettant à la balle de se déplacer en diagonal. La position de départ, la vitesse de départ ainsi que la direction de départ devront être aléatoires. Les rebonds sur les bords de la fenêtre devront rester réalistes.


À faire vous-même 6.7

Votre programme devra maintenant permettre à 2 balles (une rouge et une verte) de se déplacer (position de départ, vitesse de départ et direction de départ seront aléatoires pour les 2 balles). En cas de collision entre les 2 balles, ces 2 balles devront disparaitre.

  • On pourra considérer qu'il y a collision si la distance entre les centres des balles est inférieure à une certaine valeur que vous devrez déterminer.
  • Avec Processing, pour avoir la racine carrée de X, il suffit d'écrire sqrt(X). Pour avoir le carré de X, il suffit d'écrire sq(X).

Il est aussi possible d'utiliser les transformations ("translate", "rotate" et "scale") dans une animation.

ATTENTION : chaque exécution de la fonction "draw" annule toutes les transformations (le repère reprend sa position "normale" à chaque exécution de "draw" (à chaque image)).

À faire vous-même 6.8

Créez un programme permettant d'obtenir l'animation suivante :

À faire vous-même 6.9

Créez un programme permettant d'obtenir l'animation suivante :

À faire vous-même 6.10

Créez un programme permettant d'obtenir l'animation suivante :

En poursuivant votre navigation sur mon site, vous acceptez l’utilisation des Cookies et autres traceurs  pour réaliser des statistiques de visites et enregistrer sur votre machine vos activités pédagogiques. En savoir plus.