Mode Statique => Actif

Mode statique

Le mode statique est idéal pour débuter avec Processing. En mode statique, le programme exécute les instructions puis s’arrête.

Mode actif

Cependant, pour créer la moindre animation ou utiliser quelques fonctions plus avancées (comme la création de méthodes/fonctions) il faut passer en mode actif, c’est à dire utiliser ces 2 méthodes :

  • setup() : elle est exécutée une seule fois au début du programme. Elle sert à préparer le décor de base.
  • draw() : c’est une méthode qui est tourne en boucle. C’est cette boucle qui permet modifier le dessin en permanence … donc de créer une animation.

NB : Ces méthodes sont précédées du mot clé void car elles ne retournent pas de résultat particulier.

Exemple : Dessiner avec la souris :

void setup() {  // initialisation
  size(200,150);
  stroke(#D11AEA); //couleur fushia
  strokeWeight(4);
}
 
void draw()  { // tourne en boucle
  point(mouseX,mouseY);
}

Pr_An_dessinSouris

Quelques réglages.

Nettoyer le fond ou pas …

La même animation peut être complètement différente en rajoutant ou pas un nettoyage du fond au début de draw(). En reprenant l’exemple précédant, en rajoutant background(), il ne reste plus qu’un point (le dessin est effacé par background() ).

void setup() {
  size(200,150);
  stroke(#D11AEA);
  strokeWeight(20);
}
 
void draw() {
  background(200);  // efface le fond
  point(mouseX,mouseY);
}

Pr_An_dessinSouris2

NB : Si on ne souhaite pas redessiner tout le fond mais juste une partie alors on peut dessiner un petit rectangle comme rect(mouseX-10,mouseY-10,20,20).

Vitesse de l’animation

On peut régler la vitesse d’exécution de la boucle draw() dans le setup() avec l’instruction frameRate().

frameRate(10) : Règle la vitesse d’exécution de draw() à 10 rafraîchissements par seconde.

Utiliser des méthodes

pré-définies par Processing

Outre setup() et draw(), Processing a aussi défini d’autres méthodes pour interagir avec l’utilisateur. Attention, ces méthodes ont réellement besoin de draw() pour être actualisées en permanence : même si draw() est vide, il ne faut pas enlever draw() !!

  • mouseClicked() : appelée lorsque qu’un bouton de la souris est appuyé.
  • mouseReleased() : appelée lorsque qu’un bouton de la souris est relâché.
  • mouseMoved() : appelée lorsque que la souris bouge et qu’aucun bouton n’est appuyé.
  • mouseDragged() : appelée lorsque que la souris bouge et qu’un bouton de cette souris est appuyé.

NB : De même, ces méthodes doivent être précédées du mot clé void.

Il existe aussi les variables :

  • booléens (boolean) : mousePressed,mouseReleased, …
  • entiers (int) : mouseX, mouseY et aussi pmouseX, pmouseY (les coordonnées précédentes … celles de la précédente exécution de la méthode qui les contient draw() ou mouseClicked() )

Pour identifier le bouton cliqué : if (mousePressed && (mouseButton == LEFT)) { ... }

inventées par vous

Il est conseillé de découper un programme en plusieurs petits bouts qui font sens. Ça aide à la conception et à la compréhension.

Exemple : La méthode monLogo() inventée ci-dessous dessine un « i ». Cette fonction est appelée à chaque clic de souris et dessine le logo aux coordonnées (mouseX,mouseY). De plus, la variable mousePressed vaut true lorsque le bouton de la souris est appuyé et false sinon.

void setup() {
  size(200,150);
  stroke(#D11AEA);
  strokeWeight(4);
}
 
void draw() {
  if (mousePressed) point(mouseX,mouseY);
}
 
void mouseClicked() {
  monLogo(mouseX,mouseY);
}
 
void monLogo(int x, int y) {
 ellipse(x,y,20,20);
 rect(x-10,y+10, 20, 40);
 point(x,y+30);
}

Pr_An_mouseClicked

Rotation

PImage rocket;
float angle = 0;
void setup() {
  size (500,500);
  imageMode(CENTER);
  rocket = loadImage("rocket.png");
}
void draw() {
  angle = angle + 0.1;
  if (angle > 2*PI) angle = 0;
  background(0);
  pushMatrix();  //mémorise la matrice (le repère)
  translate(300,300); //translation à la position de la rocket
  rotate(angle); //rotation du repère
  image(rocket, 0, 0); //pose l'image ds le repère penché
  popMatrix(); //revient à la matrice initiale (repère initial)
}

Evénemenent Clavier

Pour que Processing écoute les touches clavier, il faut utiliser la fonction keyPressed() (fonction prédéfinie par Processing). Ainsi la touche appuyée est stockée dans la variable key. Cependant les touches spéciales (Alt, ctrl, shift, flèches UP, DOWN, LEFT, RIGHT…) sont quant à elles stockées dans la variable keyCode et le test if (key == CODED) permet de savoir si la touche appuyée est une touche spéciale ou non.

Se déplacer avec les touches FLECHES

Comme les flèches (UP, DOWN, LEFT, RIGHT) sont des touches spéciales, alors on commence le test if (key == CODED) puis on récupère le code de cette touche dans la variable keyCode.

Dans l’exemple suivant, nous faisons déplacer le rond grâce aux 4 touches flèches (UP, DOWN, LEFT, RIGHT).

int x=50, y=50;
 
void setup() {
  size(100,100);
}
 
void draw() {
  background(#FAA2EA); //fond rose
  ellipse(x,y,10,10);
}
 
void keyPressed() {
    if (keyCode == LEFT)   x = x - 1;
    if (keyCode == RIGHT)  x = x + 1;
    if (keyCode == UP)     y = y - 1;
    if (keyCode == DOWN)   y = y + 1;
}

pr_deplacemttouche

En biais (touches simultanées)

Dans ce cas on rajoute 4 variables booléennes (un booléen est une variable qui ne possède que 2 valeurs possibles : TRUE/FALSE).

Chaque variable mémorise si la touche est appuyée (TRUE) ou relâchée (FALSE). Puis on fait évoluer x et y selon le cas échéant.

Voici un exemple :

int x=50, y=50;
boolean right, left, up, down; 
void setup() {
  size(100,100);
  right = left = up = down = false;
}
void draw() {
  background(#FAA2EA); //fond rose
  if (right) { x = x+1;  }
  if (left ) { x = x-1;  }
  if (up)    { y = y-1;  }
  if (down)  { y = y+1;  }
  ellipse(x,y,10,10);  
}
void keyPressed() {
    if (keyCode == RIGHT) { right = true; }
    if (keyCode == LEFT ) { left = true;  }
    if (keyCode == UP)    { up = true;    }
    if (keyCode == DOWN)  { down = true;  }
}
void keyReleased() {
    if (keyCode == RIGHT) { right = false; }
    if (keyCode == LEFT ) { left = false;  }
    if (keyCode == UP)    { up = false;    }
    if (keyCode == DOWN)  { down = false;  }
}

Faire un saut (avec la touche ESPACE)

Pour faire un saut, on va simplement utiliser la touche espace (qui n’est pas une touche spéciale) pour déclencher un saut.

Dans l’exemple suivant, nous faisons déplacer le personnage horizontalement avec les 2 touches flèches (LEFT, RIGHT) et on le fait sauter avec la touche ESPACE.

On n’autorise pas les doubles sauts (i.e. on ne peut pas amorcer un 2e saut tant qu’on n’a pas fini le 1er saut).

Le plus difficile consiste à coder les mouvements du saut. Pour cela, on introduit une variable enSaut pour savoir dans quel état se trouve le personnage : à terre (il n’est pas en train de sauter) OU en train de monter (phase ascendante de saut) OU en train de retomber (phase descendante de saut)

Signification de la variable enSaut :
♦ enSaut=0 : lorsque le personnage est par terre (il n’est pas en train de sauter)
♦ enSaut=1 : lorsque le personnage est en phase ascendante de saut (il monte)
♦ enSaut=2 : lorsque le personnage est en phase descendante de saut (il retombe)

int x=100, y=100, dy=0;
boolean enSaut = false;
 
void setup() {
  size(200,150);
}
   
void draw() {
  //décor : ciel bleu et rectangle vert
  background(#D6D3FF);
  fill(#34FF4C);
  rect(0,100, width, 50);
  if (enSaut) dy = dy + 1; //on diminue la vitesse
  if (y > 100) {
    enSaut = false;
    dy = 0;
    y = 100;
  }   
  y = y + dy;
   
  //Dessin du personnage en (x,y)
  fill(#D11AEA); //couleur fushia
  ellipse(x,y,20,40); 
}
  
void keyPressed() {
  if (key == CODED){
    //Les touches 'flèche' déplacent le personnage vers la droite/gauche
    if (keyCode == LEFT)   x = x - 10;
    if (keyCode == RIGHT)  x = x + 10;
  } else {
    //si on appuie sur la touche 'ESPACE' 
    //et qu'on n'est pas déjà en saut alors on démarre un saut
    if (key == ' ' && !enSaut) {
      enSaut = true;
      dy = -13; //grosse impulsion
      println("JUMP");
    }
  }
}

pr_saut

Détecter les murs

Pour empêcher le joueur de traverser les murs, on teste la couleur du pixel avant d’autoriser un mouvement. Il s’agit donc de savoir si le pixel, sur lequel on veut se rendre, est de la couleur d’un mur ou pas.

  • color c=get(x,y); donne la couleur du pixel (x,y) du sketch de Processing (en fonction des éléments déjà tracés).
  • color c=photo.get(x,y); donne la couleur du pixel (x,y) sur la photo.

Cette couleur est donnée en AlphaRGB sous la forme d’un entier, et on peut utiliser la méthode hex() pour le convertir en hexadécimal :  println("Couleur="+hex(photo.get(10,99)));

Pour détecter les murs, on va passer par plusieurs méthodes, de plus en plus perfectionnées.

méthode basée sur le centre du joueur

Si le pixel, sur lequel on veut se rendre, n’est pas de la couleur d’un mur alors on y va.
Sinon on ne fait rien.

Exemple : Le joueur est en (x,y). Chaque mouvement est de 10px. La couleur des murs est noire #000000.

  • S’il veut aller à droite : alors on teste la couleur du pixel (x+10,y) (le point situé à 10px sur sa droite), si cette couleur n’est pas noire alors on fait le mouvement vers la droite x = x+10; (sinon rien ne se passe).
  • S’il veut aller à gauche : alors on teste la couleur du pixel (x-10,y) (le point situé à 10px sur sa gauche), si cette couleur n’est pas noire alors on fait le mouvement vers la gauche x = x-10; (sinon rien ne se passe).
PImage photo;  // variable photo (de type image)
int x, y;      // variables de type entier
boolean right, left, up, down; // variables booléennes (TRUE ou FALSE)
void setup() {
  size (800, 800); //taille de la fenêtre
  photo = loadImage("decor.png"); //charge en mémoire
  x = ........... ;  //position de départ du joueur
  y = ........... ;
  
  right = left = up = down = false;  //au départ, on est immobile
}
void draw() {
  //décor de fond (blanc avec des murs noirs)
  image(photo, 0, 0); //affiche l’image au point (0,0)
  
  //si on appuie sur une flèche et que le pixel ciblé n'est pas noir
  //alors on modifie x,y de 10px (rappel : noir = #FF000000 ou #000000)
  if (right && photo.get(x+10,y) != #000000) { x = x+10; }
  if (left  && photo.get(x-10,y) != #000000) { x = x-10; }
  if (up    && photo.get(x, .... ) != #000000) { y = .... ; }
  if (down  && photo.get(x, .... ) != #000000) { y = .... ; }  
    
  //on dessine le point jaune en x,y
  strokeWeight(50); //épaisseur du point
  stroke(#EDF500);  //couleur jaune
  point(x, y);
}
void keyPressed() { // si on appuie sur flèche, on met le booléen à TRUE
    if (keyCode == RIGHT) { right = true;}
    if (keyCode == LEFT ) { left = true; }
    if (keyCode == UP)    { up = true;   }
    if (keyCode == DOWN)  { down = true; }
}
void keyReleased() { // si on relâche une flèche alors on remet le booléen à FALSE
    if (keyCode == RIGHT) { right = false;}
    if (keyCode == LEFT ) { left = false; }
    if (keyCode == UP)    { up = false;   }
    if (keyCode == DOWN)  { down = false; }
}

Ça fonctionne bien puisque le centre ne traverse pas de mur … en revanche, le reste de son corps déborde un peu !

méthode basée sur le bord du joueur

Pour empêcher le corps de déborder sur le murs, la solution consiste à tester le bord du corps au lieu de son centre !

  • Si on va à droite : on teste le bord droit (donc on rajoute le rayon qui est 25px) :if (right && get(x+10+25,y)!=#000000)
  • Si on va à gauche : on teste le bord gauche, donc on enlève le rayon de 25px : if (right && get(x-10-25,y)!=#000000)

Corriger le code précédent en rajoutant/enlevant les 25 pixels :

if (right && photo.get(x+10+25 , y) != #000000) { x = x+10; }
if (left  && photo.get(x-10-25 , y) != #000000) { x = x-10; }
if (up    && photo.get(x , ...... ) != #000000) { y = .... ; }
if (down  && photo.get(x , ...... ) != #000000) { y = .... ; }

Cependant, ce n’est pas encore parfait => par exemple, on peut aller vers la droite tout en ayant le bas du corps qui empiète sur le mur !

méthode testant le bord entier

La solution consiste à tester le bord droit dans sa totalité : si aucun pixel n’est de la couleur d’un mur alors on y va !

Pour faire cela on utilise une boucle et un flag.

La méthode du flag est la suivante :

  1. initialisation du flag (un booléen) : le booléen est d’abord initialisé à TRUE avant de rentrer dans la boucle.
  2. boucle : on teste la couleur de chaque pixel par une boucle :
    Si cette couleur est noire, le flag passe à FALSE.
    NB : S’il y a d’autres pixels noirs dans la boucle, cela ne change rien, le flag reste à FALSE.
  3. conclusion : Une fois la boucle finie, la conclusion est simple :
    ♦ si le flag vaut encore TRUE (la valeur initiale) alors aucun pixel n’est noir.
    ♦ si le flag vaut FALSE alors il y a au moins un pixel noir (donc un mur !).
PImage photo;
int x, y;
boolean right, left, up, down;
boolean flag; // variable booléenne (TRUE ou FALSE)
void setup() {
  size (800, 800); //taille de la fenêtre
  photo = loadImage("decor.png"); //charge en mémoire
  x = ........... ;  //position de départ du joueur
  y = ........... ;
  right = left = up = down = false;  //au départ, on est immobile
}
void draw() {
  image(photo, 0, 0); //décor (fond blanc avec des murs noirs)
  //si on appuie sur une flèche, on parcourt tout le bord correspondant
  //Puis si aucun pixel n'est noir alors on modifie x,y de 10px
  if (right) {
    flag = true;
    for (int i=-25 ; i<=25 ; i++)
      if (photo.get(x+10+25 , y+i) == #000000) flag = false;
    if (flag) x = x+10; 
  }
  if (left) {
    flag = true;
    for (int i=-25 ; i<=25 ; i++)
      if (photo.get(x-10-25 , y+i) == #000000) flag = false;
    if (flag) x = x-10; 
  }
  if (up) {
    flag = true;
    for (int i=-25 ; i<=25 ; i++)
      if (photo.get(....... , ......) == #000000) flag = false;
    if (flag) y = ....... ; 
  }
  if (down) {
    flag = true;
    for (int i=-25 ; i<=25 ; i++)
      if (photo.get(....... , ......) == #000000) flag = false;
    if (flag) y = ....... ; 
  }  
  //on dessine le point jaune en x,y
  strokeWeight(50); //épaisseur du point
  stroke(#EDF500);  //couleur jaune
  point(x, y);
}
void keyPressed() { // si on appuie sur flèche, on met le booléen à TRUE
    if (keyCode == RIGHT) { right = true;}
    if (keyCode == LEFT ) { left = true; }
    if (keyCode == UP)    { up = true;   }
    if (keyCode == DOWN)  { down = true; }
}
void keyReleased() { // si on relâche alors on remet le booléen à FALSE
    if (keyCode == RIGHT) { right = false;}
    if (keyCode == LEFT ) { left = false; }
    if (keyCode == UP)    { up = false;   }
    if (keyCode == DOWN)  { down = false; }
}

Pour le mouvement vers le haut, on utilise le bord supérieur :

Personnage (spritesheet)

Fonctionnement

On utilise une feuille de sprites (spritesheet) décomposant tous les mouvements dans toutes les directions.

Puis on découpe une petite image (de dimensions 50 x 50) dans cette feuille, et on l’affiche à l’écran.

On remarque que la 1ère ligne représente le mouvement vers le haut. Donc pour illustrer cette direction, on découpe :

  • 1ère texture :  X=0   Y=0   L=50   H=50
  • 2e texture :   X=50   Y=0   L=50  H=50
  • 3e texture :   X=100  Y=0   L=50  H=50
  • 4e texture :   X=150  Y=0   L=50  H=50
  • 5e texture :   X=200  Y=0   L=50  H=50
  • 6e texture : X=250   Y=0  L=50  H=50         (puis on reviendra à la 1ère texture … en boucle)

=> On peut résumer le mouvement vers le haut en la formule :
X=nbPas*50   Y=0   L=50  H=50  avec nbPas allant de 0 jusqu’à 5.

Idem, la 2e ligne représente le mouvement vers la droite. Donc pour illustrer cette direction, on découpe 50px plus bas, donc Y=50 :

  • 1ère texture : X=0     Y=50    L=50   H=50.
  • 2e texture :   X=50    Y=50    L=50   H=50
  • 3e texture :   X=100   Y=50   L=50  H=50
  • 4e texture :   X=150   Y=50   L=50  H=50
  • 5e texture :   X=200  Y=50   L=50  H=50
  • 6e texture :  X=250   Y=50   L=50  H=50    (puis on reviendra à la 1ère texture … en boucle)

=> le mouvement vers la droite est la formule :
X=nbPas*50   Y=50   L=50  H=50 avec nbPas allant de 0 jusqu’à 5.

Et ainsi de suite …

Enregistrer la feuille de sprites et ajouter le fichier dans Processing.

Ajouter 2 variables PImage (sheet et texture) et un entier nbPas.

PImage sheet, texture;  // variables de type image
int x, y, nbPas;    // variables entières
boolean right, left, up, down; //variables booléennes
void setup() {
  size (800, 800); //taille de la fenêtre
  sheet = loadImage("sonicSheet.png");
  x = width/2;
  y = height/2;
  nbPas = 0;
  right = left = up = down = false;
  
  //On ralentit l'animation à 20 frames/seconde
  frameRate(20);
}
void draw() {
  background(200, 160, 240); //fond d'écran
  
  //A chaque frame, on incrémente le nb de pas.
  //Or nbPas = n° du sprite (de 0 à 5). Donc si nbPas atteint 6, on le remet à 0.
  nbPas++;
  if (nbPas == 6) nbPas = 0;
  
  //On met la texture d'arrêt par défaut situé en X=0 Y=200
  texture = sheet.get(0 , 200, 50, 50);
  
  //Si on est en mouvement : on change de ligne de texture (et la colonne est nbPas)
  if (right) {
      x = x+10; //on avance de 10 px
      texture = sheet.get(nbPas * 50, 50, 50, 50);  //texture de la 2e ligne (donc Y=50)
    }
  if (left)  {
      x = x-10; // on recule de 10px
      texture = sheet.get(nbPas * 50 , 150, 50, 50);  //texture de la 2e ligne (donc Y=150)
    }
  if (up)  {
      y = ...... ;
      texture = sheet.get(nbPas * 50 , .... ,  50, 50);
    }
  if (down) {
      y = ..... ;
      texture = sheet.get(nbPas * 50 , .... , 50, 50);
    }
    
  image(texture, x-25, y-25); //affiche la texture L=50 H=50, qu'on recentre en (x,y)
}
void keyPressed() {
    if (keyCode == RIGHT) { right = true;}
    if (keyCode == LEFT ) { left = true; }
    if (keyCode == UP)    { up = true;   }
    if (keyCode == DOWN)  { down = true; }
}
void keyReleased() {
    if (keyCode == RIGHT) { right = false;}
    if (keyCode == LEFT ) { left = false; }
    if (keyCode == UP)    { up = false;   }
    if (keyCode == DOWN)  { down = false; }
}

2e index pour le frameRate

Le souci est que le changement de texture est trop rapide pour l’oeil à un frameRate normal (60 frames/seconde) et avancer de 10px est trop imprécis.
La solution consiste à changer de texture que tous les 5 pas (par exemple).
Par conséquent, le nbPas varie de 0 à 29 (car le maximum est 30 = 6 textures x 5 pas).
Et le numéro de texture est un modulo de nbPas :  index = nbPas % 5. Ainsi index évolue très lentement.

Exemple : lorsque nPas = 0  alors  index = 0 % 5 = 0
lorsque nPas = 1  alors  index = 1 % 5 = 0
lorsque nPas = 2  alors  index = 2 % 5 = 0
lorsque nPas = 3  alors  index = 3 % 5 = 0
lorsque nPas = 4  alors  index = 4 % 5 = 0
lorsque nPas = 5  alors  index = 5 % 5 = 1
lorsque nPas = 6  alors  index = 6 % 5 = 1  etc … jusqu’au maximum : lorsque nPas = 29 alors  index = 29 % 5 = 5.

PImage sheet, texture;  // variables de type image
int x, y, nbPas, index;    // variables entières
boolean right, left, up, down; //variables booléennes
void setup() {
  size (800, 800); //taille de la fenêtre
  sheet = loadImage("sonicSheet.png");
  x = width/2;
  y = height/2;
  nbPas = index = 0;
  right = left = up = down = false;
}
void draw() {
  background(200, 160, 240); //fond d'écran
  
  //A chaque frame, on incrémente le nbPas (de 0 à 29). index : de 0 à 5 (car 6 textures).
  nbPas++;
  if (nbPas == 30) nbPas = 0;
  index = nbPas / 5;
  
  //Si on est en mouvement : on prend la bonne ligne de texture (la colonne est index)
  if (right || left || up || down) {
    if (right) {
        x = x+3; //on avance de 3 px
        texture = sheet.get(index * 50, 50, 50, 50);  //texture de la 2e ligne (donc Y=50)
      }
    if (left)  {
        x = x-3; // on recule de 3 px
        texture = sheet.get(index * 50 , 150, 50, 50);  //texture de la 4e ligne (donc Y=150)
      }
    if (up)  {
        y = ...... ;
        texture = sheet.get(index * 50 , .... ,  50, 50);
      }
    if (down) {
        y = ..... ;
        texture = sheet.get(index * 50 , .... , 50, 50);
      }
  } else {
    //Sinon on met la texture d'arrêt située en X=0 Y=200 et réinitialise nbPas et index
    nbPas = index = 0;
    texture = sheet.get(0 , 200, 50, 50);
  }
  
  image(texture, x-25, y-25); //affiche la texture L=50 H=50, qu'on recentre en (x,y)
}
void keyPressed() {
    if (keyCode == RIGHT) { right = true;}
    if (keyCode == LEFT ) { left = true; }
    if (keyCode == UP)    { up = true;   }
    if (keyCode == DOWN)  { down = true; }
}
void keyReleased() {
    if (keyCode == RIGHT) { right = false;}
    if (keyCode == LEFT ) { left = false; }
    if (keyCode == UP)    { up = false;   }
    if (keyCode == DOWN)  { down = false; }
}

Autres feuilles de sprites : Il faudra adapter le code ci-dessus au nouveau personnage.
= > Pour calculer les dimensions de la texture : diviser les hauteurs et largeurs de la feuille par le nombre de dessins.

                

Ajouter un son

Avec Minim

installation

Tout d’abord il faut télécharger la librairie :

  1. menu Sketch > Importer une librairie > Ajouter une librairie > sélectionner Sound
  2. puis choisir Minim et cliquer sur ‘Install‘ (le téléchargement s’effectue …).

importer dans le sketch

Ensuite, il faut importer la librairie et les fichiers audio dans le sketch :

  1. librairie : menu Sketch > Importer une librairie > Ajouter une librairie > sélectionner Minim
    => L’import de la librairie est ajouté au sketch : import ddf.minim.*;
  2. fichiers audio : menu Sketch > Ajouter un fichier

jouer un mp3

  1. Il faut définir 2 types de variables :
    Minim minim;  //Lecteur audio
    AudioSample dingdong, trompette; //Les sons (mp3 ou wav)
  2. Puis dans le setup(), il faut initialiser ces variables :
    minim = new Minim(this);
    dingdong = minim.loadSample("DingDong.wav");
    trompette = minim.loadSample("Trompette.mp3");
  3. Puis dès qu’on veut jouer un son (dans setup et/ou draw) :
    dingdong.trigger();
    trompette.trigger();
  4. Enfin, ajouter la fonction stop() ci-dessous, afin que Processing arrête les musiques correctement lorsque le sketch se ferme.
    void stop() { // Minim requires that this function be added
    dingdong.close();
    trompette.close();
    minim.stop();
    super.stop();
    }

Il existe aussi d’autres types de variable de son Minim :
AudioSnippet drum;  initialisé par    drum = minim.loadSnippet("bongo.wav");    et lancé par drum.play(0);
AudioPlayer song;  initialisé par    song = minim.loadFile("mysong.wav");      et lancé par song.play(0);

Avec Sound

Cette librairie n’autorise qu’une seule musique !

installation

Tout d’abord il faut importer la librairie :

  1. menu Sketch > Importer une librairie > Ajouter une librairie > sélectionnerSound
  2. puis choisir Sound | Sound librairie for Processing et cliquer sur ‘Install‘ (le téléchargement s’effectue …).

importer dans le sketch

Ensuite, il faut importer la librairie et les fichiers audio dans le sketch :

  1. librairie : menu Sketch > Importer une librairie > Ajouter une librairie > sélectionner Sound
    => Les imports sont ajoutés au sketch.
  2. fichiers audio : menu Sketch > Ajouter un fichier

jouer un mp3 (mais un seul !)

  1. Il faut définir une variable (et une seule) :  SoundFile musiqueDeFond;
  2. Puis dans le setup(), il faut initialiser cette variable :
    musiqueDeFond = new SoundFile(this, "music.mp3");
  3. Pour démarrer la lecture (dans setup et/ou draw) : musiqueDeFond.play();
  4. Pour l’arrêter : musiqueDeFond.stop();

NB : musiqueDeFond.loop();   : pour une lecture en boucle

Video de webcam

Capture d’une Webcam

On va utiliser la librairie Video de Sarxos (car elle bug moins que video de Processing).

  1. Télécharger le fichier ZIP de « Webcam Capture API » sur http://webcam-capture.sarxos.pl/
    Puis on va devoir installer cette librairie à la main et faire des modifications dans l’architecture des dossiers car c’est une bibliothèque Java (et non formatée pour Processing).
  2. Décompresser le ZIP et copier le dossier obtenu webcam-capture-0.3.10-dist dans le dossier libraries de votre Sketchbook, càd :   Mes Documents > Processing > libraries
  3. Comme Processing n’accepte pas les tirets ‘-‘ dans les noms de librairies alors on va renommer cette librairie (le dossier et le fichier JAR) :
    • Renommer le dossier webcam-capture-0.3.10-dist en  webcam_capture .
    • Puis faire pareil avec le fichier JAR qui est dans ce dossier :  changer  webcam-capture-0.3.10-dist.jar en  webcam_capture.jar

    En fait, le nom du dossier et le nom du fichier JAR doivent toujours être identiques.

  4. Il faut savoir que libs est le dossier des dépendances, ce sont les librairies nécessaires à la librairie de Sarxos. Mais Processing veut que ce dossier porte le nom library , donc il faut renommer le dossier libs en library .
  5. De plus, Processing veut que le JAR principal soit dans ce dossier, donc il faut déplacer webcam_capture.jar dans ce dossier library .
  6. Puis on va mettre à jour les dépendances :
    • Dans le répertoire library, supprimer le fichier slf4j*.jar  (l’ancienne version).
    • Télécharger sur https://www.slf4j.org/download.html le ZIP de la dernière version STABLE de SLF4J et le décompresser.
    • Copier ces 2 nouveaux fichiers vers library :
      * slf4j-api-1.7.26.jar
      * slf4j-nop-1.7.26.jar

  7. Tester avec le programme ci-dessous :
import com.github.sarxos.webcam.*;
import java.awt.*;
 
Webcam webcam;
 
void setup() {
  size(640, 480);
  webcam = Webcam.getDefault();
  if (webcam != null) {
    println("Webcam: " + webcam.getName());
    webcam.open();
  } else {
    println("No webcam detected");
  }
}
 
void draw() {
   PImage imgVideo = new PImage(webcam.getImage());
   image (imgVideo, 0, 0);
}

facultatif :

  • webcam.setViewSize(new Dimension(1024, 768));  mettre une résolution
  • webcam.setViewSize(webcam.getViewSizes()[webcam.getViewSizes().length-1]); mettre en résolution maximale
  • webcam.isImageNew()  :  booléen pour savoir si la caméra a une nouvelle image
  • for (Webcam cam : Webcam.getWebcams())  println("Webcam detected: " + cam.getName());
    affiche en console la liste des caméras.
  • ArrayList<Webcam> cams = new ArrayList<Webcam>(Webcam.getWebcams()); stocker les caméras disponibles dans une liste.
  • webcam=Webcam.getWebcams().get(1); choisir la 2e caméra de la liste de webcams .

Reconnaissance faciale

On va installer une nouvelle librairie : « OpenCV for Processing ».
Dans le menu de Processing : Sketch > importer une librairie > ajouter une librairie.
Taper OpenCV dans la barre de recherche puis « install ».

Pour une image de Webcam, on utilise aussi la librairie video de Sarxos (voir l’installation ci-dessus) :

import gab.opencv.*;
import com.github.sarxos.webcam.*;
import java.awt.*;

Webcam webcam;
OpenCV opencv;

void setup() {
  size(640, 480);
  webcam = Webcam.getDefault();
  if (webcam != null) {
    webcam.open();
    opencv = new OpenCV(this, 640, 480);
    opencv.loadCascade(OpenCV.CASCADE_FRONTALFACE);
  } else {
    println("No webcam detected");
    exit();
  }
}

void draw() {
  PImage imgVideo = new PImage(webcam.getImage());
  image (imgVideo, 0, 0);
  opencv.loadImage(imgVideo);
  noFill();
  stroke(0, 255, 0);
  strokeWeight(3);
  Rectangle[] faces = opencv.detect();  //un tableau de rectangles
  for (int i = 0; i < faces.length; i++) {
    println(faces[i].x + "," + faces[i].y);
    rect(faces[i].x, faces[i].y, faces[i].width, faces[i].height);
  }
}

liaison Processing-Arduino

Pour transmettre un nombre Processing -> Arduino par liaison série.

Ne pas exécuter le sketch de Processing pendant le téléversement : effectivement, le téléversement utilise aussi la même liaison série que Processing alors on ne peut pas avoir les 2 en même temps.
Idem, on ne peut pas ouvrir le moniteur série pendant le sketch de Processing car ils utilisent la même liaison série.

Pour Processing :

import processing.serial.*;

Serial port;

void setup() {
  // initialise le port série : Serial.list()[0] pour windows
  port = new Serial(this, Serial.list()[0], 57600);
}

void draw() { }

void mousePressed() {
  //A chaque clic, on génère un entier aléatoire et on le transmet à Arduino
  int number = (int) random(100);
  port.write(Integer.toString(number));
  println("Nombre envoyé : "+number);
  port.write('e');  // caractère utilisé comme marqueur de fin
}

void serialEvent(Serial p) {
  //cette partie n'est exécuté qu'n cas de réception de data (de la part d'Arduino)
  try {
    // lit le message jusqu'au marqueur 'line break' (ASCII > 13)
    String message = p.readStringUntil(13);

    // s'il y a bien des data, on les écrit en console
    if (message != null) { 
      println("message received: "+trim(message));
    }
  }
  catch (Exception e) {
  }
}

Pour Arduino :

int v = 0, nombre = 0;
int ledPin = 13; //la led native de la carte sur la pin 13

void setup() {
  pinMode(ledPin, OUTPUT); // Met la ledpin sur OUTPUT
  Serial.begin(57600);
}

void loop() {
  // si on a une connexion série, on lit le caractère reçu
  while (Serial.available()) {
    int c = Serial.read();
    //on le transforme en nombre
    if ((c >= '0') && (c <= '9')) {
      v = 10 * v + c - '0';
    }
    
    // si le caractère est le délimiteur de fin, 
    else if (c == 'e') {
      Serial.println(v); //on renvoie le nombre à Processing
      nombre  = v; // on stocke le nombre obtenu ds nombre
      v = 0; //on ré-initialise v (pour recevoir un prochain nombre)
    }
  }

  // Taitement de l'information : si le nbre > 10 alors j'allume la led 1 seconde 
  if (nombre > 10) {
    digitalWrite(ledPin, HIGH); // met du courant dans la led
    delay(1000);  // pdt 1 sec
    digitalWrite(ledPin, LOW); // stoppe le courant
    nombre = 0; // ré-initialise à une valeur inférieure à 10.
  }
}