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

  1. P5JS - Prédiction
  2. P5JS - Ça va bien aller
  3. P5JS - Bulles de savant
  4. P5JS - 10 Print
  5. P5JS - WEBGL

On a appris la fois passée ce qu'était WEBGL. Aujourd'hui, on va faire une animation très satisfaisante à regarder! Tu peux déjà visualiser cette animation ici ;-)

Pour commencer, on doit adapter notre createCanvcas() en ajoutant WEBGL en tant que 3e paramètre. Ceci rajoute une "troisième dimension".

Ensuite on va créer une animation d'une boîte dont la hauteur change constamment. Pour créer notre grande animation, on va simplement devoir repeter cette petite animation BEAUCOUP de fois.

Commence par dessiner une boîte. Tu peux commencer par la faire 100x100x200. Utilise les fonctions rotateX(), rotateY(), rotateZ() avec des valeurs comme bons te sentent pour voir cette boîte de coté.

Super! Il nous faut maintenant juste faire changer la hauteur de ce cube avec le temps. La fois passée, on a introduit une variable hauteur et une variable changement pour y arriver, mais cela n'est en fait pas optimal! Pour ce que soit plus facile, on doit reconnaître un certain mouvement.

La hauteur de la boîte doit augementer, puis diminuer, puis augementer, puis diminuer, etc. Si on dessine la fonction de la hauteur en fonction du temps, on aurait quelque chose du style:

Sinus Curve

Reconnais-tu cette fonction? Si tu n'es pas encore en 3e secondaire, tu peux directement passer à la réponse, mais si tu es en 3e secondaire tu as peut être déjà appris le nom de cette fonction de référence...

Cette fonction est la fonction "Sinus". C'est une fonction périodique, voulant dire qu'elle se répéte à l'infini. Elle va donc toujours monter, puis descendre, puis monter, etc, comme voulu!

Pour ceux que cela intéresse, un mouvement naturel comme celui de la fonction sinus s'appelle un mouvement harmonique.

Ne t'inquiètes pas si tu ne connais pas cette fonction! Il n'est pas super important de savoir ce qu'elle fait, juste sache qu'elle se repete à l'infini et qu'elle monte et qu'elle descend ;-)

Cette fonction prend des valeurs entre -1 et 1. Mais on aimerait que notre hauteur prenne des valeurs entre 0 et 200 (Par exemple). On doit donc un peu adapter la fonction.

La façon la plus simple de ce faire est de dire "On ajoute 1 à la fonction sinus (Elle va maintenant de 0 à 2), puis on multiplie tout par 100."

En p5.js, on peut utiliser la fonction sinus de la façon suivante:


              sin(...)
            

Ainsi, notre transformation va être écrite ainsi:


              ( sin(...) + 1 ) * 100
            

Reste à savoir ce qu'on peut mettre dans les .... As tu une idée?

On va utiliser le temps! En fait on veut juste une variable qui augement constamment et linéairement avec le temps, donc le temps soi même est un très bon choix!

Pour prendre le temps en p5.js, on utilise millis(). Comme son nom l'indique, il retourne le nombre de millisecondes depuis le début du code.

Essaie de remplacer les ... par le nombre de millisecondes et remplace la hauteur de ta boîte par l'équation d'avant. Est-ce que ça marche? Si la hauteur change trop vite, tu peux toujours diviser la hauteur par un certain nombre ;-) (Je te conseille de diviser par un nombre dans les alentours de 1000).


                  box(70, 70, (sin(millis() / 1000) + 1) * 100);
                

On va maintenant faire une autre boîte à côté de ce premier. Notre but final sera d'en avoir énormement, mais on va commencer par en faire 2.

Pour le moment, si tout va bien, ton code ressemble à quelque chose dans ce style:


              function setup() {
                createCanvas(400, 400, WEBGL);
              }
              
              function draw() {
                background(220);
                rotateX(20);
                rotateY(10);
                normalMaterial();
                box(70, 70, (sin(millis() / 1000) + 1) * 100);
              }
            

