Cours:Idees OOP : Différence entre versions

De troyesGEII
Aller à : navigation, rechercher
m (Travail à réaliser)
m (Travail 4)
 
(45 révisions intermédiaires par le même utilisateur non affichées)
Ligne 14 : Ligne 14 :
  
 
===Exercice 2===
 
===Exercice 2===
1°) Transformer le code ci-dessous en une classe Processing pour utilisation.
+
 
 +
====Question 1====
 +
Transformer le code ci-dessous en une classe Processing pour utilisation.
  
 
'''<u>Indications</u>''' : on vous donne le code permettant un affichage d'un seul digit
 
'''<u>Indications</u>''' : on vous donne le code permettant un affichage d'un seul digit
Ligne 59 : Ligne 61 :
 
}
 
}
 
</source>
 
</source>
 
2°) Faire fonctionner la correction de l'exercice 1. Puis réaliser l'affichage du compteur binaire de la correction sur deux digits
 
 
3°) Réaliser un affichage de 4 digits destiné à afficher l'heure et les minutes d'un réveil.
 
 
4°) Modifier la classe pour pouvoir changer la taille de chaque digit (!!! ANNULE !!!)
 
 
5°) Réaliser une classe "HHMMClass" de 2x2 digits séparés par deux points.
 
 
'''Indication''' : voici le début de la classe. Il ne vous reste qu'à positionner les ':' et probablement être capable de positionner cet ensemble de digits si vous voulez un jour afficher l'heure courante et l'heure réveil.
 
<source lang=Java>
 
class HHMMClass {
 
  int posX,posY;
 
  int hh_mm;
 
  Digit[] digits = new Digit[4];
 
  HHMMClass() {
 
    posX=posY=0;
 
    hh_mm = 0x2340;
 
    for(int i=0;i<4;i++)
 
      digits[i]=new Digit(100*i,50);
 
  }
 
  void affiche() {
 
    for(int i=0;i<4;i++) {
 
      digits[3-i].put(hh_mm >> (4*i) & 0xF);
 
      digits[3-i].affiche7segs(255,0,0);
 
    }
 
  }
 
  void incrementHHMM() {
 
      (hh_mm)++;
 
      if ((hh_mm & 0x000F) > 0x0009)
 
        hh_mm += 0x0006;
 
      if ((hh_mm & 0x00F0) > 0x0050)
 
        hh_mm += 0x00A0;
 
      if ((hh_mm & 0x0F00) > 0x0900)
 
        hh_mm += 0x0600;
 
      if ((hh_mm & 0xFF00) > 0x2300)
 
        hh_mm = 0x0000;
 
  }
 
  void decrementHHMM() {
 
      (hh_mm)--;
 
      if ((hh_mm & 0x000F) == 0x000F)
 
      hh_mm -= 0x0006;
 
      if ((hh_mm & 0x00F0) == 0x00F0)
 
      hh_mm -= 0x00A0;
 
      if ((hh_mm & 0x0F00) == 0x0F00)
 
      hh_mm -= 0x0600;
 
      if ((hh_mm & 0xFFFF) > 0x2359)
 
      hh_mm = 0x2359;
 
  }
 
}
 
</source>
 
Faire vos propres essais avant de passer à la question suivante. L'utilisation de cette classe nécessite l'utilisation de la classe digit avec laquelle elle possède un '''lien fort'''.
 
 
6°) Utiliser cette classe pour afficher l'heure courante. On utilisera
 
