Avant de t'attaquer à ce défi, on te conseille de compléter les défis suivants:

  1. En 2020 je serai...
  2. Ça va bien aller
  3. Péter ta balloune
  4. Bulles de savant
  5. La nuit étoilée

Première chose avant de commencer à travailler sur n'importe quel projet p5.js: connecte-toi à ton compte en cliquant sur "Log in".

L'objectif de ce défi, c'est de commencer à comprendre à quoi servent les classes en JavaScript (et dans beaucoup d'autres langages de programmation).

À vrai dire, on pourrait très bien se passer des classes et coder en n'utilisant que des variables, des fonctions, des boucles et des conditions.

Alors pourquoi utiliser des classes?

Parce qu'elles simplifient notre vie de dev, surtout lorsque nos programmes commencent à être trrrrrrrrrès longs!

Pour s'en rendre compte, on va coder deux fois le même programme: la première fois sans classe et la seconde fois avec. À la fin, tu pourras décider quelle version tu préfères.

L'objectif, c'est de coder trois (voire plus!) étudiants en p5.js, comme ceci:

En bonus, tu peux faire danser tes étudiants avec de la musique 🎵 lorsque tu cliques sur le canevas.

Rappelle-toi: il faut toujours commencer par le plus simple! On va commencer par un visage tout simple: un ovale pour le contour du visage.

Commence un nouveau projet p5.js que tu peux appeler "étudiants sans classe" 😉. De quelles fonctions auras-tu besoin pour dessiner un ovale et pour lui donner la couleur de ton choix?

Tu auras besoin de la fonction ellipse() et de la fonction fill()

Ton code pourrait ressembler à ceci:

                  
                  function setup() {
                    createCanvas(400, 400);
                  }

                  function draw() {
                    background(220);

                    fill("peru");
                    ellipse(200, 100, 50, 60);
                  }
                
            

Ici, "peru" est la couleur de la peau (tu peux en choisir une autre en consultant ce site des noms de couleur en HTML). Si tu veux que ton visage soit plus rond, tu peux changer les paramètres de ton ellipse: ellipse(200, 100, 55, 60), par exemple.

Il est temps d'ajouter des yeux à notre visage! Quelle est la façon la plus simple de coder des yeux?

Deux cercles et on y est! Les yeux de mon étudiante seront vert olive!

Bon, l'étudiante n'a qu'un seul œil en plein milieu de son visage. Pas top...

En même temps, j'ai bêtement réutilisé les mêmes coordonnées que pour mon visage:

          
          function draw() {
            background(220);

            // le visage
            fill("peru");
            ellipse(200, 100, 50, 60);

            // les yeux
            fill("olive");
            circle(200, 100, 10);
            circle(200, 100, 10);
          }
        
      

Comment faire pour déplacer l'oeil gauche à gauche?

N'hésite pas à consulter la documentation de la fonction circle(). Elle nous rappelle à quoi servent les trois paramètres:

            
            circle(x, y, d)
            
          

x étant la position du cercle sur l'axe horizontal, y étant la position sur l'axe vertical et d le diamètre du cercle.

Eh oui, changer la position en x de mon cercle:

            
              circle(190, 100, 10);
            
          

Et tant qu'à y être, je pourrais aussi monter un peu l'oeil:

            
              circle(190, 95, 10);
            
          

C'est déjà mieux!

Dessiner un sourire, c'est comme dessiner une demi-ellipse:

Il n'existe pas de fonction "demi-ellispe" en p5.js. Par contre, il existe une fonction arc(). En lisant la documentation, es-tu capable de faire sourire ton étudiante?

C'est toujours une bonne idée de tester les exemples. Allons-y avec le premier exemple de la documentation:

            
            arc(50, 55, 50, 50, 0, HALF_PI);
            
          

Pas génial... On a un demi de sourire vert olive dans le coin gauche. Tentons déjà de rendre le sourire blanc!

Pour un sourire blanc, il faut utiliser la fonction fill():

            
            fill("white");
            arc(50, 55, 50, 50, 0, HALF_PI);
            
          

Maintenant, comment faire pour que ce ne soit pas un demi sourire mais un sourire complet?

Pour un sourire complet, il faut comprendre ce que veulent dire les deux derniers paramètres de la fonction arc(50, 55, 50, 50, 0, HALF_PI): 0 et HALF_PI. La documentation indique ceci:

  • start: angle to start the arc, specified in radians
  • stop: angle to stop the arc, specified in radians

Les deux paramètres sont des nombres qui représentent des angles. Ici, le paramètre start prend la valeur de 0 et le paramètre stop prend la valeur de HALF_PI. HALF_PI c'est pas un nombre pourtant...

En fait, si. HALF_PI est une constante en JavaScript. Une constante, c'est comme une variable, mais une variable qui contient une valeur qui ne change jamais. Tu as probablement déjà entendu parler du nombre pi, souvent noté π. Sa valeur est de 3,14... et des poussières!

Sans surprise, la constante HALF_PI, c'est la moitié de pi, soit 1,57079632679489661923 et encore des poussières :)

Ok, donc on a un angle de 0° et un angle de 1,57° ?? Pas si vite! Les deux nombres sont des radians, pas des degrés! Si tu observes ce schéma, un radian de 0, équivaut à 0 degrés:

Par contre, un radian de 1,57 (la moitié de pi) équivaut à un angle de...

90°!

Notre fonction arc devrait donc dessiner l'arc suivant:

C'est pratiquement cela, sauf que p5.js nous l'a dessiné à l'envers:

Sais-tu pourquoi?

Si p5.js nous a dessiné l'arc vers le "bas", c'est à cause du "sens" de l'axe des y. Dans ce schéma, la valeur de y augmente lorsqu'on va vers le haut:

Au contraire, dans un canevas p5.js, la valeur de y augmente lorsqu'on va vers le bas.

Sachant cela, comment faire pour que notre arc soit plus grand et fasse un sourire? Eh oui, il faudra changer le paramètre stop.

Maintenant que tu as un sourire complet, modifie les deux premiers paramètres de la foncion arc() pour positionner ton sourire au centre du visage de l'étudiante.

Et dernier petit indice, pour que le sourire soit complet tu devras utiliser le paramètre CHORD.

Voici le code:

            
            arc(200, 110, 20, 15, 0, PI, CHORD);
            
          

Avant de passer à l'étudiant suivant, on va ajouter quelques cheveux à notre étudiante, histoire de dire qu'elle ne prendra pas de coup de soleil sur la tête!

Allons au plus simple avec 3 rectangles de couleur, bien placés :)