J'ai ajouté un normalMaterial() pour la couleur.

Notre but est d'ajouter une autre boîte. Comment ferais-tu cela? À mon avis, on doit mettre un autre box() après celui qu'on a déjà, cela devrait dessiner 2 boîtes non?

Alors oui et non. Il faut en effet ajouter un deuxième box(), mais pas que. Il nous faut aussi dire au code de ne pas dessiner cette deuxième boîte au dessus du premier! Pour ce faire, on peut simplement utiliser un translate().


                  box(...);
                  translate(100, 0);
                  box(...);
                

On a maintenant 2 boîtes qui oscillent ensemble... Comment pourrait-on les faire osciller à différentes vitesses?

Il nous faut faire ce qu'on appelle en mathématiques un déphasage. Cela semble méchant comme mot, mais cela ne l'est vraiment pas. En fait, il nous faut simplement ajouter un nombre à l'argument du sinus!

Pour faire un déphasage, change la hauteur de la deuxième boîte en


              (sin(millis() / 1000 + 1) + 1) * 100
            

Tu vois comment les deux boîtes n'ont pas la même taille? Très satisfaisant non?

Essaie maintenant d'ajouter une troisième boîte! Je sais que tu peux y arriver!

On sait maintenant comme faire 2 boîtes qui oscillent. Super, mais on est encore loin du nombre ésperé... Maintenant on va faire toute une ligne qui oscille!

Pour faire toute une ligne, on ne va pas juste copier/coller notre code 30 fois! On va utiliser une boucle!

Une boucle est un code qui ressemble au suivant:


              for(let l = 0; l < 100; l++) {
                // Faire quelque chose
              }
            

Ma boucle ici commence avec l=0, et continuera tant que l<100, et fait l++ à chaque étape. Cette boucle va donc s'executer 100 fois!

Regardons un peu les nombres: On a un écran 400x400. En particulier, on a 400 en longeur. On ne veut pas faire des boîtes trop larges, 70 c'est beaucoup trop... 10 serait une meilleure taille! On ne veut pas trop coller nos boîtes au bord, donc on peut laisser 20 en espace de chaque côté. Ainsi, on a de la place pour (400-20-20)/10=36 boîtes.

Notre boucle doit donc dessiner 36 boîtes, donc elle doit tourner 36 fois. Comment fait-on une boucle qui tourne 36 fois?

En effet! On doit juste changer la condition de la boucle!


                  for(let l = 0; l < 36; l++) {
                    // Faire quelque chose
                  }
                

Super! On a maintenant une boucle qui se repete 36 fois... Mais que faut-il faire à l'intérieur? Il faut dessiner une boîte à une nouvelle position à chaque fois!

Pour dessiner une boîte qui oscille et qui a une taille 10x10, c'est super facile! On l'a déjà fait, je suis sûr que tu peux y arriver!

On a toujours le problème qu'on ne doit pas oublier de faire un translate() après avoir dessiné une boîte. Ici, on ne veut que bouger de 10 dans l'axe X, et pas besoin de bouger dans l'axe Y. Ca aussi tu sais comment le faire ;-)

Tu devrais arriver à un code environ comme celui ci:


                  for(let l = 0; l < 36; l++) {
                    box(70, 70, (sin(millis() / 1000) + 1) * 100);
                    translate(10, 0);
                  }
                

Mais il y a deux problèmes avec ce code! Le premier est qu'on commence que à partir du centre... Pourquoi cela tu crois?

En effet! On doit se décaller vers la gauche au début du code pour commencer à placer nos boîtes de la gauche vers la droite! Pour ce faire, tu peux simplement faire un translate() avant la boucle, avec les paramètres corrects!

Un deuxième problème est que toutes les boîtes oscillent en même temps... On veut installer un déphasage! Heureuement, on peut se servir de la variable l dans la boucle pour installer ce déphasage.