*[https://processing.org/reference/second_.html second()] (éventuellement si vous avez prévu l'affichage des secondes)
 
*[https://processing.org/reference/minute_.html minute()]
 
*[https://processing.org/reference/hour_.html hour()]
 
Le code [https://processing.org/examples/clock.html d'une horloge à aiguilles] est disponible sur Internet.
 
 
 
7°) Modifier la classe HHMMClass pour pouvoir afficher les heures et les minutes à un endroit précis. Cela devrait ainsi vous permettre d'afficher à la fois l'heure courante et l'heure de réveil.
 
 
 
8°) Vous réaliserez ensuite un mécanisme de mise à jour de l'heure réveil. On pourra utiliser pour cela les fonctions souris :
 
* [https://processing.org/reference/mouseX.html mouseX]
 
* [https://processing.org/reference/mouseY.html mouseY]
 
* [https://processing.org/reference/mousePressed.html mousePressed]
 
* [https://processing.org/reference/mousePressed_.html mousePressed()]
 
et réaliser deux boutons UP et DOWN avec des rectangles.
 
 
'''Indications''' : La gestion des boutons serait mieux réalisée avec une classe Bouton. Nous vous en proposons une (assez simplifiée) :
 
<source lang=Java>
 
class Bouton
 
{
 
  int etat;
 
  String label;
 
  int couleur; // en gris
 
  //int r,v,b; // couleur allumé
 
  int posX,posY,dX,dY;
 
 
  Bouton() {
 
    couleur = 84;
 
    posX=0; posY=0; dX=40; dY=40;
 
  }
 
 
  Bouton(int posx,int posy,String txt) {
 
    couleur = 84;
 
    posX=posx; posY=posy; dX=40; dY=40;
 
    label = txt;
 
  }
 
 
  void showOff() {
 
    fill(couleur);
 
    rect(posX,posY,dX,dY);
 
    textSize(24);
 
    fill(0,255,0);
 
    text(label,posX,posY+dY+24);
 
  }
 
 
  void showOn() {
 
    fill(couleur);
 
    rect(posX,posY,dX,dY);
 
    fill(0,192,0);
 
    ellipseMode(CORNER);
 
    ellipse(posX,posY,dX,dY);
 
    fill(0,255,0);
 
    ellipse(posX+5,posY+5,dX-10,dY-10); 
 
  }
 
 
 
  Boolean mouseIn() {
 
    if ((mouseX>posX) && (mouseX < posX+dX)
 
      && (mouseY>posY) && (mouseY < posY+dY))
 
        return true;
 
    else return false;
 
  }
 
 
 
}
 
</source>
 
 
9°) Pour finir, il ne vous reste qu'à faire le mécanisme qui fait sonner le réveil quand l'heure courante est égale à l'heure réveil. Vous pourrez vous inspirer de la [https://fr.wikiversity.org/wiki/Micro_contr%C3%B4leurs_AVR/Travail_pratique/Utilisation_du_shield_LCD_keypad#Exercice_9 correction trouvée dans la Wikiversité].
 
 
'''Indications''' :
 
 
* Le bouton d'armement est un peu particulier puisqu'il mémorise son état. Il faut donc spécialiser la classe bouton de la question précédente.
 
* Il existe une classe [https://processing.org/reference/libraries/sound/ Sound] pour processing, mais vous devez vérifier si elle est installée ou pas.
 
 
 
10°) Utiliser l'héritage pour fabriquer un bouton de type switch.
 
 
'''Indications : '''
 
*[[Media:OrienteObjet.pdf|Cours Association et héritage]] appliqué à notre problématique. Il y a la réponse dans l'exercice 6 de ce cours.
 
* Et le code ressource :
 
**La classe BoutonSuper
 
<source lang=Java>
 
class BoutonSuper {
 
  String label;
 
  int couleur; // en gris
 
  int posX,posY,dX,dY;
 
  BoutonSuper() {
 
    couleur = 84;
 
    posX=0; posY=0; dX=40; dY=40;
 
  }
 
  BoutonSuper(int posx,int posy,String txt) {
 
    couleur = 84;
 
    posX=posx; posY=posy; dX=40; dY=40;
 
    label = txt;
 
  }
 
  void showOff() {
 
    fill(couleur);
 
    rect(posX,posY,dX,dY);
 
    strokeWeight(2);
 
    stroke(0);
 
    line(posX,posY+dY,posX+dX,posY+dY);
 
    line(posX+dX,posY,posX+dX,posY+dY);
 
    stroke(255);
 
    line(posX,posY,posX+dX,posY);
 
    line(posX,posY,posX+dX,posY);
 
    strokeWeight(1);
 
    noStroke();
 
    textSize(24);
 
    fill(0,255,0);
 
    text(label,posX,posY+dY+24);
 
  }
 
  void showOn() {   
 
  }
 
  Boolean mouseIn() {
 
    if ((mouseX>posX) && (mouseX < posX+dX)
 
      && (mouseY>posY) && (mouseY < posY+dY))
 
        return true;
 
    else return false;
 
  }
 
}
 
</source>
 
**La classe Bouton
 
<source lang=Java>
 
class Bouton extends BoutonSuper
 
{
 
    Bouton(int posx,int posy,String txt) {
 
    couleur = 84;
 
    posX=posx; posY=posy; dX=40; dY=40;
 
    label = txt;
 
  }
 
  void showOn() {
 
    fill(couleur);
 
    rect(posX,posY,dX,dY);
 
    fill(0,192,0);
 
    ellipseMode(CORNER);
 
    ellipse(posX,posY,dX,dY);
 
    fill(0,255,0);
 
    ellipse(posX+5,posY+5,dX-10,dY-10);
 
  }
 
}
 
</source>
 
**La classe Switch
 
<source lang=Java>
 
class Switch extends BoutonSuper
 
{
 
  int etat;
 
  Switch(int posx,int posy,String txt) {
 
    couleur = 84;
 
    posX=posx; posY=posy; dX=30; dY=40;
 
    label = txt;
 
    etat=0;
 
  }
 
  void showOff() {
 
    fill(couleur);
 
    rect(posX,posY,dX,dY);
 
    strokeWeight(2);
 
    stroke(0);
 
    line(posX,posY+dY,posX+dX,posY+dY);
 
    line(posX+dX,posY,posX+dX,posY+dY);
 
    stroke(255);
 
    line(posX,posY,posX+dX,posY);
 
    line(posX,posY,posX+dX,posY);
 
    strokeWeight(1);
 
    noStroke();
 
    textSize(24);
 
    fill(0,255,0);
 
    text(label,posX,posY+dY+24);
 
  }
 
  void switchEtat() {
 
    etat ^= 1;
 
  }
 
  void showOn() {
 
    fill(couleur);
 
    rect(posX,posY,dX,dY);
 
    fill(0,192,0);
 
    ellipseMode(CORNER);
 
    ellipse(posX,posY,dX,dY);
 
    fill(0,255,0);
 
    ellipse(posX+5,posY+5,dX-10,dY-10);
 
  }
 
  void show() {
 
    if (etat == 0) showOff(); else showOn();
 
  }
 
}
 
</source>
 
** et un exemple d'utilisation :
 
<source lang=Java>
 
Bouton bouton1 = new Bouton(50,50,"UP");
 
Switch switch1 = new Switch(150,50,"SW0");
 
void setup() {
 
  size(300,300);
 
  frameRate(10);
 
}
 
void draw() {
 
    bouton1.showOff();
 
    switch1.show();
 
}
 
void mousePressed() {
 
  if (bouton1.mouseIn()) {
 
      bouton1.showOn();
 
    } else if (switch1.mouseIn()) {
 
      switch1.switchEtat();
 
    }
 
}
 
</source>
 
 
Poursuivez avec l'exercice 7 du cours ci-dessus qui change seulement l'apparence du bouton.
 
 
 
 
  
 
====Réponse à la question 1 (Exercice 2)====
 
====Réponse à la question 1 (Exercice 2)====
Ligne 414 : Ligne 154 :
 
</source>
 
</source>
  
====Réponse à la question 6 (Exercice 2)====
+
'''<u>FIN DE LA CORRECTION de la question 1</u>'''
 +
 
 +
====Question 2 ====
 +
Faire fonctionner la correction de la question 1. Puis réaliser un affichage de compteur binaire sur deux digits.
 +
 
 +
====Correction de la question 2====
 +
La classe digit est inchangée par rapport à la question 1. On ne donne donc que le programme principal.
 +
<source lang=java>
 +
Digit digitpoids0,digitpoids1;
 +
 
 +
void setup() { 
 +
  digitpoids0 = new Digit(150,50);
 +
  digitpoids1 = new Digit(50,50);
 +
  frameRate(1);
 +
  size(480, 400);
 +
}
 +
 
 +
int i=0;
 +
 
 +
void draw() { 
 +
  i++;
 +
  digitpoids0.put(i%16);
 +
  digitpoids0.affiche7segs(255,0,0);
 +
  digitpoids1.put((i/16)%16);
 +
  digitpoids1.affiche7segs(255,0,0);
 +
}
 +
</source>
 +
 
 +
====Question 3====
 +
Réaliser un affichage de 4 digits destiné à afficher l'heure et les minutes d'un réveil. A ce stade, on ne vous demande pas de réaliser un compteur heures/minutes. En effet l'arithmétique heures/minutes est très particulière et on vous donnera de l'aide pour la réaliser. '''Vous pouvez par contre réaliser un compteur décimal qui affichera donc sur 4 digits'''.
 +
 
 +
====Question 4====
 +
Modifier la classe pour pouvoir changer la taille de chaque digit ('''!!! ANNULE !!!''')
 +
 
 +
====Question 5====
 +
Réaliser une classe "HHMMClass" de 2x2 digits séparés par deux points.
 +
 
 +
'''Indication''' : voici le début de la classe. Il ne vous reste qu'à positionner les ':' et probablement être capable de positionner cet ensemble de digits si vous voulez un jour afficher l'heure courante et l'heure réveil.
 +
<source lang=Java>
 +
class HHMMClass {
 +
  int posX,posY;
 +
  int hh_mm;
 +
  Digit[] digits = new Digit[4];
 +
  HHMMClass() {
 +
    posX=posY=0;
 +
    hh_mm = 0x2340;
 +
    for(int i=0;i<4;i++)
 +
      digits[i]=new Digit(100*i,50);
 +
  }
 +
  void affiche() {
 +
    for(int i=0;i<4;i++) {
 +
      digits[3-i].put(hh_mm >> (4*i) & 0xF);
 +
      digits[3-i].affiche7segs(255,0,0);
 +
    }
 +
  }
 +
  void incrementHHMM() {
 +
      (hh_mm)++;
 +
      if ((hh_mm & 0x000F) > 0x0009)
 +
        hh_mm += 0x0006;
 +
      if ((hh_mm & 0x00F0) > 0x0050)
 +
        hh_mm += 0x00A0;
 +
      if ((hh_mm & 0x0F00) > 0x0900)
 +
        hh_mm += 0x0600;
 +
      if ((hh_mm & 0xFF00) > 0x2300)
 +
        hh_mm = 0x0000;
 +
  }
 +
  void decrementHHMM() {
 +
      (hh_mm)--;
 +
      if ((hh_mm & 0x000F) == 0x000F)
 +
      hh_mm -= 0x0006;
 +
      if ((hh_mm & 0x00F0) == 0x00F0)
 +
      hh_mm -= 0x00A0;
 +
      if ((hh_mm & 0x0F00) == 0x0F00)
 +
      hh_mm -= 0x0600;
 +
      if ((hh_mm & 0xFFFF) > 0x2359)
 +
      hh_mm = 0x2359;
 +
  }
 +
}
 +
</source>
 +
Faire vos propres essais avant de passer à la question suivante. L'utilisation de cette classe nécessite l'utilisation de la classe digit avec laquelle elle possède un '''lien fort'''.
 +
 
 +
====Question 6====
 +
Utiliser cette classe pour afficher l'heure courante. On utilisera
 +
*[https://processing.org/reference/second_.html second()] (éventuellement si vous avez prévu l'affichage des secondes)
 +
*[https://processing.org/reference/minute_.html minute()]
 +
*[https://processing.org/reference/hour_.html hour()]
 +
Le code [https://processing.org/examples/clock.html d'une horloge à aiguilles] est disponible sur Internet.
 +
 
 +
====Correction question 6====
 
Voici la nouvelle classe HHMMClass :
 
Voici la nouvelle classe HHMMClass :
 
<source lang=Java>
 
<source lang=Java>
Ligne 495 : Ligne 323 :
 
</source>
 
</source>
  
====Réponse à la question 7 (Exercice 2)====
+
====Question 7====
Nous avons ajouté une possibilité de zoom en plus d'un placement défini. Voici donc la classe HHMM complète correspondante :
+
Modifier la classe HHMMClass pour pouvoir afficher les heures et les minutes à un endroit précis. Cela devrait ainsi vous permettre d'afficher à la fois l'heure courante et l'heure de réveil.
 +
 
 +
====Correction question 7====
 +
Nous avons ajouté la possibilité de déplacer l'affichage des 4 digits ainsi que leur grandeur.
 +
 
 +
Nouvelle classe HHMM :
 
<source lang=Java>
 
<source lang=Java>
 
class HHMMClass {
 
class HHMMClass {
 
   int posX,posY;
 
   int posX,posY;
 
   int hh_mm;
 
   int hh_mm;
 +
  int rouge,vert,bleu;
 
   float zoom;
 
   float zoom;
 
   Digit[] digits = new Digit[4];
 
   Digit[] digits = new Digit[4];
 
 
 
   HHMMClass() {
 
   HHMMClass() {
 
     posX=posY=0;
 
     posX=posY=0;
 +
    hh_mm = 0x950;
 +
    zoom=1.0;
 +
    for(int i=0;i<4;i++) {
 +
      if (i < 2)
 +
        digits[i]=new Digit(100*i,50);
 +
      else
 +
        digits[i]=new Digit(100*(i+1),50);
 +
    }
 +
  }
 +
  HHMMClass(int x,int y) {
 +
    posX= x;
 +
    posY=y;
 +
    hh_mm = 0x950;
 +
    for(int i=0;i<4;i++) {
 +
      if (i < 2)
 +
        digits[i]=new Digit(100*i+posX,50+posY);
 +
      else
 +
        digits[i]=new Digit(100*(i+1)+posX,50+posY);
 +
    }
 
     zoom=1.0;
 
     zoom=1.0;
 +
  }
 +
  HHMMClass(int x,int y,int red,int green,int blue) {
 +
    posX= x;
 +
    posY=y;
 +
    rouge = red;
 +
    vert = green;
 +
    bleu = blue;
 
     hh_mm = 0x950;
 
     hh_mm = 0x950;
 
     for(int i=0;i<4;i++) {
 
     for(int i=0;i<4;i++) {
 
       if (i < 2)
 
       if (i < 2)
         digits[i]=new Digit(100*i,50,zoom);
+
         digits[i]=new Digit(100*i+posX,50+posY);
 
       else
 
       else
         digits[i]=new Digit(100*(i+1),50,zoom);
+
         digits[i]=new Digit(100*(i+1)+posX,50+posY);
 
     }
 
     }
 +
    zoom=1.0;
 
   }
 
   }
 
+
   HHMMClass(int x,int y,int red,int green,int blue,float grossissement) {
   HHMMClass(int posx,int posy,float grossissement) {
+
    posX= x;
 +
    posY=y;
 +
    rouge = red;
 +
    vert = green;
 +
    bleu = blue;
 
     zoom = grossissement;
 
     zoom = grossissement;
    posX=posx; posY=posy;
 
 
     hh_mm = 0x950;
 
     hh_mm = 0x950;
 
     for(int i=0;i<4;i++) {
 
     for(int i=0;i<4;i++) {
 
       if (i < 2)
 
       if (i < 2)
         digits[i]=new Digit(int(100*i+posX),int(50+posY),zoom);
+
         digits[i]=new Digit(100*i+posX,50+posY,zoom);
 
       else
 
       else
         digits[i]=new Digit(int(100*(i+1)+posX),int(50+posY),zoom);
+
         digits[i]=new Digit(100*(i+1)+posX,50+posY,zoom);
 
     }
 
     }
 
   }
 
   }
 
+
   void affiche() {
   void affiche(int red,int green,int blue) {
 
 
     for(int i=0;i<4;i++) {
 
     for(int i=0;i<4;i++) {
 
       digits[3-i].put(hh_mm >> (4*i) & 0xF);
 
       digits[3-i].put(hh_mm >> (4*i) & 0xF);
       digits[3-i].affiche7segs(red,green,blue);
+
       digits[3-i].affiche7segs(rouge,vert,bleu);
 
     }
 
     }
     if ((second() & 1) == 1)
+
     if ((second() % 2) == 1)
       fill(red,green,blue);
+
       fill(rouge,vert,bleu);
 
     else  
 
     else  
 
       fill(200);
 
       fill(200);
 
        
 
        
     ellipse(int((260+posX)*zoom),int((100+posY)*zoom),20*zoom,20*zoom);
+
     ellipse((260+posX)*zoom,(100+posY)*zoom,20*zoom,20*zoom);
     ellipse(int((255+posX)*zoom),int((150+posY)*zoom),20*zoom,20*zoom);
+
     ellipse((255+posX)*zoom,(150+posY)*zoom,20*zoom,20*zoom);
 
   }
 
   }
 
    
 
    
Ligne 573 : Ligne 435 :
 
}
 
}
 
</source>
 
</source>
Cette classe possède un défaut : le facteur de zoom intervient sur le déplacement !
 
  
On vous donne de plus la nouvelle classe Digit :
+
La classe Digit a du être elle aussi modifiée :
 
<source lang=Java>
 
<source lang=Java>
 
class Digit {
 
class Digit {
Ligne 584 : Ligne 445 :
 
   Digit(){
 
   Digit(){
 
     nb1digit = val[0];
 
     nb1digit = val[0];
    zoom = 1.0;
 
 
     x=0;y=0;
 
     x=0;y=0;
 +
    zoom=1.0;
 
   }
 
   }
 
   Digit(int nb){
 
   Digit(int nb){
 
     x=0;y=0;
 
     x=0;y=0;
     zoom = 1.0;
+
     zoom=1.0;
 
     if (nb < 16)
 
     if (nb < 16)
 
       nb1digit = val[nb];
 
       nb1digit = val[nb];
Ligne 596 : Ligne 457 :
 
   }
 
   }
 
    
 
    
   Digit(int xd, int yd,float dilatation){
+
   Digit(int xd, int yd){
 
     nb1digit = val[0];
 
     nb1digit = val[0];
    zoom = dilatation;
 
 
     x=xd;y=yd;
 
     x=xd;y=yd;
 +
    zoom=1.0;
 +
  }
 +
 
 +
  Digit(int xd, int yd, float grossissement){
 +
    nb1digit = val[0];
 +
    x=xd;y=yd;
 +
    zoom=grossissement;
 
   }
 
   }
 
    
 
    
Ligne 626 : Ligne 493 :
 
   if ((nb1digit & 1) == 1) fill(rouge,vert,bleu); else fill(200);
 
   if ((nb1digit & 1) == 1) fill(rouge,vert,bleu); else fill(200);
 
   segment(); // segment a
 
   segment(); // segment a
   translate(-10*zoom,70*zoom);
+
   translate((-10)*zoom,70*zoom);
 
   if ((nb1digit & 64) == 64) fill(rouge,vert,bleu); else fill(200);
 
   if ((nb1digit & 64) == 64) fill(rouge,vert,bleu); else fill(200);
 
   segment(); // segment g
 
   segment(); // segment g
Ligne 651 : Ligne 518 :
 
</source>
 
</source>
  
====Réponse à la question 10 (Exercice 2)====
+
Et le programme principal :
 +
<source lang=Java>
 +
HHMMClass heureC;
 +
void setup() {
 +
  heureC = new HHMMClass(100,50,255,0,0,1.4);
 +
  frameRate(10);
 +
  size(900,400);
 +
}
 +
 
 +
void draw() {
 +
  heureC.updateHHMM();
 +
  heureC.affiche();
 +
}
 +
</source>
 +
 
 +
====Question 8====
 +
1°) Réaliser un affichage heure courante heure réveil
 +
 
 +
2°) Vous réaliserez ensuite un mécanisme de mise à jour de l'heure réveil. On pourra utiliser pour cela les fonctions souris :
 +
* [https://processing.org/reference/mouseX.html mouseX]
 +
* [https://processing.org/reference/mouseY.html mouseY]
 +
* [https://processing.org/reference/mousePressed.html mousePressed]
 +
* [https://processing.org/reference/mousePressed_.html mousePressed()]
 +
et réaliser deux boutons UP et DOWN avec des rectangles.
 +
 
 +
'''Indications''' : La gestion des boutons serait mieux réalisée avec une classe Bouton. Nous vous en proposons une (assez simplifiée) :
 +
<source lang=Java>
 +
class Bouton
 +
{
 +
  int etat;
 +
  String label;
 +
  int couleur; // en gris
 +
  //int r,v,b; // couleur allumé
 +
  int posX,posY,dX,dY;
 +
 
 +
  Bouton() {
 +
    couleur = 84;
 +
    posX=0; posY=0; dX=40; dY=40;
 +
  }
 +
 
 +
  Bouton(int posx,int posy,String txt) {
 +
    couleur = 84;
 +
    posX=posx; posY=posy; dX=40; dY=40;
 +
    label = txt;
 +
  }
 +
 
 +
  void showOff() {
 +
    fill(couleur);
 +
    rect(posX,posY,dX,dY);
 +
    textSize(24);
 +
    fill(0,255,0);
 +
    text(label,posX,posY+dY+24);
 +
  }
 +
 
 +
  void showOn() {
 +
    fill(couleur);
 +
    rect(posX,posY,dX,dY);
 +
    fill(0,192,0);
 +
    ellipseMode(CORNER);
 +
    ellipse(posX,posY,dX,dY);
 +
    fill(0,255,0);
 +
    ellipse(posX+5,posY+5,dX-10,dY-10); 
 +
  }
 +
 
 +
  Boolean mouseIn() {
 +
    if ((mouseX>posX) && (mouseX < posX+dX)
 +
      && (mouseY>posY) && (mouseY < posY+dY))
 +
        return true;
 +
    else return false;
 +
  }
 +
 
 +
}
 +
</source>
 +
 
 +
====Question 9====
 +
Pour finir, il ne vous reste qu'à faire le mécanisme qui fait sonner le réveil quand l'heure courante est égale à l'heure réveil. Vous pourrez vous inspirer de la [https://fr.wikiversity.org/wiki/Micro_contr%C3%B4leurs_AVR/Travail_pratique/Utilisation_du_shield_LCD_keypad#Exercice_9 correction trouvée dans la Wikiversité].
 +
 
 +
'''Indications''' :
 +
 
 +
* Le bouton d'armement est un peu particulier puisqu'il mémorise son état. Il faut donc spécialiser la classe bouton de la question précédente.
 +
* Il existe une classe [https://processing.org/reference/libraries/sound/ Sound] pour processing, mais vous devez vérifier si elle est installée ou pas.
 +
 
 +
 
 +
====Question 10====
 +
Utiliser l'héritage pour fabriquer un bouton de type switch.
 +
 
 +
'''Indications : '''
 +
*[[Media:OrienteObjet.pdf|Cours Association et héritage]] appliqué à notre problématique. Il y a la réponse dans l'exercice 6 de ce cours.
 +
* Et le code ressource :
 +
**La classe BoutonSuper
 +
<source lang=Java>
 +
class BoutonSuper {
 +
  String label;
 +
  int couleur; // en gris
 +
  int posX,posY,dX,dY;
 +
  BoutonSuper() {
 +
    couleur = 84;
 +
    posX=0; posY=0; dX=40; dY=40;
 +
  }
 +
  BoutonSuper(int posx,int posy,String txt) {
 +
    couleur = 84;
 +
    posX=posx; posY=posy; dX=40; dY=40;
 +
    label = txt;
 +
  }
 +
  void showOff() {
 +
    fill(couleur);
 +
    rect(posX,posY,dX,dY);
 +
    strokeWeight(2);
 +
    stroke(0);
 +
    line(posX,posY+dY,posX+dX,posY+dY);
 +
    line(posX+dX,posY,posX+dX,posY+dY);
 +
    stroke(255);
 +
    line(posX,posY,posX+dX,posY);
 +
    line(posX,posY,posX+dX,posY);
 +
    strokeWeight(1);
 +
    noStroke();
 +
    textSize(24);
 +
    fill(0,255,0);
 +
    text(label,posX,posY+dY+24);
 +
  }
 +
  void showOn() {   
 +
  }
 +
  Boolean mouseIn() {
 +
    if ((mouseX>posX) && (mouseX < posX+dX)
 +
      && (mouseY>posY) && (mouseY < posY+dY))
 +
        return true;
 +
    else return false;
 +
  }
 +
}
 +
</source>
 +
**La classe Bouton
 +
<source lang=Java>
 +
class Bouton extends BoutonSuper
 +
{
 +
    Bouton(int posx,int posy,String txt) {
 +
    couleur = 84;
 +
    posX=posx; posY=posy; dX=40; dY=40;
 +
    label = txt;
 +
  }
 +
  void showOn() {
 +
    fill(couleur);
 +
    rect(posX,posY,dX,dY);
 +
    fill(0,192,0);
 +
    ellipseMode(CORNER);
 +
    ellipse(posX,posY,dX,dY);
 +
    fill(0,255,0);
 +
    ellipse(posX+5,posY+5,dX-10,dY-10);
 +
  }
 +
}
 +
</source>
 +
**La classe Switch
 +
<source lang=Java>
 +
class Switch extends BoutonSuper
 +
{
 +
  int etat;
 +
  Switch(int posx,int posy,String txt) {
 +
    couleur = 84;
 +
    posX=posx; posY=posy; dX=30; dY=40;
 +
    label = txt;
 +
    etat=0;
 +
  }
 +
  void showOff() {
 +
    fill(couleur);
 +
    rect(posX,posY,dX,dY);
 +
    strokeWeight(2);
 +
    stroke(0);
 +
    line(posX,posY+dY,posX+dX,posY+dY);
 +
    line(posX+dX,posY,posX+dX,posY+dY);
 +
    stroke(255);
 +
    line(posX,posY,posX+dX,posY);
 +
    line(posX,posY,posX+dX,posY);
 +
    strokeWeight(1);
 +
    noStroke();
 +
    textSize(24);
 +
    fill(0,255,0);
 +
    text(label,posX,posY+dY+24);
 +
  }
 +
  void switchEtat() {
 +
    etat ^= 1;
 +
  }
 +
  void showOn() {
 +
    fill(couleur);
 +
    rect(posX,posY,dX,dY);
 +
    fill(0,192,0);
 +
    ellipseMode(CORNER);
 +
    ellipse(posX,posY,dX,dY);
 +
    fill(0,255,0);
 +
    ellipse(posX+5,posY+5,dX-10,dY-10);
 +
  }
 +
  void show() {
 +
    if (etat == 0) showOff(); else showOn();
 +
  }
 +
}
 +
</source>
 +
** et un exemple d'utilisation :
 +
<source lang=Java>
 +
Bouton bouton1 = new Bouton(50,50,"UP");
 +
Switch switch1 = new Switch(150,50,"SW0");
 +
void setup() {
 +
  size(300,300);
 +
  frameRate(10);
 +
}
 +
void draw() {
 +
    bouton1.showOff();
 +
    switch1.show();
 +
}
 +
void mousePressed() {
 +
  if (bouton1.mouseIn()) {
 +
      bouton1.showOn();
 +
    } else if (switch1.mouseIn()) {
 +
      switch1.switchEtat();
 +
    }
 +
}
 +
</source>
 +
 
 +
Poursuivez avec l'exercice 7 du cours ci-dessus qui change seulement l'apparence du bouton.
 +
 
 +
===Corrections de l'exercice 2===
 +
[[Cours:Idees_OOP_corrige|<big>'''Éléments de correction'''</big>]]
 +
 
 +
==Projet Coronavirus==
 +
Suite à l'arrêt complet de l'enseignement le lundi 16 Mars 2020 pour une durée indéterminée, nous vous proposons le travail personnel suivant.
 +
 
 +
Pour ce projet, '''Travail 1''' et '''Travail 2''' ne représentent qu'une promenade de santé. Le vrai travail commence avec '''Travail 3''' et '''Travail 4'''.
 +
===Code de départ===
 +
Voici le code de départ d'un '''jeu snake''' pratiquement fonctionnel mais comportant un certain nombre de défauts. Ce code est tiré du Forum [https://forum.processing.org/two/discussion/4521/realisation-d-un-jeu-snake-en-3d Réalisation d'un jeu snake en 3D] mais il s'agit naturellement d'un jeu 2D.
 +
<source lang=Java>
 +
int colonnes=100;
 +
int lignes=60;
 +
 +
ArrayList<TeteOuCorps> serpent;
 +
 +
int posX=0;
 +
int posY=0;
 +
Pomme pomme;
 +
 +
long  tpbouger=0;
 +
long  tpbouger2=0;
 +
 +
int temps=150;
 +
boolean commencer;
 +
 +
TeteOuCorps TETE ;
 +
TeteOuCorps elmt;
 +
 +
int dir;
 +
String mesag="";
 +
int score=0;
 +
int serpentTaille=2;
 +
int pas=11;
 +
 +
// -----------------------------------------------------------
 +
 +
void setup()
 +
{
 +
  size(1000, 600);
 +
  background(0, 0, 255);
 +
 +
  textAlign(CENTER);
 +
  int posX=width/2;
 +
  int posY=height/2;
 +
 +
  serpent=new ArrayList();
 +
  serpent.add(new TeteOuCorps(posX, posY));
 +
  serpent.add(new TeteOuCorps(posX-1*pas, posY));
 +
  serpent.add(new TeteOuCorps(posX-2*pas, posY));
 +
 +
  AjoutPomme();
 +
  mesag="Pour commencer, cliquez à l'intérieur de la grille.\n\nUtilisez les flèches du clavier pour diriger le serpent.";
 +
 +
  tpbouger=millis();
 +
  tpbouger2=millis();
 +
 +
  DessinerGrille();
 +
 +
  posX=1;
 +
  posY=0;
 +
}
 +
 +
void draw()
 +
{
 +
  background(0, 0, 255);
 +
 +
  if (commencer)
 +
  {
 +
    DessinerGrille();
 +
    pomme.draw();
 +
    DeplacerEtManger();
 +
  }
 +
  else
 +
  {
 +
    text(mesag, 500, 100);
 +
  }
 +
}
 +
 +
// -------------------------------------------------------------------
 +
 +
void DeplacerEtManger()
 +
{
 +
 +
  //  TeteOuCorps elmt2 = serpent.get(serpent.size()-1);
 +
  //  if ((elmt2.x<0)||(elmt2.x>=colonnes)||(elmt2.y<0)||(elmt2.y>=lignes))
 +
  //  {
 +
  //    serpent.clear(); // on vide le tableau
 +
  //    posX = colonnes/2; // et on repositionne la tête du serpent au centre
 +
  //    posY = lignes/2;
 +
  //
 +
  //    temps = 250; // on remet le temps à 250
 +
  //  }
 +
 +
  println  (serpent.size());
 +
 +
 +
  for (int i = serpent.size()-1; i >= 0; i--)
 +
  {
 +
    TeteOuCorps elmt = serpent.get(i);
 +
    elmt.draw();
 +
    //      if (elmt.touche(posX, posY))
 +
    //      {
 +
    //        // serpent.clear(); // on vide le tableau
 +
    //        posX = colonnes/2; // on repositionne le serpent au centre
 +
    //        posY = lignes/2;
 +
    //
 +
    //        temps = 250; // on remet le tempsàa 250
 +
    //        break; //  sortir prématurement de la boucle
 +
    //      }
 +
  } // for
 +
 +
  TeteOuCorps elmt = serpent.get(0);
 +
  if (pomme.touche(elmt.x, elmt.y))
 +
  {
 +
    score ++;        // un point de plus
 +
    serpentTaille ++; // une taille en plus
 +
    temps -=1;        // on accelere la cadence
 +
 +
 +
    //obtenir les deux dernier elmt
 +
    TeteOuCorps elmt2 = serpent.get(serpent.size()-1);
 +
    serpent.add(new TeteOuCorps(elmt2.x-2*pas, elmt2.y));
 +
 +
    AjoutPomme();
 +
  }
 +
 +
  // move
 +
  if (tpbouger2+400 < millis()) {
 +
 +
    if (posX!=0||posY!=0) {
 +
      for (int i = serpent.size()-1; i > 0; i--) {
 +
        elmt = serpent.get(i);
 +
        TeteOuCorps elmt2 = serpent.get(i-1);
 +
        elmt.x = elmt2.x;
 +
        elmt.y = elmt2.y;
 +
      } // for
 +
    } // if
 +
 +
    elmt  =  serpent.get(0);
 +
    elmt.x += posX * pas;
 +
    elmt.y += posY * pas;
 +
 +
    tpbouger2 = millis();
 +
  } // if
 +
 +
  //score
 +
  fill(255, 0, 0);
 +
 +
  textAlign(LEFT);
 +
  text("Score : ", width -120, 25);
 +
  text(score, width -50, 25);
 +
} // func
 +
 +
void keyPressed()
 +
{
 +
  // reset
 +
  posX=0;
 +
  posY=0;
 +
  // get key
 +
  if (key==CODED)
 +
  {
 +
    if (keyCode==UP)
 +
    {
 +
      dir=1;
 +
    }
 +
    if (keyCode==DOWN)
 +
    {
 +
      dir=2;
 +
    }
 +
    if (keyCode==RIGHT)
 +
    {
 +
      dir=3;
 +
    }
 +
    if (keyCode==LEFT)
 +
    {
 +
      dir=4;
 +
    }
 +
    // on determine la position de la tête en fonction de la direction du serpent
 +
    switch(dir)
 +
    {
 +
    case 1:
 +
      posY=-1;
 +
      break;
 +
    case 2:
 +
      posY=1;
 +
      break;
 +
    case 3:
 +
      posX=1;
 +
      break;
 +
    case 4:
 +
      posX=-1;
 +
      break;
 +
    }
 +
  }
 +
}
 +
 +
void DessinerGrille()
 +
{
 +
  background(0, 0, 255);
 +
  stroke(255);
 +
  for (int x =0; x < width; x+=10) {
 +
    line(x, 0, x, height);
 +
  }
 +
  for (int y =0; y < height; y+=10) {
 +
    line(0, y, width, y);
 +
  }
 +
}
 +
 +
void AjoutPomme()
 +
{
 +
  pomme=new Pomme(pas/2*(int)random(colonnes), pas/2*(int)random(lignes));
 +
}
 +
 +
void mousePressed()
 +
{
 +
  mesag="";
 +
  commencer=true;
 +
}
 +
 +
// ==========================================================
 +
 +
class Pomme {
 +
  int x; // position x
 +
  int y; // et y
 +
  //
 +
  // le constructeur de la classe
 +
  Pomme(int x_, int y_)
 +
  {
 +
    x=x_;
 +
    y=y_;
 +
  }
 +
 +
  void draw() {
 +
    // draw
 +
    fill(0, 255, 0);
 +
    noStroke();
 +
 +
    ellipse(x, y, 10, 10);
 +
  }
 +
 +
  Boolean touche(int a, int b) {
 +
    // return ((a==x)&&(b==y));
 +
    return dist(a, b, x, y)<20;
 +
  }
 +
} //class
 +
// ==========================================================
 +
class TeteOuCorps
 +
{
 +
  int x;
 +
  int y;
 +
 +
  //le constructeur de la class TeteOuCorps
 +
  TeteOuCorps(int x_, int y_)
 +
  {
 +
    x=x_;
 +
    y=y_;
 +
  } // constr
 +
 +
  void draw () {
 +
    // draw
 +
    fill(255, 0, 0);
 +
    noStroke();
 +
    ellipseMode(CENTER);
 +
    ellipse(x, y, 20, 20);
 +
  }
 +
 +
  Boolean touche(int a, int b) {
 +
    return false;
 +
    // return (((a==x)&&(b==(y+5)))||(a==x&&(b==(y-5)))||((a==(x+5)&&(b==y)))||((a==(x-5)&&(b==y))));
 +
  }
 +
} // class
 +
// =========================================================
 +
</source>
 +
 
 +
Votre travail va consister à modifier ce code. Il vous faudra réaliser un compte-rendu au fur et à mesure de l'avancement de votre travail et l'envoyer à mon adresse mail "serge.moutou at univ-reims".
 +
 
 +
===Travail 1===
 +
Dessiner (sur une feuille de papier) en utilisant la technique présentée dans les documents fournis en cours les classes utilisées dans ce code en précisant leurs attributs et méthodes.
 +
 
 +
Si vous avez perdu vos documents, nous les avons ajouté en cours 6 du document [https://moutou.pagesperso-orange.fr/CoursProcessing.pdf Processing de mon site perso].
 +
 
 +
====Remarque====
 +
Il est très possible que ce code :
 +
 
 +
<source lang=Java>
 +
ArrayList<TeteOuCorps> serpent;
 +
</source>
 +
 
 +
vous pose des problèmes de compréhension. L'interprétation de cette ligne est :
 +
* serpent est une variable de type ArrayList
 +
* une ArrayList est quelque chose qui ressemble à un tableau mais sa taille n'est pas forcément déclarée au départ
 +
** par contre l'ajout d'une case au tableau se fait par  serpent.add();
 +
* <TeteOuCorps> veut dire deux choses :
 +
** une classe nommée "TeteOuCorps" apparaîtra plus loin dans votre code
 +
** chacune des cases du tableau contient un objet qui est du type de cette classe "TeteOuCorps".
 +
*L’accès à une case du tableau se fait par "serpent.get(i)" où i est l'index de la case.
 +
 
 +
===Travail 2===
 +
On vous demande d'organiser le code de manière un peu plus traditionnelle avec le code principal d'un côté dans lequel on ajoutera deux onglets (un par classe).
 +
 
 +
Nous vous rappelons que le nom des onglets doit forcément être celui de la classe.
 +
 
 +
'''Il n'y a aucune modification de code à ce stade, seulement quelques couper/coller pour remplir les onglets !!!'''
 +
 
 +
===Travail 3===
 +
Vous devez à tout prix personnaliser ce jeu d'une manière ou d'une autre :
 +
* diminuer la taille du jeu (ou pas)
 +
* éventuellement afficher le score en dehors de l'aire de jeu pour une plus grande lisibilité
 +
* afficher votre nom en dehors de l'aire de jeu.
 +
* changer les couleurs
 +
 
 +
<big>'''La personnalisation sera pour moi la seule manière de distinguer le travail des uns et des autres : éviter trop d'échanges de code entre vous. Il n'est pas interdit d'échanger entre vous des idées mais recopier le code d'un autre NON.'''</big>
 +
 
 +
<big>{{Rouge|A ce stade aucun des projets ne doit se ressembler : }}
 +
 
 +
{{Rouge| * ni par les couleurs}}
 +
 
 +
{{Rouge| * ni par la taille de jeu}}
 +
 
 +
{{Rouge| * ni par vos noms qui doivent apparaître quelque part}}
 +
 
 +
{{Rouge| * ni par l'affichage du score}}
 +
</big>
 +
 
 +
===Travail 4===
 +
Maintenant vous allez améliorer le code pour résoudre un certain nombre de problèmes :
 +
*le serpent mange la pomme alors qu'il est encore un peu loin
 +
*l'ajout d'une ellipse quand le serpent mange la pomme doit être amélioré elle est mal positionnée parfois même si cela ne dure pas très longtemps
 +
*ajout de la possibilité de perdre et donc de remettre le score à 0 si
 +
**le serpent sort de l'aire de jeu
 +
**le serpent se traverse lui-même
 +
*apparition de temps en temps de "pomme bonus" qui sont d'une autre couleur et comptent plus de points
 +
 
 +
<big>'''Je ne veux pas retrouver des choses trop avancées venant du forum originel [https://forum.processing.org/two/discussion/4521/realisation-d-un-jeu-snake-en-3d Réalisation d'un jeu snake en 3D] comme des menus par exemple !!!! Restez modeste, vous êtes sensés ne passer que 12 heures sur ce projet.
 +
'''</big>
 +
 
 +
==TD : Visualisation des données d'un accéléromètre==
 +
Notre but est d'utiliser la programmation objet pour réaliser une visualisation 3D des données venant d'un Gyroscope/Accéléromètre/Magnétomètre.
 +
 
 +
===Code de départ===
 +
Voici un code complet capable de visualiser les données provenant d'un Arduino couplé avec un MPU9250.
 +
 
 +
====La classe Solid====
 +
On rappelle que traditionnellement ce code est mis dans un onglet spécifique qui porte le nom de la classe.
 +
<source lang=Java>
 +
class Solid {
 +
  // attributs de position
 +
  int posX, posY;
 +
  // angles d'Euler
 +
  float angleX, angleY, angleZ;
 +
  // couleurs
 +
  int red, green, blue;
 +
  // constructeurs
 +
  Solid() {
 +
    angleX=angleY=angleZ=0;
 +
    posX=width/2;
 +
    posY=height/2;
 +
  }
 +
  // angles en degrés
 +
  Solid(int posx,int posy,float anglex,float angley,float anglez){
 +
    posX=posx;
 +
    posY=posy;
 +
    //posZ=-50;
 +
    angleX=anglex;
 +
    angleY=angley;
 +
    angleZ=anglez;
 +
  }
 +
  // methodes
 +
  void setColor(int rouge,int vert,int bleu){
 +
    red=rouge;
 +
    green=vert;
 +
    bleu=blue;
 +
  }
 +
  void upDateAngles(float anglex,float angley,float anglez) {
 +
    angleX = anglex;
 +
    angleY = angley;
 +
    angleZ = anglez;
 +
  }
 +
  void draw_Solid() {
 +
    //Show angles data
 +
    pushMatrix();
 +
   
 +
    translate(posX, posY, -50);
 +
    // dans le repère de l'écran pour Euler123 de l'accéléromètre
 +
    rotateX(radians(-angleX-90));
 +
    rotateZ(radians(-angleZ));
 +
    rotateY(radians(-angleY));
 +
   
 +
    scale(90);
 +
    beginShape(QUADS);
 +
 
 +
    fill(red, green, blue);
 +
    vertex(-1, 1.5, 0.25);
 +
    vertex( 1, 1.5, 0.25);
 +
    vertex( 1, -1.5, 0.25);
 +
    vertex(-1, -1.5, 0.25);
 +
 
 +
    vertex( 1, 1.5, 0.25);
 +
    vertex( 1, 1.5, -0.25);
 +
    vertex( 1, -1.5, -0.25);
 +
    vertex( 1, -1.5, 0.25);
 +
 
 +
    vertex( 1, 1.5, -0.25);
 +
    vertex(-1, 1.5, -0.25);
 +
    vertex(-1, -1.5, -0.25);
 +
    vertex( 1, -1.5, -0.25);
 +
 
 +
    vertex(-1, 1.5, -0.25);
 +
    vertex(-1, 1.5, 0.25);
 +
    vertex(-1, -1.5, 0.25);
 +
    vertex(-1, -1.5, -0.25);
 +
 
 +
    vertex(-1, 1.5, -0.25);
 +
    vertex( 1, 1.5, -0.25);
 +
    vertex( 1, 1.5, 0.25);
 +
    vertex(-1, 1.5, 0.25);
 +
 
 +
    vertex(-1, -1.5, -0.25);
 +
    vertex( 1, -1.5, -0.25);
 +
    vertex( 1, -1.5, 0.25);
 +
    vertex(-1, -1.5, 0.25);
 +
 
 +
    endShape();
 +
    popMatrix();
 +
  }
 +
}
 +
</source>
 +
 
 +
====Le code principal====
 +
Le code donné ci-dessous gère une liaison série pour recevoir des données d'un Arduino couplé à un MPU9250. Le code Arduino sera donné un peu plus loin.
 +
 
 +
Cette liaison série est capable d'analyser des donnée séparées par des marqueurs. Nous la laisson telle quelle pour le moment.
 +
<source lang=Java>
 +
import processing.serial.*;
 +
 
 +
Serial  myPort;
 +
short  portIndex = 1;
 +
int    lf = 10;      //ASCII linefeed
 +
String  inString;      //String for testing serial communication
 +
int    calibrating;
 +
 +
float  dt;
 +
float  x_gyr;  //Gyroscope data
 +
float  y_gyr;
 +
float  z_gyr;
 +
float  x_acc;  //Accelerometer data
 +
float  y_acc;
 +
float  z_acc;
 +
float  x_fil;  //Filtered data
 +
float  y_fil;
 +
float  z_fil;
 +
 
 +
Solid solide;
 +
 +
void setup()  {
 +
//  size(640, 360, P3D);
 +
  size(1400, 800, P3D);
 +
  noStroke();
 +
  colorMode(RGB, 256);
 +
  solide = new Solid(width/2,height/2,0,0,0);
 +
//  println("in setup");
 +
//  String portName = Serial.list()[portIndex];
 +
  String portName = "/dev/ttyACM0";
 +
//  println(Serial.list());
 +
//  println(" Connecting to -> " + Serial.list()[portIndex]);
 +
  myPort = new Serial(this, portName, 38400);
 +
  myPort.clear();
 +
  myPort.bufferUntil(lf);
 +
}
 +
 
 +
void draw()  {
 +
 
 +
  background(0);
 +
  lights();
 +
 
 +
  solide.setColor(56, 140, 206);
 +
  solide.draw_Solid();
 +
}
 +
 
 +
void serialEvent(Serial p) {
 +
 
 +
  inString = (myPort.readString());
 +
 
 +
  try {
 +
    // Parse the data
 +
    String[] dataStrings = split(inString, '#');
 +
    for (int i = 0; i < dataStrings.length; i++) {
 +
      String type = dataStrings[i].substring(0, 4);
 +
      String dataval = dataStrings[i].substring(4);
 +
      if (type.equals("DEL:")) {
 +
        dt = float(dataval);
 +
      } else if (type.equals("ACC:")) {
 +
        String data[] = split(dataval, ',');
 +
        x_acc = float(data[0]);
 +
        y_acc = float(data[1]);
 +
        z_acc = float(data[2]);
 +
      } else if (type.equals("GYR:")) {
 +
        String data[] = split(dataval, ',');
 +
        x_gyr = float(data[0]);
 +
        y_gyr = float(data[1]);
 +
        z_gyr = float(data[2]);
 +
      } else if (type.equals("FIL:")) {
 +
        String data[] = split(dataval, ',');
 +
        x_fil = float(data[0]);
 +
        y_fil = float(data[1]);
 +
        z_fil = float(data[2]);
 +
      }
 +
    }
 +
    solide.upDateAngles(x_acc,y_acc,z_acc);
 +
  } catch (Exception e) {
 +
      println("Caught Exception");
 +
  }
 +
}
 +
</source>
 +
====Le code Arduino====
 +
Le code Arduino est disponible dans [https://fr.wikiversity.org/wiki/Micro_contr%C3%B4leurs_AVR/Travail_pratique/Utilisation_du_MPU9250#Application_6_:_fusion_de_donn%C3%A9es_par_filtre_compl%C3%A9mentaire la Wikiversité ICI : Application 6 : fusion de données par filtre complémentaire]. On ne vous demande pas de comprendre ce code dans le détail.
 +
 
 +
====Exercice 4====
 +
Faire fonctionner correctement cet ensemble de code.
 +
 
 +
Le moins que l'on puisse dire c'est que la visualisation fonctionne correctement mais avec un accéléromètre un peu poussif. Ce code ne pourra donc n'être utilisé pour un jeu vidéo que dans certains cas. Nous allons donc essayer de l'améliorer.
  
[[Media:Reveil_12.zip|Correction complète]]
+
====Exercice 5====
 +
Nous allons utiliser le processeur DMP (Data Movement Processor) du MPU9250. Ceci fonctionne très bien si on installe la librairie qui va bien [https://fr.wikiversity.org/wiki/Micro_contr%C3%B4leurs_AVR/Travail_pratique/Utilisation_du_MPU9250#Utilisation_du_DMP_(Digital_Motions_Processor) comme expliqué ICI].
  
===Exercice3===
+
#Installer la bibliothèque de Jeff Rowberg en faisant fonctionner l'exemple de la librairie
Caractères matriciel et affichage LCD.
+
#Modifier le code de l'exemple pour être compatible avec notre logiciel de visualisation
 +
#Faire fonctionner correctement l'ensemble
 +
 
 +
====Exercice 6====
 +
Vous allez modifier le code de visualisation pour réaliser un jeu vidéo de votre choix.
 +
 
 +
Il ne s'agit pas pour vous de trouver un jeu tout fait mais de l'adapter à votre problématique. S'il n'est pas en '''POO''' (Programmation Orientée Objet) vous le modifierez pour qu'il contienne au moins une classe.
 +
 
 +
Si vous manquez d'idée, cela peut être :
 +
* un Pong avec le mouvement de la raquette réalisé par l'accéléromètre. Vous pouvez vous aider de [https://documentation.labboite.fr/xwiki/bin/view/3%20-%20Projets/Jeux/Cr%C3%A9er%20un%20Pong%20avec%20Processing/ Créer un Pong avec Processing]
 +
* un plateau horizontal avec des trous et des billes à mettre dans les trous. La modification de la position de l'accéléromètre permettra de faire bouger correctement les billes avec comme objectif de les mettre chacune dans un trou.
 +
* voyage galactique ... avec des obstacles à éviter...
 +
* [https://forum.processing.org/two/discussion/4521/realisation-d-un-jeu-snake-en-3d Réalisation d'un jeu snake en 3D]
 +
*[https://www.openprocessing.org/curation/25/ Ensemble de jeux ici]
  
 
==TP programmation Objet==
 
==TP programmation Objet==
Ligne 843 : Ligne 1 461 :
  
 
===Travail à réaliser===
 
===Travail à réaliser===
# Pour éviter de travailler avec de l'héritage, vous allez définir 4 types de touches : 3 blanches et 1 noire. Par défaut ces touches seront considérées comme dessinées en coordonnée (0,0) en haut à gauche. Le constructeur devra contenir la définition du type de touche qui déterminera complètement le graphisme de la touche.
+
# Pour éviter de travailler avec de l'héritage, vous allez définir 4 types de touches : 3 blanches et 1 noire. Par défaut ces touches seront considérées comme dessinées en coordonnée (0,0) en haut à gauche. Le constructeur devra contenir la définition du type de touche qui déterminera complètement le graphisme de la touche. Pévoir aussi une couleur pour touche non appuyée (blanc ou noir) et une couleur pour touche appuyée.
# Décomposer chacune des touches blanches en deux rectangles dont on déterminera les coordonnées à partir de l'exemple donné. Évidemment, au moment du dessin il ne faudra pas dessiner de bords aux rectangles sauf sur le côté gauche et le côté droit ([https://processing.org/reference/line_.html line]).  
+
# Décomposer chacune des touches blanches en deux rectangles dont on déterminera les coordonnées à partir de l'exemple donné. Évidemment, au moment du dessin il ne faudra pas dessiner de bords aux rectangles sauf sur le côté gauche et le côté droit ([https://processing.org/reference/line_.html line] et le [https://processing.org/reference/stroke_.html stroke] associé).  
# Traite le cas des touches noires
+
# Traiter le cas des touches noires
 
# Décider de la taille et de la forme la zone dans laquelle il faudra appuyer pour considérer un appui de touche. La mise en place de cette zone sera faite par le constructeur en fonction du type de touche.
 
# Décider de la taille et de la forme la zone dans laquelle il faudra appuyer pour considérer un appui de touche. La mise en place de cette zone sera faite par le constructeur en fonction du type de touche.
 
# A jouter une possibilité de transfert vers la droite pour chacun des types de touche
 
# A jouter une possibilité de transfert vers la droite pour chacun des types de touche
# Gérer la mise de l'ensemble des touches dans un tableau
+
# Gérer la mise de l'ensemble des touches dans un tableau ([http://www.ecole-art-aix.fr/processing-13-Listes Les listes (ou tableaux)])
 
# Tester avec des [https://processing.org/reference/print_.html print]  et/ou des [https://processing.org/reference/println_.html println]  
 
# Tester avec des [https://processing.org/reference/print_.html print]  et/ou des [https://processing.org/reference/println_.html println]  
 
# Gérer la liaison série ([https://processing.org/reference/libraries/serial/Serial.html Serial]) en lieu et place de l'affichage dans la console processing.
 
# Gérer la liaison série ([https://processing.org/reference/libraries/serial/Serial.html Serial]) en lieu et place de l'affichage dans la console processing.
 +
===Correction partielle sans liaison série===
 +
 +
<source lang=Java>
 +
class ClassPianoKey
 +
{
 +
  int _note;
 +
  int _type; // type d la touche
 +
  int couleurOff, couleurOn; // noir, blanc ou  gris
 +
  int offsetX;
 +
  int clickAreaPosX,clickAreaPosY,clickAreaDX,clickAreaDY;
 +
 
 +
ClassPianoKey(int deltaX,int type,int note) {
 +
    _note = note;
 +
    _type = type;
 +
    offsetX = deltaX;
 +
    if (type < 4) { // touche blanche
 +
      couleurOff = 255;
 +
      couleurOn = 200;
 +
      clickAreaPosX=offsetX;
 +
      clickAreaPosY = 250;
 +
      clickAreaDX= 50;
 +
      clickAreaDY = 150;
 +
    } else {
 +
      couleurOff = 0;
 +
      couleurOn = 50;
 +
      clickAreaPosX=offsetX;
 +
      clickAreaPosY = 0;
 +
      clickAreaDX= 30;
 +
      clickAreaDY = 250;
 +
    }
 +
   
 +
  }
 +
 +
  void showOff() {
 +
    if (_type == 1) {
 +
      fill(couleurOff);
 +
      stroke(couleurOff);
 +
      rect(0+offsetX,0,35,250);
 +
      rect(0+offsetX,250,50,150);
 +
      // black
 +
      stroke(0);
 +
      line(0+offsetX,0,0+offsetX,400);
 +
      line(0+offsetX+50,0+250,0+offsetX+50,400);
 +
    }
 +
    if (_type == 2) {
 +
      fill(couleurOff);
 +
      stroke(couleurOff);
 +
      rect(0+offsetX+15,0,35,250);
 +
      rect(0+offsetX,250,50,150);
 +
      stroke(0);
 +
      line(0+offsetX,0+250,0+offsetX,400);
 +
      line(0+offsetX+50,0,0+offsetX+50,400);
 +
    }
 +
    if (_type == 3) {
 +
      fill(couleurOff);
 +
      stroke(couleurOff);
 +
      rect(0+offsetX+15,0,20,250);
 +
      rect(0+offsetX,250,50,150);
 +
      stroke(0);
 +
      line(0+offsetX,0+250,0+offsetX,400);
 +
      line(0+offsetX+50,0+250,0+offsetX+50,400);
 +
    }
 +
    if (_type == 4) {
 +
      fill(couleurOff);
 +
      stroke(couleurOff);
 +
      rect(0+offsetX,0,30,250);     
 +
    }
 +
   
 +
  }
 +
 +
  void showOn() {
 +
    if (_type == 1) {
 +
      fill(couleurOn);
 +
      stroke(couleurOn);
 +
      rect(0+offsetX,0,35,250);
 +
      rect(0+offsetX,250,50,150);
 +
      // black
 +
      stroke(0);
 +
      line(0+offsetX,0,0+offsetX,400);
 +
      line(0+offsetX+50,0+250,0+offsetX+50,400);
 +
    }
 +
    if (_type == 2) {
 +
      fill(couleurOn);
 +
      stroke(couleurOn);
 +
      rect(0+offsetX+15,0,35,250);
 +
      rect(0+offsetX,250,50,150);
 +
      stroke(0);
 +
      line(0+offsetX,0+250,0+offsetX,400);
 +
      line(0+offsetX+50,0,0+offsetX+50,400);
 +
    }
 +
    if (_type == 3) {
 +
      fill(couleurOn);
 +
      stroke(couleurOn);
 +
      rect(0+offsetX+15,0,20,250);
 +
      rect(0+offsetX,250,50,150);
 +
      stroke(0);
 +
      line(0+offsetX,0+250,0+offsetX,400);
 +
      line(0+offsetX+50,0+250,0+offsetX+50,400);
 +
    }
 +
    if (_type == 4) {
 +
      fill(couleurOn);
 +
      stroke(couleurOn);
 +
      rect(0+offsetX,0,30,250);     
 +
    }
 +
   
 +
  }
 +
 
 +
  Boolean mouseIn() {
 +
    if ((mouseX>clickAreaPosX) && (mouseX < clickAreaPosX+clickAreaDX)
 +
      && (mouseY>clickAreaPosY) && (mouseY < clickAreaPosY+clickAreaDY))
 +
        return true;
 +
    else return false;
 +
  }
 +
 
 +
}
 +
</source>
 +
 +
Et enfin le programme principal :
 +
 +
<source lang=Java>
 +
ClassPianoKey[] pianokeys = new ClassPianoKey[15];
 +
 +
void setup() {
 +
  size(400,400);
 +
  frameRate(1);
 +
  pianokeys[0]= new ClassPianoKey(0,1,1);  //do
 +
  pianokeys[1]= new ClassPianoKey(35,4,2);  //do#
 +
  pianokeys[2]= new ClassPianoKey(50,3,3);  //re
 +
  pianokeys[3]= new ClassPianoKey(85,4,4);
 +
  pianokeys[4]= new ClassPianoKey(100,2,5);
 +
  pianokeys[5]= new ClassPianoKey(150,1,6);
 +
  pianokeys[6]= new ClassPianoKey(185,4,7);
 +
  pianokeys[7]= new ClassPianoKey(200,3,8);
 +
  pianokeys[8]= new ClassPianoKey(235,4,9);
 +
  pianokeys[9]= new ClassPianoKey(250,3,10);
 +
  pianokeys[10]= new ClassPianoKey(235,4,11);
 +
  pianokeys[11]= new ClassPianoKey(250,3,12);
 +
  pianokeys[12]= new ClassPianoKey(285,4,13);
 +
  pianokeys[13]= new ClassPianoKey(300,2,14);
 +
  pianokeys[14]= new ClassPianoKey(350,1,15);
 +
  for (int i=0;i<15;i++) {
 +
    pianokeys[i].showOff();
 +
  }
 +
}
 +
 +
void draw() {
 +
 
 +
}
 +
 +
void mousePressed() {
 +
  for (int i=0;i<15;i++) {
 +
    if (pianokeys[i].mouseIn())
 +
      pianokeys[i].showOn();
 +
  } 
 +
}
 +
 +
void mouseReleased() {
 +
  for (int i=0;i<15;i++) {
 +
    if (pianokeys[i].mouseIn())
 +
      pianokeys[i].showOff();
 +
  } 
 +
}
 +
</source>
 +
 +
Malheureusement  l'ensemble est un peu lent pour être utilisé pour réaliser de la musique !!!
  
 
==Voir aussi==
 
==Voir aussi==

Version actuelle datée du 25 mars 2020 à 10:08

Introduction aux objets avec Processing

Programmation orientée-objet (version sympathique) peut être lue en guise de cours.

Exercice 1

Refaire les exemples développés dans la Playlist Youtube de Daniel Shiffman. On commencera par la classe Bubble développée dans le troisième cours.

Préparation à l'exercice suivant

Processing : Les Objets peut être consulté pour un rappel sur les objets. Nous allons continuer avec les tableaux ou listes.

Les listes (ou tableaux) vous propose des tableaux sur types simples (ou presque).

Pour aller plus loin, les listes d'objets sont abordées avec « Programmation orientée-objet (version sympathique) » en y cherchant la section Liste d'objets.

Array Objects montre une autre syntaxe pour les boucles for.

Exercice 2

Question 1

Transformer le code ci-dessous en une classe Processing pour utilisation.

Indications : on vous donne le code permettant un affichage d'un seul digit

int[] val={63,6,91,79,102,109,125,7,127,111,119,124,57,94,121,113};

void segment() {
  beginShape();
  vertex(0,10);
  vertex(10,0);
  vertex(50,0);
  vertex(60,10);
  vertex(50,20);
  vertex(10,20);
 endShape(CLOSE); 
}

void affiche7segs(int val,int rouge,int vert, int bleu) {
  pushMatrix(); // on désire laisser le repère inchangé
  noStroke();
  translate(40,0);
  if ((val & 1) == 1) fill(rouge,vert,bleu); else fill(200);
  segment(); // segment a
  translate(-10,70);
  if ((val & 64) == 64) fill(rouge,vert,bleu); else fill(200);
  segment(); // segment g
  translate(-10,70);
  if ((val & 8) == 8) fill(rouge,vert,bleu); else fill(200);
  segment(); // segment d
  translate(15,-53);
  rotate(radians(100));
  if ((val & 16) == 16) fill(rouge,vert,bleu); else fill(200);
  segment(); // segment e
  translate(-70,0);
  if ((val & 32) == 32) fill(rouge,vert,bleu); else fill(200);
  segment(); // segtment f
  translate(-12,-68);
  if ((val & 2) == 2) fill(rouge,vert,bleu); else fill(200);
  segment(); // segment b
  translate(72,0);
  if ((val & 4) == 4) fill(rouge,vert,bleu); else fill(200);
  segment(); // segment c
  popMatrix(); // on récupère le repère initial
}

Réponse à la question 1 (Exercice 2)

Voici la définition de classe qui est un peu différente de celle présentée en cours.

 
class Digit {
   private int[] val={63,6,91,79,102,109,125,7,127,111,119,124,57,94,121,113};
   int nb1digit;
   int x,y;
   Digit(){
     nb1digit = val[0];
     x=0;y=0;
   }
   Digit(int nb){
     x=0;y=0;
     if (nb < 16)
       nb1digit = val[nb];
     else
       nb1digit=64; // affichage tiret en cas d'erreur
   }
   
   Digit(int xd, int yd){
     nb1digit = val[0];
     x=xd;y=yd;
   }
   
   void put(int nb) {
     if (nb < 16)
       nb1digit = val[nb];
     else
       nb1digit=64; // affichage tiret en cas d'erreur
   }

  private void segment() {
    beginShape();
    vertex(0,10);
    vertex(10,0);
    vertex(50,0);
    vertex(60,10);
    vertex(50,20);
    vertex(10,20);
   endShape(CLOSE); 
  }

void affiche7segs(int rouge,int vert, int bleu) {
  pushMatrix(); // on désire laisser le repère inchangé
  noStroke();
  translate(40+x,0+y);
  if ((nb1digit & 1) == 1) fill(rouge,vert,bleu); else fill(200);
  segment(); // segment a
  translate(-10,70);
  if ((nb1digit & 64) == 64) fill(rouge,vert,bleu); else fill(200);
  segment(); // segment g
  translate(-10,70);
  if ((nb1digit & 8) == 8) fill(rouge,vert,bleu); else fill(200);
  segment(); // segment d
  translate(15,-53);
  rotate(radians(100));
  if ((nb1digit & 16) == 16) fill(rouge,vert,bleu); else fill(200);
  segment(); // segment e
  translate(-70,0);
  if ((nb1digit & 32) == 32) fill(rouge,vert,bleu); else fill(200);
  segment(); // segtment f
  translate(-12,-68);
  if ((nb1digit & 2) == 2) fill(rouge,vert,bleu); else fill(200);
  segment(); // segment b
  translate(72,0);
  if ((nb1digit & 4) == 4) fill(rouge,vert,bleu); else fill(200);
  segment(); // segment c
  popMatrix(); // on récupère le repère initial
}

}

Et voici maintenant un exemple de programme d'utilisation :

Digit digitpoids0;

void setup() {  
  digitpoids0 = new Digit(50,50);
  frameRate(1); 
  size(480, 400);
}

int i=0;

void draw() {  
  i = (++i %16);
  digitpoids0.put(i);
  digitpoids0.affiche7segs(255,0,0);
}

FIN DE LA CORRECTION de la question 1

Question 2

Faire fonctionner la correction de la question 1. Puis réaliser un affichage de compteur binaire sur deux digits.

Correction de la question 2

La classe digit est inchangée par rapport à la question 1. On ne donne donc que le programme principal.

Digit digitpoids0,digitpoids1;

void setup() {  
  digitpoids0 = new Digit(150,50);
  digitpoids1 = new Digit(50,50);
  frameRate(1); 
  size(480, 400);
}

int i=0;

void draw() {  
  i++;
  digitpoids0.put(i%16);
  digitpoids0.affiche7segs(255,0,0);
  digitpoids1.put((i/16)%16);
  digitpoids1.affiche7segs(255,0,0);
}

Question 3

Réaliser un affichage de 4 digits destiné à afficher l'heure et les minutes d'un réveil. A ce stade, on ne vous demande pas de réaliser un compteur heures/minutes. En effet l'arithmétique heures/minutes est très particulière et on vous donnera de l'aide pour la réaliser. Vous pouvez par contre réaliser un compteur décimal qui affichera donc sur 4 digits.

Question 4

Modifier la classe pour pouvoir changer la taille de chaque digit (!!! ANNULE !!!)

Question 5

Réaliser une classe "HHMMClass" de 2x2 digits séparés par deux points.

Indication : voici le début de la classe. Il ne vous reste qu'à positionner les ':' et probablement être capable de positionner cet ensemble de digits si vous voulez un jour afficher l'heure courante et l'heure réveil.

class HHMMClass {
  int posX,posY;
  int hh_mm;
  Digit[] digits = new Digit[4];
  HHMMClass() {
    posX=posY=0;
    hh_mm = 0x2340;
    for(int i=0;i<4;i++)
      digits[i]=new Digit(100*i,50);
  }
  void affiche() {
    for(int i=0;i<4;i++) {
      digits[3-i].put(hh_mm >> (4*i) & 0xF);
      digits[3-i].affiche7segs(255,0,0);
    }
  }
  void incrementHHMM() {
      (hh_mm)++;
      if ((hh_mm & 0x000F) > 0x0009)
        hh_mm += 0x0006;
      if ((hh_mm & 0x00F0) > 0x0050)
        hh_mm += 0x00A0;
      if ((hh_mm & 0x0F00) > 0x0900)
        hh_mm += 0x0600;
      if ((hh_mm & 0xFF00) > 0x2300)
        hh_mm = 0x0000;
  }
  void decrementHHMM() {
      (hh_mm)--;
      if ((hh_mm & 0x000F) == 0x000F)
      hh_mm -= 0x0006;
      if ((hh_mm & 0x00F0) == 0x00F0)
      hh_mm -= 0x00A0;
      if ((hh_mm & 0x0F00) == 0x0F00)
      hh_mm -= 0x0600;
      if ((hh_mm & 0xFFFF) > 0x2359)
      hh_mm = 0x2359;
  }
}

Faire vos propres essais avant de passer à la question suivante. L'utilisation de cette classe nécessite l'utilisation de la classe digit avec laquelle elle possède un lien fort.

Question 6

Utiliser cette classe pour afficher l'heure courante. On utilisera

Le code d'une horloge à aiguilles est disponible sur Internet.

Correction question 6

Voici la nouvelle classe HHMMClass :

class HHMMClass {
  int posX,posY;
  int hh_mm;
  Digit[] digits = new Digit[4];
  HHMMClass() {
    posX=posY=0;
    hh_mm = 0x950;
    for(int i=0;i<4;i++) {
      if (i < 2)
        digits[i]=new Digit(100*i,50);
      else
        digits[i]=new Digit(100*(i+1),50);
    }
  }
  void affiche() {
    for(int i=0;i<4;i++) {
      digits[3-i].put(hh_mm >> (4*i) & 0xF);
      digits[3-i].affiche7segs(255,0,0);
    }
    if ((second() % 2) == 1)
      fill(255,0,0);
    else 
      fill(200);
      
    ellipse(260,100,20,20);
    ellipse(255,150,20,20);
  }
  
  void updateHHMM() {
    int temp;
    temp = hour();
    hh_mm = ((temp/10) << 12)+((temp%10)<<8);
    temp = minute();
    hh_mm += ((temp/10) << 4)+(temp%10);
  }
  void incrementHHMM() {
      (hh_mm)++;
      if ((hh_mm & 0x000F) > 0x0009)
        hh_mm += 0x0006;
      if ((hh_mm & 0x00F0) > 0x0050)
        hh_mm += 0x00A0;
      if ((hh_mm & 0x0F00) > 0x0900)
        hh_mm += 0x0600;
      if ((hh_mm & 0xFF00) > 0x2300)
        hh_mm = 0x0000;
  }
  void decrementHHMM() {
      (hh_mm)--;
      if ((hh_mm & 0x000F) == 0x000F)
      hh_mm -= 0x0006;
      if ((hh_mm & 0x00F0) == 0x00F0)
      hh_mm -= 0x00A0;
      if ((hh_mm & 0x0F00) == 0x0F00)
      hh_mm -= 0x0600;
      if ((hh_mm & 0xFFFF) > 0x2359)
      hh_mm = 0x2359;
  }
}

Il serait bon de modifier la méthode affiche() pour qu'elle puisse changer la couleur d'affichage.

La classe Digit n'a pas changée.

Et voici maintenant le programme principal :

HHMMClass heureC;
void setup() {
  heureC = new HHMMClass();
  frameRate(10);
  size(520,400);
}

void draw() {
  heureC.updateHHMM();
  heureC.affiche();
}

Question 7

Modifier la classe HHMMClass pour pouvoir afficher les heures et les minutes à un endroit précis. Cela devrait ainsi vous permettre d'afficher à la fois l'heure courante et l'heure de réveil.

Correction question 7

Nous avons ajouté la possibilité de déplacer l'affichage des 4 digits ainsi que leur grandeur.

Nouvelle classe HHMM :

class HHMMClass {
  int posX,posY;
  int hh_mm;
  int rouge,vert,bleu;
  float zoom;
  Digit[] digits = new Digit[4];
  HHMMClass() {
    posX=posY=0;
    hh_mm = 0x950;
    zoom=1.0;
    for(int i=0;i<4;i++) {
      if (i < 2)
        digits[i]=new Digit(100*i,50);
      else
        digits[i]=new Digit(100*(i+1),50);
    }
  }
  HHMMClass(int x,int y) {
    posX= x;
    posY=y;
    hh_mm = 0x950;
    for(int i=0;i<4;i++) {
      if (i < 2)
        digits[i]=new Digit(100*i+posX,50+posY);
      else
        digits[i]=new Digit(100*(i+1)+posX,50+posY);
    }
    zoom=1.0;
  }
  HHMMClass(int x,int y,int red,int green,int blue) {
    posX= x;
    posY=y;
    rouge = red;
    vert = green;
    bleu = blue;
    hh_mm = 0x950;
    for(int i=0;i<4;i++) {
      if (i < 2)
        digits[i]=new Digit(100*i+posX,50+posY);
      else
        digits[i]=new Digit(100*(i+1)+posX,50+posY);
    }
    zoom=1.0;
  }
  HHMMClass(int x,int y,int red,int green,int blue,float grossissement) {
    posX= x;
    posY=y;
    rouge = red;
    vert = green;
    bleu = blue;
    zoom = grossissement;
    hh_mm = 0x950;
    for(int i=0;i<4;i++) {
      if (i < 2)
        digits[i]=new Digit(100*i+posX,50+posY,zoom);
      else
        digits[i]=new Digit(100*(i+1)+posX,50+posY,zoom);
    }
  }
  void affiche() {
    for(int i=0;i<4;i++) {
      digits[3-i].put(hh_mm >> (4*i) & 0xF);
      digits[3-i].affiche7segs(rouge,vert,bleu);
    }
    if ((second() % 2) == 1)
      fill(rouge,vert,bleu);
    else 
      fill(200);
      
    ellipse((260+posX)*zoom,(100+posY)*zoom,20*zoom,20*zoom);
    ellipse((255+posX)*zoom,(150+posY)*zoom,20*zoom,20*zoom);
  }
  
  void updateHHMM() {
    int temp;
    temp = hour();
    hh_mm = ((temp/10) << 12)+((temp%10)<<8);
    temp = minute();
    hh_mm += ((temp/10) << 4)+(temp%10);
  }
  void incrementHHMM() {
      (hh_mm)++;
      if ((hh_mm & 0x000F) > 0x0009)
        hh_mm += 0x0006;
      if ((hh_mm & 0x00F0) > 0x0050)
        hh_mm += 0x00A0;
      if ((hh_mm & 0x0F00) > 0x0900)
        hh_mm += 0x0600;
      if ((hh_mm & 0xFF00) > 0x2300)
        hh_mm = 0x0000;
  }
  void decrementHHMM() {
      (hh_mm)--;
      if ((hh_mm & 0x000F) == 0x000F)
      hh_mm -= 0x0006;
      if ((hh_mm & 0x00F0) == 0x00F0)
      hh_mm -= 0x00A0;
      if ((hh_mm & 0x0F00) == 0x0F00)
      hh_mm -= 0x0600;
      if ((hh_mm & 0xFFFF) > 0x2359)
      hh_mm = 0x2359;
  }
}

La classe Digit a du être elle aussi modifiée :

class Digit {
   private int[] val={63,6,91,79,102,109,125,7,127,111,119,124,57,94,121,113};
   int nb1digit;
   int x,y;
   float zoom;
   Digit(){
     nb1digit = val[0];
     x=0;y=0;
     zoom=1.0;
   }
   Digit(int nb){
     x=0;y=0;
     zoom=1.0;
     if (nb < 16)
       nb1digit = val[nb];
     else
       nb1digit=64; // affichage tiret en cas d'erreur
   }
   
   Digit(int xd, int yd){
     nb1digit = val[0];
     x=xd;y=yd;
     zoom=1.0;
   }
   
   Digit(int xd, int yd, float grossissement){
     nb1digit = val[0];
     x=xd;y=yd;
     zoom=grossissement;
   }
   
   void put(int nb) {
     if (nb < 16)
       nb1digit = val[nb];
     else
       nb1digit=64; // affichage tiret en cas d'erreur
   }

  private void segment() {
    beginShape();
    vertex(0*zoom,10*zoom);
    vertex(10*zoom,0*zoom);
    vertex(50*zoom,0*zoom);
    vertex(60*zoom,10*zoom);
    vertex(50*zoom,20*zoom);
    vertex(10*zoom,20*zoom);
   endShape(CLOSE); 
  }

void affiche7segs(int rouge,int vert, int bleu) {
  pushMatrix(); // on désire laisser le repère inchangé
  noStroke();
  translate((40+x)*zoom,(0+y)*zoom);
  if ((nb1digit & 1) == 1) fill(rouge,vert,bleu); else fill(200);
  segment(); // segment a
  translate((-10)*zoom,70*zoom);
  if ((nb1digit & 64) == 64) fill(rouge,vert,bleu); else fill(200);
  segment(); // segment g
  translate(-10*zoom,70*zoom);
  if ((nb1digit & 8) == 8) fill(rouge,vert,bleu); else fill(200);
  segment(); // segment d
  translate(15*zoom,-53*zoom);
  rotate(radians(100));
  if ((nb1digit & 16) == 16) fill(rouge,vert,bleu); else fill(200);
  segment(); // segment e
  translate(-70*zoom,0*zoom);
  if ((nb1digit & 32) == 32) fill(rouge,vert,bleu); else fill(200);
  segment(); // segtment f
  translate(-12*zoom,-68*zoom);
  if ((nb1digit & 2) == 2) fill(rouge,vert,bleu); else fill(200);
  segment(); // segment b
  translate(72*zoom,0*zoom);
  if ((nb1digit & 4) == 4) fill(rouge,vert,bleu); else fill(200);
  segment(); // segment c
  popMatrix(); // on récupère le repère initial
}

}

Et le programme principal :

HHMMClass heureC;
void setup() {
  heureC = new HHMMClass(100,50,255,0,0,1.4);
  frameRate(10);
  size(900,400);
}

void draw() {
  heureC.updateHHMM();
  heureC.affiche();
}

Question 8

1°) Réaliser un affichage heure courante heure réveil

2°) Vous réaliserez ensuite un mécanisme de mise à jour de l'heure réveil. On pourra utiliser pour cela les fonctions souris :

et réaliser deux boutons UP et DOWN avec des rectangles.

Indications : La gestion des boutons serait mieux réalisée avec une classe Bouton. Nous vous en proposons une (assez simplifiée) :

class Bouton
{
  int etat;
  String label;
  int couleur; // en gris
  //int r,v,b; // couleur allumé
  int posX,posY,dX,dY;

  Bouton() {
    couleur = 84;
    posX=0; posY=0; dX=40; dY=40;
  }

  Bouton(int posx,int posy,String txt) {
    couleur = 84;
    posX=posx; posY=posy; dX=40; dY=40;
    label = txt;
  }

  void showOff() {
    fill(couleur);
    rect(posX,posY,dX,dY);
    textSize(24);
    fill(0,255,0);
    text(label,posX,posY+dY+24);
  }

  void showOn() {
    fill(couleur);
    rect(posX,posY,dX,dY);
    fill(0,192,0);
    ellipseMode(CORNER);
    ellipse(posX,posY,dX,dY);
    fill(0,255,0);
    ellipse(posX+5,posY+5,dX-10,dY-10);   
  }
  
  Boolean mouseIn() {
    if ((mouseX>posX) && (mouseX < posX+dX)
      && (mouseY>posY) && (mouseY < posY+dY)) 
         return true;
    else return false;
  }
  
}

Question 9

Pour finir, il ne vous reste qu'à faire le mécanisme qui fait sonner le réveil quand l'heure courante est égale à l'heure réveil. Vous pourrez vous inspirer de la correction trouvée dans la Wikiversité.

Indications :

  • Le bouton d'armement est un peu particulier puisqu'il mémorise son état. Il faut donc spécialiser la classe bouton de la question précédente.
  • Il existe une classe Sound pour processing, mais vous devez vérifier si elle est installée ou pas.


Question 10

Utiliser l'héritage pour fabriquer un bouton de type switch.

Indications :

  • Cours Association et héritage appliqué à notre problématique. Il y a la réponse dans l'exercice 6 de ce cours.
  • Et le code ressource :
    • La classe BoutonSuper
class BoutonSuper {
  String label;
  int couleur; // en gris
  int posX,posY,dX,dY;
  BoutonSuper() {
    couleur = 84;
    posX=0; posY=0; dX=40; dY=40;
  }
  BoutonSuper(int posx,int posy,String txt) {
    couleur = 84;
    posX=posx; posY=posy; dX=40; dY=40;
    label = txt;
  }
  void showOff() {
    fill(couleur);
    rect(posX,posY,dX,dY);
    strokeWeight(2);
    stroke(0);
    line(posX,posY+dY,posX+dX,posY+dY);
    line(posX+dX,posY,posX+dX,posY+dY);
    stroke(255);
    line(posX,posY,posX+dX,posY);
    line(posX,posY,posX+dX,posY);
    strokeWeight(1);
    noStroke();
    textSize(24);
    fill(0,255,0);
    text(label,posX,posY+dY+24);
  }
  void showOn() {    
  }
  Boolean mouseIn() {
    if ((mouseX>posX) && (mouseX < posX+dX)
      && (mouseY>posY) && (mouseY < posY+dY)) 
         return true;
    else return false;
  }
}
    • La classe Bouton
class Bouton extends BoutonSuper
{
    Bouton(int posx,int posy,String txt) {
    couleur = 84;
    posX=posx; posY=posy; dX=40; dY=40;
    label = txt;
  }
  void showOn() {
    fill(couleur);
    rect(posX,posY,dX,dY);
    fill(0,192,0);
    ellipseMode(CORNER);
    ellipse(posX,posY,dX,dY);
    fill(0,255,0);
    ellipse(posX+5,posY+5,dX-10,dY-10);
  }
}
    • La classe Switch
class Switch extends BoutonSuper
{ 
  int etat;
  Switch(int posx,int posy,String txt) {
    couleur = 84;
    posX=posx; posY=posy; dX=30; dY=40;
    label = txt;
    etat=0;
  }
  void showOff() {
    fill(couleur);
    rect(posX,posY,dX,dY);
    strokeWeight(2);
    stroke(0);
    line(posX,posY+dY,posX+dX,posY+dY);
    line(posX+dX,posY,posX+dX,posY+dY);
    stroke(255);
    line(posX,posY,posX+dX,posY);
    line(posX,posY,posX+dX,posY);
    strokeWeight(1);
    noStroke();
    textSize(24);
    fill(0,255,0);
    text(label,posX,posY+dY+24);
  }
  void switchEtat() {
    etat ^= 1;
  }
  void showOn() {
    fill(couleur);
    rect(posX,posY,dX,dY);
    fill(0,192,0);
    ellipseMode(CORNER);
    ellipse(posX,posY,dX,dY);
    fill(0,255,0);
    ellipse(posX+5,posY+5,dX-10,dY-10);
  }
  void show() {
    if (etat == 0) showOff(); else showOn();
  }
}
    • et un exemple d'utilisation :
Bouton bouton1 = new Bouton(50,50,"UP");
Switch switch1 = new Switch(150,50,"SW0");
void setup() {
  size(300,300);
  frameRate(10);
}
void draw() {
    bouton1.showOff();
    switch1.show();
}
void mousePressed() {
  if (bouton1.mouseIn()) {
      bouton1.showOn();
    } else if (switch1.mouseIn()) {
      switch1.switchEtat();
    }
}

Poursuivez avec l'exercice 7 du cours ci-dessus qui change seulement l'apparence du bouton.

Corrections de l'exercice 2

Éléments de correction

Projet Coronavirus

Suite à l'arrêt complet de l'enseignement le lundi 16 Mars 2020 pour une durée indéterminée, nous vous proposons le travail personnel suivant.

Pour ce projet, Travail 1 et Travail 2 ne représentent qu'une promenade de santé. Le vrai travail commence avec Travail 3 et Travail 4.

Code de départ

Voici le code de départ d'un jeu snake pratiquement fonctionnel mais comportant un certain nombre de défauts. Ce code est tiré du Forum Réalisation d'un jeu snake en 3D mais il s'agit naturellement d'un jeu 2D.

int colonnes=100;
int lignes=60;
 
ArrayList<TeteOuCorps> serpent;
 
int posX=0;
int posY=0;
Pomme pomme;
 
long  tpbouger=0;
long  tpbouger2=0;
 
int temps=150;
boolean commencer;
 
TeteOuCorps TETE ;
TeteOuCorps elmt;
 
int dir;
String mesag="";
int score=0;
int serpentTaille=2;
int pas=11;
 
// -----------------------------------------------------------
 
void setup()
{
  size(1000, 600);
  background(0, 0, 255);
 
  textAlign(CENTER);
  int posX=width/2;
  int posY=height/2;
 
  serpent=new ArrayList();
  serpent.add(new TeteOuCorps(posX, posY));
  serpent.add(new TeteOuCorps(posX-1*pas, posY));
  serpent.add(new TeteOuCorps(posX-2*pas, posY));
 
  AjoutPomme();
  mesag="Pour commencer, cliquez à l'intérieur de la grille.\n\nUtilisez les flèches du clavier pour diriger le serpent.";
 
  tpbouger=millis();
  tpbouger2=millis();
 
  DessinerGrille();
 
  posX=1;
  posY=0;
}
 
void draw()
{
  background(0, 0, 255);
 
  if (commencer)
  { 
    DessinerGrille();
    pomme.draw();
    DeplacerEtManger();
  }
  else
  {
    text(mesag, 500, 100);
  }
}
 
// -------------------------------------------------------------------
 
void DeplacerEtManger()
{
 
  //  TeteOuCorps elmt2 = serpent.get(serpent.size()-1);
  //  if ((elmt2.x<0)||(elmt2.x>=colonnes)||(elmt2.y<0)||(elmt2.y>=lignes))
  //  {
  //    serpent.clear(); // on vide le tableau
  //    posX = colonnes/2; // et on repositionne la tête du serpent au centre
  //    posY = lignes/2;
  //
  //    temps = 250; // on remet le temps à 250
  //  }
 
  println  (serpent.size());
 
 
  for (int i = serpent.size()-1; i >= 0; i--)
  {
    TeteOuCorps elmt = serpent.get(i);
    elmt.draw();
    //      if (elmt.touche(posX, posY)) 
    //      { 
    //        // serpent.clear(); // on vide le tableau
    //        posX = colonnes/2; // on repositionne le serpent au centre
    //        posY = lignes/2;
    //
    //        temps = 250; // on remet le tempsàa 250
    //        break; //  sortir prématurement de la boucle
    //      }
  } // for 
 
  TeteOuCorps elmt = serpent.get(0);
  if (pomme.touche(elmt.x, elmt.y))
  {
    score ++;         // un point de plus
    serpentTaille ++; // une taille en plus 
    temps -=1;        // on accelere la cadence
 
 
    //obtenir les deux dernier elmt
    TeteOuCorps elmt2 = serpent.get(serpent.size()-1);
    serpent.add(new TeteOuCorps(elmt2.x-2*pas, elmt2.y));
 
    AjoutPomme();
  }
 
  // move
  if (tpbouger2+400 < millis()) {
 
    if (posX!=0||posY!=0) {
      for (int i = serpent.size()-1; i > 0; i--) {
        elmt = serpent.get(i);
        TeteOuCorps elmt2 = serpent.get(i-1);
        elmt.x = elmt2.x;
        elmt.y = elmt2.y;
      } // for
    } // if
 
    elmt   =  serpent.get(0);
    elmt.x += posX * pas;
    elmt.y += posY * pas;
 
    tpbouger2 = millis();
  } // if 
 
  //score
  fill(255, 0, 0);
 
  textAlign(LEFT);
  text("Score : ", width -120, 25);
  text(score, width -50, 25);
} // func
 
void keyPressed()
{
  // reset 
  posX=0;
  posY=0;
  // get key 
  if (key==CODED)
  {
    if (keyCode==UP)
    {
      dir=1;
    }
    if (keyCode==DOWN)
    {
      dir=2;
    }
    if (keyCode==RIGHT)
    {
      dir=3;
    }
    if (keyCode==LEFT)
    {
      dir=4;
    }
    // on determine la position de la tête en fonction de la direction du serpent
    switch(dir)
    {
    case 1:
      posY=-1;
      break;
    case 2:
      posY=1;
      break;
    case 3:
      posX=1;
      break;
    case 4:
      posX=-1;
      break;
    }
  }
}
 
void DessinerGrille()
{
  background(0, 0, 255);
  stroke(255);
  for (int x =0; x < width; x+=10) {
    line(x, 0, x, height);
  }
  for (int y =0; y < height; y+=10) {
    line(0, y, width, y);
  }
}
 
void AjoutPomme()
{
  pomme=new Pomme(pas/2*(int)random(colonnes), pas/2*(int)random(lignes));
}
 
void mousePressed()
{
  mesag="";
  commencer=true;
}
 
// ==========================================================
 
class Pomme {
  int x; // position x
  int y; // et y
  //
  // le constructeur de la classe
  Pomme(int x_, int y_) 
  {
    x=x_;
    y=y_;
  }
 
  void draw() {
    // draw
    fill(0, 255, 0);
    noStroke();
 
    ellipse(x, y, 10, 10);
  }
 
  Boolean touche(int a, int b) {
    // return ((a==x)&&(b==y));
    return dist(a, b, x, y)<20;
  }
} //class
// ==========================================================
class TeteOuCorps
{
  int x;
  int y;
 
  //le constructeur de la class TeteOuCorps
  TeteOuCorps(int x_, int y_)
  {
    x=x_;
    y=y_;
  } // constr
 
  void draw () {
    // draw
    fill(255, 0, 0);
    noStroke();
    ellipseMode(CENTER);
    ellipse(x, y, 20, 20);
  }
 
  Boolean touche(int a, int b) {
    return false;
    // return (((a==x)&&(b==(y+5)))||(a==x&&(b==(y-5)))||((a==(x+5)&&(b==y)))||((a==(x-5)&&(b==y))));
  }
} // class
// =========================================================

Votre travail va consister à modifier ce code. Il vous faudra réaliser un compte-rendu au fur et à mesure de l'avancement de votre travail et l'envoyer à mon adresse mail "serge.moutou at univ-reims".

Travail 1

Dessiner (sur une feuille de papier) en utilisant la technique présentée dans les documents fournis en cours les classes utilisées dans ce code en précisant leurs attributs et méthodes.

Si vous avez perdu vos documents, nous les avons ajouté en cours 6 du document Processing de mon site perso.

Remarque

Il est très possible que ce code :

ArrayList<TeteOuCorps> serpent;

vous pose des problèmes de compréhension. L'interprétation de cette ligne est :

  • serpent est une variable de type ArrayList
  • une ArrayList est quelque chose qui ressemble à un tableau mais sa taille n'est pas forcément déclarée au départ
    • par contre l'ajout d'une case au tableau se fait par serpent.add();
  • <TeteOuCorps> veut dire deux choses :
    • une classe nommée "TeteOuCorps" apparaîtra plus loin dans votre code
    • chacune des cases du tableau contient un objet qui est du type de cette classe "TeteOuCorps".
  • L’accès à une case du tableau se fait par "serpent.get(i)" où i est l'index de la case.

Travail 2

On vous demande d'organiser le code de manière un peu plus traditionnelle avec le code principal d'un côté dans lequel on ajoutera deux onglets (un par classe).

Nous vous rappelons que le nom des onglets doit forcément être celui de la classe.

Il n'y a aucune modification de code à ce stade, seulement quelques couper/coller pour remplir les onglets !!!

Travail 3

Vous devez à tout prix personnaliser ce jeu d'une manière ou d'une autre :

  • diminuer la taille du jeu (ou pas)
  • éventuellement afficher le score en dehors de l'aire de jeu pour une plus grande lisibilité
  • afficher votre nom en dehors de l'aire de jeu.
  • changer les couleurs

La personnalisation sera pour moi la seule manière de distinguer le travail des uns et des autres : éviter trop d'échanges de code entre vous. Il n'est pas interdit d'échanger entre vous des idées mais recopier le code d'un autre NON.

A ce stade aucun des projets ne doit se ressembler :

* ni par les couleurs

* ni par la taille de jeu

* ni par vos noms qui doivent apparaître quelque part

* ni par l'affichage du score

Travail 4

Maintenant vous allez améliorer le code pour résoudre un certain nombre de problèmes :

  • le serpent mange la pomme alors qu'il est encore un peu loin
  • l'ajout d'une ellipse quand le serpent mange la pomme doit être amélioré elle est mal positionnée parfois même si cela ne dure pas très longtemps
  • ajout de la possibilité de perdre et donc de remettre le score à 0 si
    • le serpent sort de l'aire de jeu
    • le serpent se traverse lui-même
  • apparition de temps en temps de "pomme bonus" qui sont d'une autre couleur et comptent plus de points

Je ne veux pas retrouver des choses trop avancées venant du forum originel Réalisation d'un jeu snake en 3D comme des menus par exemple !!!! Restez modeste, vous êtes sensés ne passer que 12 heures sur ce projet.

TD : Visualisation des données d'un accéléromètre

Notre but est d'utiliser la programmation objet pour réaliser une visualisation 3D des données venant d'un Gyroscope/Accéléromètre/Magnétomètre.

Code de départ

Voici un code complet capable de visualiser les données provenant d'un Arduino couplé avec un MPU9250.

La classe Solid

On rappelle que traditionnellement ce code est mis dans un onglet spécifique qui porte le nom de la classe.

class Solid {
  // attributs de position
  int posX, posY;
  // angles d'Euler
  float angleX, angleY, angleZ;
  // couleurs
  int red, green, blue;
  // constructeurs
  Solid() {
    angleX=angleY=angleZ=0;
    posX=width/2; 
    posY=height/2;
  }
  // angles en degrés
  Solid(int posx,int posy,float anglex,float angley,float anglez){
    posX=posx;
    posY=posy;
    //posZ=-50;
    angleX=anglex;
    angleY=angley;
    angleZ=anglez;
  }
  // methodes
  void setColor(int rouge,int vert,int bleu){
    red=rouge;
    green=vert;
    bleu=blue;
  }
  void upDateAngles(float anglex,float angley,float anglez) {
    angleX = anglex; 
    angleY = angley;
    angleZ = anglez;
  }
  void draw_Solid() {
    //Show angles data
    pushMatrix(); 
    
    translate(posX, posY, -50); 
    // dans le repère de l'écran pour Euler123 de l'accéléromètre
    rotateX(radians(-angleX-90));
    rotateZ(radians(-angleZ));
    rotateY(radians(-angleY));
    
    scale(90);
    beginShape(QUADS);

    fill(red, green, blue);
    vertex(-1, 1.5, 0.25);
    vertex( 1, 1.5, 0.25);
    vertex( 1, -1.5, 0.25);
    vertex(-1, -1.5, 0.25);

    vertex( 1, 1.5, 0.25);
    vertex( 1, 1.5, -0.25);
    vertex( 1, -1.5, -0.25);
    vertex( 1, -1.5, 0.25);

    vertex( 1, 1.5, -0.25);
    vertex(-1, 1.5, -0.25);
    vertex(-1, -1.5, -0.25);
    vertex( 1, -1.5, -0.25);

    vertex(-1, 1.5, -0.25);
    vertex(-1, 1.5, 0.25);
    vertex(-1, -1.5, 0.25);
    vertex(-1, -1.5, -0.25);

    vertex(-1, 1.5, -0.25);
    vertex( 1, 1.5, -0.25);
    vertex( 1, 1.5, 0.25);
    vertex(-1, 1.5, 0.25);

    vertex(-1, -1.5, -0.25);
    vertex( 1, -1.5, -0.25);
    vertex( 1, -1.5, 0.25);
    vertex(-1, -1.5, 0.25);

    endShape();
    popMatrix();
  }
}

Le code principal

Le code donné ci-dessous gère une liaison série pour recevoir des données d'un Arduino couplé à un MPU9250. Le code Arduino sera donné un peu plus loin.

Cette liaison série est capable d'analyser des donnée séparées par des marqueurs. Nous la laisson telle quelle pour le moment.

import processing.serial.*;

Serial  myPort;
short   portIndex = 1;
int     lf = 10;       //ASCII linefeed
String  inString;      //String for testing serial communication
int     calibrating;
 
float   dt;
float   x_gyr;  //Gyroscope data
float   y_gyr;
float   z_gyr;
float   x_acc;  //Accelerometer data
float   y_acc;
float   z_acc;
float   x_fil;  //Filtered data
float   y_fil;
float   z_fil;

Solid solide;
 
void setup()  { 
//  size(640, 360, P3D); 
  size(1400, 800, P3D);
  noStroke();
  colorMode(RGB, 256); 
  solide = new Solid(width/2,height/2,0,0,0);
//  println("in setup");
//  String portName = Serial.list()[portIndex];
  String portName = "/dev/ttyACM0";
//  println(Serial.list());
//  println(" Connecting to -> " + Serial.list()[portIndex]);
  myPort = new Serial(this, portName, 38400);
  myPort.clear();
  myPort.bufferUntil(lf);
} 

void draw()  { 
  
  background(0);
  lights();

  solide.setColor(56, 140, 206);
  solide.draw_Solid();
} 

void serialEvent(Serial p) {

  inString = (myPort.readString());
  
  try {
    // Parse the data
    String[] dataStrings = split(inString, '#');
    for (int i = 0; i < dataStrings.length; i++) {
      String type = dataStrings[i].substring(0, 4);
      String dataval = dataStrings[i].substring(4);
      if (type.equals("DEL:")) {
        dt = float(dataval);
      } else if (type.equals("ACC:")) {
        String data[] = split(dataval, ',');
        x_acc = float(data[0]);
        y_acc = float(data[1]);
        z_acc = float(data[2]);
      } else if (type.equals("GYR:")) {
        String data[] = split(dataval, ',');
        x_gyr = float(data[0]);
        y_gyr = float(data[1]);
        z_gyr = float(data[2]);
      } else if (type.equals("FIL:")) {
        String data[] = split(dataval, ',');
        x_fil = float(data[0]);
        y_fil = float(data[1]);
        z_fil = float(data[2]);
      }
    }
    solide.upDateAngles(x_acc,y_acc,z_acc); 
  } catch (Exception e) {
      println("Caught Exception");
  }
}

Le code Arduino

Le code Arduino est disponible dans la Wikiversité ICI : Application 6 : fusion de données par filtre complémentaire. On ne vous demande pas de comprendre ce code dans le détail.

Exercice 4

Faire fonctionner correctement cet ensemble de code.

Le moins que l'on puisse dire c'est que la visualisation fonctionne correctement mais avec un accéléromètre un peu poussif. Ce code ne pourra donc n'être utilisé pour un jeu vidéo que dans certains cas. Nous allons donc essayer de l'améliorer.

Exercice 5

Nous allons utiliser le processeur DMP (Data Movement Processor) du MPU9250. Ceci fonctionne très bien si on installe la librairie qui va bien comme expliqué ICI.

  1. Installer la bibliothèque de Jeff Rowberg en faisant fonctionner l'exemple de la librairie
  2. Modifier le code de l'exemple pour être compatible avec notre logiciel de visualisation
  3. Faire fonctionner correctement l'ensemble

Exercice 6

Vous allez modifier le code de visualisation pour réaliser un jeu vidéo de votre choix.

Il ne s'agit pas pour vous de trouver un jeu tout fait mais de l'adapter à votre problématique. S'il n'est pas en POO (Programmation Orientée Objet) vous le modifierez pour qu'il contienne au moins une classe.

Si vous manquez d'idée, cela peut être :

  • un Pong avec le mouvement de la raquette réalisé par l'accéléromètre. Vous pouvez vous aider de Créer un Pong avec Processing
  • un plateau horizontal avec des trous et des billes à mettre dans les trous. La modification de la position de l'accéléromètre permettra de faire bouger correctement les billes avec comme objectif de les mettre chacune dans un trou.
  • voyage galactique ... avec des obstacles à éviter...
  • Réalisation d'un jeu snake en 3D
  • Ensemble de jeux ici

TP programmation Objet

L'objectif de ce TP sur deux séances de trois heures est de réaliser un clavier de Piano capable de d'envoyer les changements d'états de ses touches par une liaison série. Les changements d'états des touches seront réalisés par la souris. Vous devrez donc être capable de gérer les deux événement souris "mousePressed()" et "mouseReleased()". Nous aurons en bout de la liaison série, un Arduino Leonardo qui lui-même sera relié à un amplificateur sonore

Code de départ

Pour vous aider, quelques ressources vous sont fournies.

Un clavier piano fonctionnel sur une octave

Un code de départ vous est fourni pour vous éviter de chercher les tailles et la façon de représenter votre clavier. Ce code n'envoie absolument rien sur la liaison série mais affiche dans le moniteur de Processing la touche appuyée ou relachée.

int spazio = 50;
int value;

void setup(){
size(400,400);
  //minim = new Minim(this); 
}

void draw(){
background(0);
stroke(0);
for (int x = 0; x <= width; x = x + spazio ){
  fill(255); // white
  rect(x - 50,0,x,height);
}
fill(0); // black
rect(35, 0, 30, 250);
rect(85, 0, 30, 250);
rect(185, 0, 30, 250);
rect(235, 0, 30, 250);
rect(285, 0, 30, 250);
rect(385, 0, 30, 250);
}

void mouseReleased() {
    value = 0;
    println(value);
}

void mousePressed(){
  value=0;
 //do 
if (mouseX < 35 && mouseY < 250 || mouseX < 50 && mouseY > 250){
  //song = minim.loadFile("Do1.mp3");
  //song.play();
  value = 1;
  //println(value);
} 
//re
if (mouseX > 65 && mouseX < 85 && mouseY < 250){
  //song = minim.loadFile("Re1.mp3");
  //song.play();
  value = 3;
  //println(value);
} 
if (mouseY > 250 && mouseX > 50 && mouseX < 100 || value == 3){
  //song = minim.loadFile("Re1.mp3");
  //song.play();
  value = 3;
  //println(value);
} 
//mi
if (mouseX > 115 && mouseX < 150 && mouseY < 250){
  //song = minim.loadFile("Mi1.mp3");
  //song.play();
  value = 5;
  //println(value);
} 
if ( mouseY > 250 && mouseX > 100 && mouseX < 150 || value == 5){
  //song = minim.loadFile("Mi1.mp3");
  //song.play();
  value = 5;
  //println(value);
} 
//fa
if (mouseX > 150 && mouseX < 185 && mouseY < 250){
  //song = minim.loadFile("Fa1.mp3");
  //song.play();
  value = 6;
  //println(value);
} 
if (mouseY > 250 && mouseX > 150 && mouseX < 200 || value == 6){
  //song = minim.loadFile("Fa1.mp3");
  //song.play();
  value = 6;
  //println(value);
} 
//sol
if (mouseX > 215 && mouseX < 235 && mouseY < 250){
  //song = minim.loadFile("Sol1.mp3");
  //song.play();
  value = 8;
  //println(value);
} 
if (mouseY > 250 && mouseX > 200 && mouseX < 250 || value == 8){
  //song = minim.loadFile("Sol1.mp3");
  //song.play();
  value = 8;
  //println(value);
} 

//la
if (mouseX > 265 && mouseX < 285 && mouseY < 250){
  //song = minim.loadFile("La1.mp3");
  //song.play();
  value = 10;
  //println(value);
} 
if (mouseY > 250 && mouseX > 250 && mouseX < 300 || value == 10){
  //song = minim.loadFile("La1.mp3");
  //song.play();
  value = 10;
  //println(value);
} else


//si 
if (mouseX > 315 && mouseX < 350 && mouseY < 250){
  //song = minim.loadFile("Si1.mp3");
  //song.play();
  value = 12;
  //println(value);
} 
if (mouseY > 250 && mouseX > 300 && mouseX < 350 || value == 12){
  //song = minim.loadFile("Si1.mp3");
  //song.play();
  value = 12;
  //println(value);
} 

//do2
if (mouseX > 350 && mouseX < 385 && mouseY < 250){
//  song = minim.loadFile("Do2.mp3");
  //song.play();
  value = 13;
  //println(value);
} 
if (mouseY > 250 && mouseX > 350 && mouseX < 400 || value == 13){
  //song = minim.loadFile("Do2.mp3");
  //song.play();
  value = 13;
  //println(value);
} 

// I bemolli
//do#
if ( mouseX > 35 && mouseX < 65 && mouseY < 250){
  //song = minim.loadFile("Do#1.mp3");
  //song.play();
  value = 2;
} 
//re#

if ( mouseX > 85 && mouseX < 115 && mouseY < 250){
  //song = minim.loadFile("Re#1.mp3");
  //song.play();
  value = 4;
} 
// fa#
if ( mouseX > 185 && mouseX < 215 && mouseY < 250){
  //song = minim.loadFile("Fa#1.mp3");
  //song.play();
  value = 7;
} 
// sol#
if ( mouseX > 235 && mouseX < 265 && mouseY < 250){
  //song = minim.loadFile("Sol#1.mp3");
  //song.play();
  value = 9;
} 
//la#
if ( mouseX > 285 && mouseX < 315 && mouseY < 250){
  //song = minim.loadFile("La#1.mp3");
  //song.play();
  value = 11;
}
  println(value);
}

Ce code est un bon point de départ mais il comporte plusieurs défauts :

  1. si le graphisme n'est pas trop mal, son principe est de dessiner d'abord les touches blanches puis, par dessus, les touches noires.
  2. les touches ne sont pas des objets et donc il est difficile de gérer une couleur appuyée et une couleur relachée

La classe Bouton

La question 8 de l'exercice 2 introduit la notion de classe pour un bouton et vous seriez bien inspiré de relire le code correspondant.

Travail à réaliser

  1. Pour éviter de travailler avec de l'héritage, vous allez définir 4 types de touches : 3 blanches et 1 noire. Par défaut ces touches seront considérées comme dessinées en coordonnée (0,0) en haut à gauche. Le constructeur devra contenir la définition du type de touche qui déterminera complètement le graphisme de la touche. Pévoir aussi une couleur pour touche non appuyée (blanc ou noir) et une couleur pour touche appuyée.
  2. Décomposer chacune des touches blanches en deux rectangles dont on déterminera les coordonnées à partir de l'exemple donné. Évidemment, au moment du dessin il ne faudra pas dessiner de bords aux rectangles sauf sur le côté gauche et le côté droit (line et le stroke associé).
  3. Traiter le cas des touches noires
  4. Décider de la taille et de la forme la zone dans laquelle il faudra appuyer pour considérer un appui de touche. La mise en place de cette zone sera faite par le constructeur en fonction du type de touche.
  5. A jouter une possibilité de transfert vers la droite pour chacun des types de touche
  6. Gérer la mise de l'ensemble des touches dans un tableau (Les listes (ou tableaux))
  7. Tester avec des print et/ou des println
  8. Gérer la liaison série (Serial) en lieu et place de l'affichage dans la console processing.

Correction partielle sans liaison série

class ClassPianoKey
{
  int _note;
  int _type; // type d la touche
  int couleurOff, couleurOn; // noir, blanc ou  gris
  int offsetX;
  int clickAreaPosX,clickAreaPosY,clickAreaDX,clickAreaDY;
  
 ClassPianoKey(int deltaX,int type,int note) {
    _note = note;
    _type = type;
    offsetX = deltaX;
    if (type < 4) { // touche blanche
      couleurOff = 255;
      couleurOn = 200;
      clickAreaPosX=offsetX;
      clickAreaPosY = 250; 
      clickAreaDX= 50;
      clickAreaDY = 150;
    } else {
      couleurOff = 0;
      couleurOn = 50;
      clickAreaPosX=offsetX;
      clickAreaPosY = 0; 
      clickAreaDX= 30;
      clickAreaDY = 250;
    }
    
  }

  void showOff() {
    if (_type == 1) {
      fill(couleurOff);
      stroke(couleurOff);
      rect(0+offsetX,0,35,250);
      rect(0+offsetX,250,50,150);
      // black
      stroke(0);
      line(0+offsetX,0,0+offsetX,400);
      line(0+offsetX+50,0+250,0+offsetX+50,400);
    }
    if (_type == 2) {
      fill(couleurOff);
      stroke(couleurOff);
      rect(0+offsetX+15,0,35,250);
      rect(0+offsetX,250,50,150);
      stroke(0);
      line(0+offsetX,0+250,0+offsetX,400);
      line(0+offsetX+50,0,0+offsetX+50,400);
    }
    if (_type == 3) {
      fill(couleurOff);
      stroke(couleurOff);
      rect(0+offsetX+15,0,20,250);
      rect(0+offsetX,250,50,150);
      stroke(0);
      line(0+offsetX,0+250,0+offsetX,400);
      line(0+offsetX+50,0+250,0+offsetX+50,400);
    }
    if (_type == 4) {
      fill(couleurOff);
      stroke(couleurOff);
      rect(0+offsetX,0,30,250);      
    }
    
  }

  void showOn() {
    if (_type == 1) {
      fill(couleurOn);
      stroke(couleurOn);
      rect(0+offsetX,0,35,250);
      rect(0+offsetX,250,50,150);
      // black
      stroke(0);
      line(0+offsetX,0,0+offsetX,400);
      line(0+offsetX+50,0+250,0+offsetX+50,400);
    }
    if (_type == 2) {
      fill(couleurOn);
      stroke(couleurOn);
      rect(0+offsetX+15,0,35,250);
      rect(0+offsetX,250,50,150);
      stroke(0);
      line(0+offsetX,0+250,0+offsetX,400);
      line(0+offsetX+50,0,0+offsetX+50,400);
    }
    if (_type == 3) {
      fill(couleurOn);
      stroke(couleurOn);
      rect(0+offsetX+15,0,20,250);
      rect(0+offsetX,250,50,150);
      stroke(0);
      line(0+offsetX,0+250,0+offsetX,400);
      line(0+offsetX+50,0+250,0+offsetX+50,400);
    }
    if (_type == 4) {
      fill(couleurOn);
      stroke(couleurOn);
      rect(0+offsetX,0,30,250);      
    }
    
  }
  
  Boolean mouseIn() {
    if ((mouseX>clickAreaPosX) && (mouseX < clickAreaPosX+clickAreaDX)
      && (mouseY>clickAreaPosY) && (mouseY < clickAreaPosY+clickAreaDY)) 
         return true;
    else return false;
  }
  
}

Et enfin le programme principal :

ClassPianoKey[] pianokeys = new ClassPianoKey[15];

void setup() {
  size(400,400);
  frameRate(1); 
  pianokeys[0]= new ClassPianoKey(0,1,1);  //do
  pianokeys[1]= new ClassPianoKey(35,4,2);  //do#
  pianokeys[2]= new ClassPianoKey(50,3,3);  //re
  pianokeys[3]= new ClassPianoKey(85,4,4);
  pianokeys[4]= new ClassPianoKey(100,2,5);
  pianokeys[5]= new ClassPianoKey(150,1,6);
  pianokeys[6]= new ClassPianoKey(185,4,7);
  pianokeys[7]= new ClassPianoKey(200,3,8);
  pianokeys[8]= new ClassPianoKey(235,4,9);
  pianokeys[9]= new ClassPianoKey(250,3,10);
  pianokeys[10]= new ClassPianoKey(235,4,11);
  pianokeys[11]= new ClassPianoKey(250,3,12);
  pianokeys[12]= new ClassPianoKey(285,4,13);
  pianokeys[13]= new ClassPianoKey(300,2,14);
  pianokeys[14]= new ClassPianoKey(350,1,15);
  for (int i=0;i<15;i++) {
    pianokeys[i].showOff();
  }
}

void draw() {
  
}

void mousePressed() {
  for (int i=0;i<15;i++) {
    if (pianokeys[i].mouseIn())
      pianokeys[i].showOn();
  }  
}

void mouseReleased() {
  for (int i=0;i<15;i++) {
    if (pianokeys[i].mouseIn())
      pianokeys[i].showOff();
  }  
}

Malheureusement l'ensemble est un peu lent pour être utilisé pour réaliser de la musique !!!

Voir aussi