Pour dessiner des rectangles, la fonction rect() te sera sans doute utile!

Nous allons maintenant donner un nom à notre étudiante. La nôtre s'appellera Lara, car c'est le nom d'une élève du Techies qui nous a inspiré ce défi!

Affiche le nom de ton étudiante en-dessous de son visage comme ceci:

Utilise la fonction text()

Il est temps d'ajouter les amis de Lara: Margo et Seb. À toi de coder deux étudiant-e-s de plus!

Comment as-tu trouvé l'expérience de coder deux étudiants de plus? Est-ce que c'était facile, difficile? Court, long?

Combien de lignes fait ton code maintenant?

Le mien fait 80 lignes (avec quelques lignes que j'ai laissées vides, pour "aérer" mon code, le rendre plus lisible, et quelques lignes de commentaires aussi).

Imagine qu'on veuille créer 3 étudiants de plus. Ou 15 étudiants de plus. Ou 100!

Aïe, aïe, aïe, ça fait beaucoup de copier-coller tout ça! Notre code va devenir suuuuuuuper long!

Peux-tu penser à une façon de réduire la longueur du code?

Eh oui, on pourrait coder une fonction, qui reprendrait toutes les instructions pour coder un étudiant.

Après les fonctions setup() et draw(), tu peux coder une fonction drawStudent() (tu peux donner un autre nom à ta fonction).

Ma fonction a l'air de ceci:

            
            function drawStudent() {
  // le visage
  fill("RosyBrown");
  ellipse(300, 300, 50, 60);

  // les yeux
  fill("silver");
  circle(290, 295, 10);
  circle(310, 295, 10);

  // bouche
  fill("white");
  arc(300, 310, 20, 15, 0, PI, CHORD);

  // cheuveux
  fill("Wheat");
  rect(300-2.5, 300-39, 5, 15);
  rect(300+5, 300-37, 5, 15);
  rect(300-9.5, 300-37, 5, 15);

  // nom
  fill("black");
  textSize(32);
  text("Margo", 300-35, 300+80);
}
            
          

En fait, j'y ai mis tout le code pour l'étudiante Margo. Manque de pot, Margo a disparu du canevas. Sais-tu pourquoi?

Maintenant que le code de Margo est dans la fonction drawStudent(), il faut que je me serve (que j'appelle) cette fonction. Dans la fonction draw(), j'ajoute la ligne suivante:

            
            function draw() {
              // code pour dessiner Lara
              //...

              // code pour dessiner Seb
              //...

              // code pour dessiner Seb
              drawStudent();
            }
            
          

Et hop, Margo est de retour! Puis-je me servir de ma fonction drawStudent() à nouveau pour Seb? Pas vraiment... Si je code

            
            function draw() {
              // code pour dessiner Lara
              //...

              // code pour dessiner Seb
              drawStudent();

              // code pour dessiner Seb
              drawStudent();
            }
            
          

Seb disparaît! En fait, on a utilisé deux fois une fonction qui au final... ne fait que dessiner Margo! Comment faire pour que la fonction puisse à la fois dessiner Margo et Seb et Lara et Jean-Mich...?

Pour rendre ta fonction drawStudent() plus flexible, tu vas devoir utiliser des paramètres:

            
            function drawStudent(positionX, positionY, skinColor, hairColor, eyesColor, name) {
              //...
            }
            
          

          
          function setup() {
  createCanvas(400, 400);
}

function draw() {
  background(220);

   // Lara
  drawStudent(200, 100, "peru", "PaleVioletRed", "olive", "Lara");

  // Seb
  drawStudent(100, 300, "PapayaWhip", "SaddleBrown", "Indigo", "Seb");

  // Margo
  drawStudent(300, 300, "RosyBrown", "Wheat", "silver", "Margo");
}

function drawStudent(positionX, positionY, skinColor, hairColor, eyesColor, name) {
  // le visage
  fill(skinColor);
  ellipse(positionX, positionY, 50, 60);

  // les yeux
  fill(eyesColor);
  circle(positionX-10, positionY-5, 10);
  circle(positionX+10, positionY-5, 10);

  // bouche
  fill("white");
  arc(positionX, positionY+10, 20, 15, 0, PI, CHORD);

  // cheuveux
  fill(hairColor);
  rect(positionX-2.5, positionY-39, 5, 15);
  rect(positionX+5, positionY-37, 5, 15);
  rect(positionX-9.5, positionY-37, 5, 15);

  // nom
  fill("black");
  textSize(32);
  text(name, positionX-35, positionY+80);
}
          
        

Mon code ne fait plus que 42 lignes!

Trouve une belle image comme arrière-plan pour nos étudiants. Tu peux en trouver sur ton moteur de recherche préféré ou encore sur un site comme Unsplash.

Télécharge la photo sur ton ordinateur (sur le Bureau, par exemple) et puis charge-la dans p5.js. Tu peux te créer un dossier assets.

Tu peux maintenant utiliser cette image comme arrière-plan. Tu te souviens comment faire? On a ajouté un arrière-plan dans le défi Bulles de savant, par exemple.

Tu peux utiliser la fonction preload() et passer ton objet image directement à la fonction background()

Comment vas-tu faire pour faire "danser" tes étudiants? Essaie d'abord de les faire bouger vers la droite. Pour cela ton ordinateur auras constamment besoin de savoir quelle est la position de chaque étudiant. En d'autres mots, il aura besoin de stocker dans sa mémoire la position de chaque étudiant. Et qui dit stocker, dit...

... dit variable! Mais combien de variable te faudra-t-il?

Si tu as 3 étudiants, il te faudra 3 variables: une pour la position sur l'axe des x de chaque étudiant.

         
          // j'initialise les trois variables de position
          let positionXLara = 200;
          let positionXSeb = 100;
          let positionXMargo = 300;

          function setup() {
            createCanvas(400, 400);
          }

          function draw() {
            background(220);

            // lorsque j'appelle la fonction drawStudent() j'utilise les variables définies plus haut (plutôt que de mettre directement la valeur)
            // Lara
            drawStudent(positionXLara, 100, "peru", "PaleVioletRed", "olive", "Lara");

            // Seb
            drawStudent(positionXSeb, 300, "PapayaWhip", "SaddleBrown", "Indigo", "Seb");

            // Margo
            drawStudent(positionXMargo, 300, "RosyBrown", "Wheat", "silver", "Margo");

            // j'augmente la valeur des variables pour que les étudiants se déplacent vers la droite
            positionXLara++;
            positionXSeb++;
            positionXMargo++;
          }

          function drawStudent(positionX, positionY, skinColor, hairColor, eyesColor, name) {
            //...
          }
         
       

Tes étudiants se déplacent vers la droite... mais ne s'arrêtent jamais!

Comment faire en sorte pour qu'après une certaine distance, les étudiants reviennent vers la gauche?

Nos étudiants se déplacent vers la droite... mais ne s'arrêtent pas! Il est temps de la faire revenir vers la gauche!

Pour aller vers la gauche, il suffit de diminuer la valeur de la position en x:

        
        positionXMargo--;
        
      

Par contre, si l'on augmente puis l'on diminue la position l'un à la suite de l'autre, les deux instructions s'annulent et les étudiants restent immobiles:

        
        positionXMargo++;
        positionXMargo--;
        
      

Il faut donc trouver une façon de dire à l'ordinateur "augmente jusqu'à ce que tu sois à +30 de ta position initiale et ensuite diminue, jusqu'à ce que tu sois à -30 de ta position initiale.

Il faudra probablement que tu sauvegardes la position initiale de chaque étudiant. Cette position ne changera jamais, tandis que la position "actuelle" de l'étudiant, elle, va changer.

Imagine que la position initiale en x de Margo est 300. Tu peux dédider que Margo se déplacera jusqu'à 330 avant de repartir vers la gauche:

        
        // cette variable sauvegarde la position actuelle de Margo
        let positionXMargo = 300;

        // cette variable sauvegarde la position originale (au tout début de l'animation) de Margo
        let origineXMargo = 300;

        function setup() {
          // ...
        }

        function draw() {
          // ...

          positionXMargo++;

          if (positionXMargo >= origineXMargo + 30) {
            // ???
          }
        }
        
      

Qu'arrive-t-il quand Margo arrive au bout de sa trajectoire à droite?

Au bout de la trajectoire à droite, Margo doit changer de direction! On pourrait être tenté de coder quelque chose comme ceci:

          
          function draw() {
            // ...

            positionXMargo++;

            if (positionXMargo >= origineXMargo + 30) {
              positionXMargo--;
            }
          
        

Mais ça ne fonctionnerait pas! En effet, quand Margo atteindrait la position en x de 330, la condition positionXMargo-- s'appliquerait et donc Margo retournerait à la position 329. La ligne de code positionXMargo++ s'appliquerait ensuite et Margo retournerait à 330. Au final, Margo ferait du surplace entre 329 et 330.

En fait, quand Margo arrive au bout de sa trajectoire à droite, il faut qu'elle change de direction! Et bien entendu, ce serait chouette que l'ordinateur sache la direction de chaque étudiant en tout temps. Il faut donc créer une variable... direction pour chaque étudiant!

          

          let positionXMargo = 300;
          let origineXMargo = 300;

          // cette variable donne la direction de Margo (au début, elle part vers la droite)
          let directionMargo = "droite";

          function setup() {
            // ...
          }

          function draw() {
            // ...

            positionXMargo++;

            if (positionXMargo >= origineXMargo + 30) {
              directionMargo = "gauche";
            }
          }
          
        

Il ne te reste plus qu'à changer la position de Margo en fonction de sa direction... eh oui, encore une condition à coder!

          

          let positionXMargo = 300;
          let origineXMargo = 300;
          let directionMargo = "droite";

          function setup() {
            // ...
          }

          function draw() {
            // ...
            if (positionXMargo >= origineXMargo + 30) {
              directionMargo = "gauche";
            } else if (positionXMargo <= origineXMargo - 30) {
              directionMargo = "droite";
            }

            if (positionXMargo == "droite") {
              positionXMargo++;
            } else {
              positionXMargo--;
            }
          }