LEÇONS
Vous voulez programmer sur Processing, créer un petit jeu de balles assez sympa, comprendre les lignes de code ou vous êtes juste curieux ? Alors vous êtes bien au bon endroit !
Voici les cours dispensés par notre professeur d'ISN, M. Laclaverie. Il y aura régulièrement des mises à jour bien évidemment.
Jetez également un coup d’œil aux lignes de code, à la culture informatique ( version ordi. - version mobile ) et aux récapitulatifs sur l'informatique afin de mieux comprendre le cours...
Note : vous ne comprenez pas les cours ? retrouvez nos captures d'écran !
LEÇON 1 : INTRODUCTION A PROCESSING
I) Présentation de l'IDE (Integrated Development Environement)
Cet environnement de programmation utilise un langage Java (Just Another Vague Acronym) simplifié. Processing utilise des fonctions pré-programmés qui permettent facilement de dessiner des formes, gérer des sons, des vidéos, etc. Cliquer sur "Help>Reference" pour le détail des fonctions. Un programme est structuré en différents blocs : "void setup() {}" est une fonction qui ne prend aucun paramètre, qui ne s'exécute qu'une fois et qui ne renvoie rien au reste du programme (qui renvoie le vide = void). "void draw() {}" s'exécute en boucle (30 fps par défaut). Elle non plus ne prend pas de paramètres et ne renvoie rien au reste du programme. Au début du programme, on déclare des variables globales qui seront utilisables dans tout le programme et auxquelles on peut affecter des valeurs. Attention, il faut finir les lignes par un point-virgule, au même titre qu'un point à la fin d'une phrase.
II) Déplacer un objet
Pour déplacer un objet, il faut tout d'abord avoir déclaré une variable vitesse. Ensuite, il suffit d'additionner cette vitesse aux coordonnées de l'objet dans le "void draw" pour que l'objet bouge.
Exemple de balle se déplaçant à l'horizontale :
void draw() {
ellipse (x, y, a, b) ;
vitesseX = x + vitesseX
}
LEÇON 2 : LES CONDITIONS, L'ALÉATOIRE & LE RÉPÉTITIF
Pour réaliser notre jeu, les balles doivent apparaître à des endroits différents à chaque démarrage du jeu (aléatoire), elles doivent rebondir sur les limites (condition) et elles doivent être une dizaine à l'écran (répétition du même code pour chaque balle).
I) Condition
if(x>470){vitesseX=-vitesseX;}
Si x est supérieur à 470, alors la vitesse change de signe, sinon rien
x>470 est bouléen : il est vrai ou faux
II) Aléatoire
int x=(int)random(40,460);
random est une fonction renvoyant un nombre aléatoire compris entre 40 et 460, mais ce nombre est décimal : (int) permet de ne prendre que la partie entière.
III) Répétitif
Les tableaux sont des outils permettant de stocker sous un même nom plusieurs variables d'un même type.
int[]x; <-- création d'un tableau d'entiers nommé "x"
x=new int[10]; <-- le tableau d'entiers pourra contenir 10 valeurs
for(int i=0 ; i<10 ; i++) { ==> i=i+1 équivalent à i++
instructions;
}
i est le compteur de boucles et prendra des valeurs comprises entre 0 et 9 de 1 en 1
LEÇON 3 : TIRER
Pour tirer, il faut associer un viseur à la souris et vérifier qu'au moment du clic, elle est bien sur une balle.
mouseX et mouseY sont deux variables prédéfinies dans Processing permettant d'accéder à la position de la souris.
stroke(255) : le trait devient blanc
noFill() : pas de remplissage
fill(255) : remplissage blanc
Lorsqu'un tir est réussi, la balle doit disparaître, le score augmenter, le nombre de tir restants diminuer et le nombre de tirs réussis augmenter.
LEÇON 4 : BARGRAPH
I) Faire apparaître une balle
L'objectif est de faire
apparaître 10 rectangle blancs l'un au-dessus de l'autre au
démarrage et un bouton pour recharger. Dès que l'on tire, il faut faire disparaître un
rectangle blanc, et si l'on clique sur le bouton pour recharger, les 10 rectangles doivent réapparaître.
II) Agencer les différentes lignes
Au bout d'un certain moment, les lignes commencent à se faire nombreuses, et cela peut devenir vite très difficile de se relire. Eh bien, il est possible d'agencer les lignes de telle sorte à alléger et aérer les lignes de code. Explications : prenons par exemple un ensemble de lignes qui codent pour un cercle qui va se déplacer :
ellipse(x, y, a, b);
x=x+vitesseX;
y=y+VitesseY;
Ici, nous nous contenterons de trois lignes, mais il peut y en avoir bien plus évidemment. On considère que l'on va créer une fonction, que l'on nomme "ball", et qui va correspondre à toutes ces lignes. Ainsi, en dehors du "void draw", vous allez créer un "void ball" qui va contenir toutes ces lignes :
void ball() {
ellipse(x, y, a, b);
x=x+vitesseX;
y=y+VitesseY;
}
Et maintenant, on va "appeler" cette fonction dans le "void draw" : à l'endroit où il y avait trois lignes, il n'y aura plus que "ball();". Vous en déduirez que cela peut s'avérer utile lorsque l'on a des dizaines de lignes qui codent pour le même "intérêt".
Vous n'avez peu-être pas bien saisi ? Pour continuer dans notre exemple, voici un extrait de code :
void draw() {
ellipse(x, y, a, b);
x=x+vitesseX;
y=y+VitesseY;
}
Avec la technique que nous venons de voir, ceci serait transformé en cela :
void draw() {
ball();
}
void ball() {
ellipse(x, y, a, b);
x=x+vitesseX;
y=y+VitesseY;
}
Libre à vous de nommer la fonction comme vous voulez ! Ainsi, vos lignes de codes sont regroupés en "parties", ayant chacun un intérêt, ici par exemple de générer et faire bouger une balle.
LEÇON 5 : PROGRAMMATION ORIENTÉE OBJETS
La programmation orientée consiste en une méthode de programmation se concentrant sur la programmation des objets. Ainsi, on n'énonce plus les instructions une par une à la suite des autres mais l'on regroupe différents paramètres ensemble afin de générer facilement des balles, de changer leur style, leur couleur, leur texture...
//Déclaration d'une instance de Balle
Balle maBalle;
void setup() {
smooth(); //Lissage des dessins
size(400, 200); //Taille de la fenêtre
noStroke();
// on initialise une Balle nommée maBalle
maBalle = new Balle(width/2, height/2, color(255));
}
void draw() {
fill(0, 10);
rect(0, 0, width, height);
// appel des méthodes
maBalle.bouge();
maBalle.rebondir();
maBalle.affiche();
}
class Balle {
//Déclaration des paramètres de base de la balle
float x; //position
float y;
float vitesseX; // vitesse
float vitesseY;
color couleur; // couleur
//Constructeur de la balle, appelé quand on fait new Balle(...)
Balle (float nouvX, float nouvY, color nouvCouleur) {
x = nouvX;
y = nouvY;
couleur = nouvCouleur;
vitesseX = 2 + random(-1, 1);
vitesseY = 2 + random(-1, 1);
}
//Dessin de la balle
void affiche() {
fill(couleur);
ellipse(x, y, 40, 40);
}
void bouge() {
x = x + vitesseX;
y = y + vitesseY;
}
void rebondir() {
//Si la balle touche une mur, elle rebondit
if (x > width-20 '' x < 20) {
vitesseX = vitesseX * -1;
}
if (y > height-20 '' y < 20) {
vitesseY = vitesseY * -1;
}
}
}
Il faut cependant appliquer des modifications à ce sketch pour faire apparaître nos 10 balles :
- Balle []
maBalle;
- new
- for (int x
= 0; x < 10; x++) {
- maBalle[x] = new Balle(random(25,350),random(25,150), color(random(127,255),random(127,255),random(127,255)));
LEÇON 6 : QUELQUES OUTILS POUR LE PROJET
I) L’intérêt des classes
Les classes permettent de créer plusieurs objets avec le meme groupe de lignes de code. Les classes permettent de modifier facilement le nombre d'objets à traiter et de créer des niveaux avec peu de lignes de code. Elles permettent également de gérer le comportement des objets en leur appliquant des méthodes : par exemple, le tableau d'objets permet de gérer en peu de lignes des milliers de balles ! Et enfin cela permet d'organiser le code de manière plus lisible.
II) Eviter la repetition des clics
La fonction millis(); renvoie le nombre de millisecondes qui s'est déroulé depuis le début de l exécution. Lors d'un clic, on met sa valeur dans la variable date. La variable oldDate contient l'instant du clic précédent. Si la différence est supérieure à 1000 millisecondes (par exemple), le booléen tir devient vrai et le tir est possible.
III) Images, limites et mouvements
Une image est constituée de pixels RVB (rouge, vert, bleu). Leurs valeurs sont stockées dans le tableau pixels[]. Pour y accéder :
- loadPixels(); charger le pixel
- for(int i=0; i<230300;i=i+1){pixels[i]=color(#F50C2B);} modifier la couleur
- updatePixels(); appliquer le changement
- red(get(x, y))==0; get est l'accesseur permettant d accéder à la composante rouge du pixel de coordonnées x,y ; si elle est égale a 0, le booléen est vrai
- PImage
img; déclare une variable de type image.
- img
= loadImage("labyrinthe.png"); charge l'image labyrinthe préalablement jetée sur
le sketch
- image(img, 0, 0); affiche l image dont l'angle supérieur gauche aura pour coordonnées 0,0
IV)
Les librairies
Toutes les possibilités JAVA ne sont pas chargés par défaut au lancement de Processing : des librairies placés dans le dossier sketchbook permettent de donner à Processing de nouvelles capacités. Pour cela, il faut importer la librairie : import readBox.* ; et indiquer à Processing dans les préférences où se trouvent le sketchbook.
LEÇON 7 : COMPRESSION DE FICHIERS TEXTE PAR L'ALGORITHME DE HUFFMAN
Lorsque des textes se retrouvent dans des dossiers compressés, .zip par exemple, ils seront compressés. La compression d'un fichier tete se fait sans perte d'informations.
I) Codages des caractères
Le code ASCII, codant sur 1 octet ou 8 bits, permet de coder les caractères américains du clavier. Tous les caractères sont codés sur le même nombre de bits. Pour compresser, il faut coder les caractères les plus fréquents sur un plus petit nombre de bits. Exemple :
c'est_un_texte
- (c,
1) [le "c" apparaît une fois]
- (',
1)
- (e,
3) [le "e" apparaît trois fois]
- (s,
1)
- (t,
3)
- (_,
2)
- (u,
1)
- (n, 1)
- (x, 1)
Il faut enregistrer le code et l'arbre (comme ci-dessous) car il existe de nombreux arbres possibles pour un texte donné.
Evidemment, pour un texte aussi court - celui qui est l'exemple -, on ne va pas gagner de place, au contraire, puisqu'il faudra aussi enregistrer l'arbre ! Mais pour des longs fichiers textes, comme des bases de données, où aucune perte ne peut être acceptée - contrairement à la résolution pour une image ou une vidéo, une perte de qualité sonore pour de la musique et des vidéos... -, on peut gagner beaucoup de place, quelques fois des gigaoctets ! Il faut aussi optimiser l'arbre pour que l'encodage soit le plus court possible pour chaque caractère...
II) Permutation
circulaire de Burrows-Wheeler (ici avec "TETE_A_TETE")
Il s'agit là de faire passer la première lettre à la fin de la phrase - ou l'inverse - jusqu'à retrouver la phrase du début :
TETE_A_TETE
ETE_A_TETET
TE_A_TETETE
E_A_TETETET
_A_TETETETE
A_TETETETE_
_TETETETE_A
TETETETE_A_
ETETETE_A_T
TETETE_A_TE
ETETE_A_TET
TETE_A_TETE
Ensuite, on trie par ordre alphabétique :
A_TETETETE_
ETETETE_A_T
ETETE_A_TET
ETE_A_TETET
E_A_TETETET
TETETETE_A_
TETETE_A_TE
TETE_A_TETE
TE_A_TETETE
_A_TETETETE
_TETETETE_A
Enfin, on notifie les derniers caractères et la position de la phrase initiale.
_TTTT_EEEEA
Position de la phrase initiale :8
III) Move-to-front
On prend chaque lettre et on la code selon son numéro dans l'alphabet puis on envoie la lettre devant l'alphabet :
- dictionnaire : 0 --> A ; 1 --> B ; 2 --> C ; 3 --> D ; ... ; 25 --> Z ; 26 --> _
_ --> 26
- 0 --> _ ; 1 --> A ; 2 --> B ; 3 --> C ; ... ; 26 --> Z
T --> 20
- 0 --> T ; 1 --> _ ; 2 --> A ; 3 --> B ; ... ; 26 --> Z
T --> 0
T --> 0
T --> 0
_ --> 1
- 0 --> _ ; 1 --> T ; 2 --> A ; 3 --> B ; ... ; 26 --> Z
E --> 6
- 0 --> E ; 1 --> _ ; 2 --> T ; 3 --> A ; ... ; 26 --> Z
E --> 0
E --> 0
E --> 0
A --> 3
Code final : 26;20;0;0;0;1;6;0;0;0;3
Ces 3 méthodes sont associés pour créer des fichiers .zip (Burrows-Wheeler, Move-to-front puis Huffman). Pour décoder, on fait l'inverse.
LEÇON 8 : INITIATION
A LA ROBOTIQUE AVEC ARDUINO !
Arduino est un microcontrôleur OpenSource qui peut servir à piloter un robot, une station météo, ou enregistrer des données dans une fusée. Il comprend des entrées et des sorties analogiques et numériques, une mémoire et un microprocesseur. C'est un véritable ordinateur.
Exemple du clignotement d'une diode
int led = 13; //comme sur processing
void setup() {
pinMode(led, OUTPUT); //on déclare que l'on utilise le port 13 (led)
} //et qu'il agira comme sortie (et pas entrée)
void loop() { //comparable au void draw sur processing
digitalWrite(led, HIGH); // allumer la LED (HIGH équivaut à 1/tension)
delay(1000); // on attend 1000 millisecondes (1 seconde)
digitalWrite(led, LOW); // éteindre la LED (LOW équivaut à 0/non-tension)
delay(1000);
Un robot fonctionne avec une boucle infinie qui va lui permettre de réagir en fonction des données reçues par le port série ou par les entrées. Pour que l'action soit visible, il faut des actionneurs reliés aux sorties de l'arduino.
Amélioration du programme :
void loop() { //analogWrite permet l'envoi d'un message analogique
analogWrite(led, brightness); //on a préalablement déclaré brightness=0
brightness = brightness + fadeAmount; //brightness va varier
if (brightness == 0 '' brightness == 255) { //si brightness = 0 ou 255
fadeAmount = -fadeAmount ; //on fait diminuer ou augmenter brightness
}
delay(30); //le tout avec un délai de 30 millisecondes
}
Dans cet exemple plus complet, l'intensité lumineuse de la diode dépend de la variable brightness. Cette variable change toutes les 30 millisecondes à chaque tour de la fonction loop.
Communication série
Serial.begin(9600); //au début, les ports vont communiquer 9600 fois/sec
if (Serial.available() > 0) { //si on envoie une donnée (non nulle)
int thisChar = Serial.read(); //thisChar prend la valeur du caractère lu
Serial.print("You sent me: \'"); //affichage du caractère lu
Serial.write(thisChar);
Serial.print("\' ASCII Value: "); //affichage du code ASCII
Serial.println(thisChar);
LEÇON 9 : LES GRAPHES
Un graphe est un outil permettant de représenter des objets (sommets) et liens ou interactions entre ces objets (arêtes).
Ex : réseau SNCF, villes et routes, réseaux intrnet, labyrinthes
Les graphes peuvent permettre de trouver les sorties de labyrinthes.
L'exemple du berger
Problématique : un berger a un loup, une chèvre et un chou. En présence du berger, la chèvre ne mange pas le chou et le loup ne mange pas la chèvre. Pour traverser une rivière, le berger ne peut transporter qu'un de ses compagnons à la fois.
-
Combinaisons impossibles : chèvre + chou, loup + chèvre, loup + berger, chou + berger, chou + chèvre + loup, berger (seul).
Sortir d'un labyrinthe
Un labyrinthe peut être décrit par un graphe, les croisements étant les objets placés au sommet et les couloirs les liens entre ces sommets.
Entrée : A ; sortie : Z.
A
AB
ABC
ABM
ABCD
ABCK
ABM
ABCDE
ABCDK
ABCK
ABM
ABCDEF
ABCDEG
ABCK
ABM
ABCDEGH
ABCDEGI
ABCK
ABM
ABCDEGIJ
ABCK
ABM
ABCKD
ABCKL
ABM
ABMN
ABMZ <-- sortie !

Comment résoudre le problème du berger ? Nous vous laissons tout le temps d'y réfléchir ; vous pourrez trouver la solution ici...

Exploration en profondeur
Le parcours d'un graphe en largeur traite d'abord les possibilités les plus courtes.
A
AB
ABC
ABM
ABM
ABCK
ABCD
ABMZ <-- sortie !
ABMN
ABCK
ABCD
Conclusion : le parcours en largeur permet de trouver le chemin le plus court pour sortir ; le parcours en profondeur, pour ne pas tourner en rond, doit interdire de repasser par des sommets déjà utilisés.
LEÇON 10 : LES ALGORITHMES DE TRI
Pourquoi trier les données ? Si les données sont triées, l'accès aux informations sera plus rapide dans la plupart des cas. Toutes les informations peuvent être représentées par des nombres que l'on triera par ordre (dé)croissant.
- Tri par sélection
C'est la méthode spontanée pour trier un tableau sans ordinateur : on cherche la valeur la plus petite, on la place dans la première case d'un nouveau tableau et on la supprime du tableau à trier puis de même avec les suivantes.
Amélioration de l'algorithme : un nouveau tableau n'est pas nécessaire, il suffit de déplacer les valeurs les plus petites au début du tableau. Ainsi, plus de cases vides. Cette méthode demande un temps d'exécution plus important que le tri par fusion.
- Tri par fusion
Cet algorithme découpe la table en groupes de deux cases ; les nombres sont triés par ordre croissant dans chaque groupe. Puis, on groupe deux ensembles de deux cases que l'on trie, puis deux ensembles de quatre, de huit... Si nécessaire, on rajoute à la fin du tableau de grandes valeurs pour permettre le tri. Cette méthode est plus rapide, surtout si elle est codée avec un algorithme récursif. Celui-ci utilise des fonctions qui s'appellent elles-mêmes. Le code est moins long et plus rapide d'exécution.
Programmation d'un tri
création un tableau de valeurs aléatoires
affichage le tableau non-trié
appel de la fonction de tri
affichage du tableau trié