Plutôt que d'ajouter 1 au nombre de millisecondes, ajoute la variable l. Si le déphasage te paraît trop grand, divise la variable l par un nombre adapté!


              box(70, 70, (sin(millis() / 1000 + l / 10) + 1) * 100);
            

On a maintenant une super jolie vague! Mais on peut ajouter encore plus de boîtes pour rendre l'animation encore plus satisfaisante!

On va maintenant faire plusieurs lignes qui oscillent pour former un carré qui oscille, comme montré dans l'animation de base.

Comment ferais-tu pour dessiner plusieurs lignes? Tu pourras juste copier/coller le code pour une ligne, mais cela ne va pas pas marcher pour créer 36 lignes...

On va de nouveau utiliser une boucle for. Dans l'étape précedente, on a utilisé a boucle pour multiplier une boîte plusieurs fois pour créer une ligne, dans celle ci on va utiliser cette boucle pour créer plusieurs lignes pour créer un carré!

Tout d'abord, on doit déterminer combien de fois la boucle doit tourner. Comme on veut faire un carré, on veut surement faire 36 lignes (Le même nombre que le nombre de boîtes par ligne). Tu peux donc entourer tout ton code pour dessiner une ligne dans une boucle.

Tu dois utiliser un autre nom de variable pour cette boucle. Tu pourrais l'appeller c comme on parle ici du nombre de la Colonne qu'on dessine.


              for(let c = 0; c < 36; c++) {
                // Code pour dessiner une ligne
              }
            

Si tu fais tout bien, tu vois juste une ligne... Pourquoi?

Le problème est similaire à celui de l'étape précédente!

On doit bouger le centre après avoir dessiné chaque ligne. Sinon elles vont juste se superposer....


                  translate(0, 10);
                

Tu vas encore voir des problèmes... Tu ne vois toujours que une ligne, peut être le début de la deuxième mais à un endroit bizarre... C'est parce qu'on doit aussi se souvenir de remettre le centre en X à la droite!


              translate(-360, 0);
            

Tu pourrais combiner les deux translate() en un seul aussi!


              translate(-360, 10);
            

Tu devrais maitenant voir plein de boîtes qui oscillent!

En anglais, le déphasage s'appelle un "offset". On va donc utiliser ce mot pour désigner la quantité qu'on ajoute aux millisecondes pour créer l'effet de vague.

Tout d'abord, juste avant de dessiner ta boîte tu peux créer une variable offset et la mettre à ce que tu veux. On va un peu jouer avec cette variable plus tard.


              for(...) {
                for(...) {
                  let offset = 1;
                  box(...);
                  translate(...);
                }
                translate(...);
              }
            

Plutôt que d'ajouter ce que tu ajoutais aux millisecondes plus tôt, tu peux maintenant ajouter la nouvelle variable offset.


              box(..., ..., ( sin( millis() / 1000 + offset) + 1 ) * 100 )
            

Tu vas alors voir que toutes tes boîtes oscillent avec la même phase. Pour changer cela, tu pourrais mettre offset à l ou c.

Voici une liste de formules qui donnent des résultats drôles:

  • let offset = l + c
  • let offset = l * c
  • let offset = l ^ c
  • let offset = (l ^ c) / 10
  • let offset = i ^ ((j * j) / 100)

Essaie de trouver d'autres formules qui donnent des résultats drôles!

Si tu veux un résultat un peu plus ésthetique, tu peux utiliser la formule let offset = (i + j) / 10, elle te donnera une jolie vague!

La formule pour former la jolie animation que tu as vue au début est la suivante:

      
              let offset = dist(l, c, 18, 18) / 5;
            

Voilà! J'espere que tu es content avec ton animation! Tu peux encore jouer un peu avec, essayer d'autres formules pour le déphasage, et essayer d'autres couleurs!