Introduction à Processing Java
Introduction à Processing Java
2. DESSINER............................................................................................................................................................. 21
2.1. L'espace de dessin ............................................................................................................................................. 21
2.2. Les formes .......................................................................................................................................................... 23
2.3. Les couleurs ....................................................................................................................................................... 27
2.4. Le texte ............................................................................................................................................................... 30
2.5. Les images .......................................................................................................................................................... 32
Les styles de bordures ................................................................................................................................................... 40
La typographie .............................................................................................................................................................. 41
Les transformations ...................................................................................................................................................... 46
3. PROGRAMMER .................................................................................................................................................. 55
3.1. Les variables ...................................................................................................................................................... 55
3.2. Les conditions .................................................................................................................................................... 57
3.3. Les répétitions ................................................................................................................................................... 58
3.4. Les listes ............................................................................................................................................................. 62
3.5. Les méthodes ..................................................................................................................................................... 70
3.6. Les objets ........................................................................................................................................................... 76
3.7. Les commentaires.............................................................................................................................................. 80
4. ANIMER ................................................................................................................................................................ 82
4.1. La méthode draw .............................................................................................................................................. 82
4.2. La ligne de temps............................................................................................................................................... 86
4.3. L'animation d'un objet ..................................................................................................................................... 89
4.4. L'animation de plusieurs objets ....................................................................................................................... 94
4.5. La lecture du son ............................................................................................................................................... 98
Processing fédère une forte communauté d'utilisateurs professionnels et amateurs : artistes, graphistes,
vidéastes, typographes, architectes, web designers et designers en général. Il est également utilisé par des
enseignants en arts qui souhaitent familiariser leurs étudiants avec les potentialités artistiques de la
programmation, les concepteurs du logiciel l'ayant pensé dès l'origine comme un outil d'apprentissage.
Pour un artiste habitué à utiliser à main levée des outils comme son crayon, son pinceau, sa souris ou sa
tablette graphique, il peut sembler surprenant de créer des formes, des couleurs, des mouvements en
saisissant seulement une suite d'instructions à l'aide de son clavier.
Ce mode d'expression artistique par le code utilise les caractéristiques propres à l'informatique (rapidité
d'exécution, automatisation des actions et des répétitions, interaction, etc.) pour produire des créations
originales qui n'auraient pas vu le jour autrement ou dont la réalisation, à l'aide de procédés plus classiques
ou de logiciels plus complexes, aurait demandé davantage de temps.
Processing permet également de programmer des circuits électroniques qui interagissent avec le milieu qui
les entoure. Connectés à des capteurs sonores, thermiques, de mouvement, ces circuits électroniques peu
coûteux, dénommés micro-contrôleurs, peuvent en retour générer des images, actionner un bras articulé,
envoyer des messages sur Internet... bien entendu en fonction du programme que vous aurez créé.
Comme nous le verrons dans ce manuel, en apprenant à programmer avec Processing, vous allez développer
votre capacité d'expression et d'imagination.
Plusieurs universités, écoles et centres d'artistes donnent des cours sur ce logiciel. Dans un contexte
francophone, on peut mentionner notamment l'Université du Québec à Montréal (UQAM), l'Université
Laval, la Société des arts technologiques - SAT (Canada-Québec), le Centre art sensitif - Mains d'oeuvres à
Paris, l'Ecole d'Art d'Aix en Provence, l'association PING à Nantes (France), l'Ecole de Recherche
Graphique (ERG) et IMAL à Bruxelles, la Haute Ecole Albert Jacquard (HEAJ) à Namur (Belgique), La
Haute Ecole d'Art et de Design (HEAD) à Genève, La Haute Ecole d'Arts Appliqués de Lausanne - ECAL
(Suisse).
En tant que logiciel libre, Processing bénéficie de la générosité de nombreux programmeurs volontaires qui
mettent à disposition des utilisateurs des morceaux de codes facilement réutilisables (dénommés en jargon
informatique des librairies). Plus d'une centaine de librairies étendent ainsi les capacités du logiciel dans le
domaine du son, de la vidéo, de l'interaction, etc.
Un peu d'histoire
Processing a été conçu au laboratoire Aesthetics + Computation Group (ACG) du MIT Media Lab par Ben
Fry et Casey Reas en 2001. Ce logiciel est plus ou moins le prolongement du projet Design By Numbers,
créé par le directeur du laboratoire, l'artiste-programmeur John Maeda. Dans son livre présentant le langage
de programmation qu'il a conçu, Maeda met en avant la simplicité et l’économie d'action dans la
programmation d’images.
Plusieurs éléments de ce premier projet sont visibles dans l’environnement Processing : la simplicité de
l’interface du logiciel, la priorité donnée à l’expérimentation et l’apprentissage, ainsi que les nombreuses
fonctions que les deux environnements partagent. Les concepteurs de Processing ne cachent pas cet héritage.
La version actuelle de Processing est la version 1.2.1. Les exemples donnés dans ce manuel font référence à
cette version du logiciel.
La saisie des exemples de programmes proposés dans ce manuel peut constituer à elle seule une expérience
formatrice, ne serait-ce qu'en apprenant à éviter de faire des erreurs de frappe. Si cette activité vous rebute
ou si vous voulez rapidement expérimenter le résultat d'un exemple, copiez le code du programme depuis les
pages web de l'ouvrage (consultables sur la partie francophone du site Flossmanuals à l'adresse
[Link] pour ensuite le coller directement dans la fenêtre du logiciel.
Disponible en plusieurs formats numériques (html, pdf, ePub) ainsi qu'en version papier, ce manuel est
publié sous licence GPLv2 : vous êtes autorisé à le lire et à le copier librement.
Ouvrage collectif, ce manuel est vivant : il évolue au fur et à mesure des contributions. Pour consulter la
dernière version actualisée, nous vous invitons à visiter régulièrement le volet francophone de Flossmanuals
sur le site [Link]
Le cœur du manuel d'environ 270 pages a été réalisé en 5 jours dans le cadre d'un Booksprint qui s'est tenu à
Paris du 6 au 10 septembre 2010 à l'initiative et avec le soutien de l'Organisation internationale de la
Francophonie ([Link]
publicités, génériques de films, vidéos clips, dessins animés, Processing permettant de créer des
effets visuels originaux ;
visualisation de données scientifiques sous la forme d'images fixes ou animées, facilitant ainsi la
représentation d'informations complexes dans de multiples secteurs professionnels (environnement,
transports, économie, sciences humaines, etc.) ;
production musicale, Processing permettant non seulement de lire mais aussi de transformer et de
créer du son ;
spectacle vivant, grâce aux nombreuses fonctions d'interaction offertes par Processing, il est
possible de créer des performances de VJing, utiliser le mouvement des danseurs pour générer en
temps réel des effets sonores et visuels dans un spectacle, réaliser des œuvres d'arts numériques
interactives ;
Architecture, Processing facilitant la représentation spatiale, il est utilisé dans des projets
d'architecture pour automatiser le dessin de constructions en 2 ou 3 dimensions.
La suite de ce chapitre va vous présenter quelques exemples de travaux réalisés avec l'aide de Processing
dans différents contextes.
Mycelium
Des traits apparaissent sur l'écran, se ramifient pour finalement constituer un visage. A partir d'une image
d'origine, ce programme d'animation conçu avec Processing simule le développement du mycelium, la partie
végétative des champignons, et utilise ce procédé à des fins esthétiques.
NY Times est un système de visualisation de données basé sur les flux d'information du site internet New
York Times. Utilisant les actualités du journal comme source de données, le programme rend visible sous la
forme d'un graphe le degré d'importance des mots employés et leur relation entre eux. Au final, on obtient
une série d'images en haute résolution destinée à l'impression.
Shadow Monsters
Shadow Monster est une installation interactive qui fonctionne sur le principe des ombres chinoises. Le
public qui passe devant l'installation voit son ombre se transformer en monstre, des excroissances étranges
poussant instantanément sur les extrémités du corps. Sur cette image, des personnes se sont amusées à
réaliser des figures animales avec l'ombre portée de leurs mains, l'installation interactive prenant de son côté
l'initiative d'y rajouter des dents, des touffes de cheveux, des antennes ou des yeux.
Création de formes géométriques complexes s'inspirant de l'ouvrage Kunstformen der Natur (Formes d'art
de la nature) du scientifique et talentueux dessinateur du XIXe siècle, Ernst Haeckel.
Champ d'Ozone
Champ d'Ozone est une installation artistique présentée en 2007 à Paris dans le cadre de l'exposition "Airs
de Paris". Commandée par le Centre d'art et de culture Georges Pompidou, elle a été conçue en collaboration
avec Airparif, un organisme de surveillance de la qualité de l'air en Ile-de-France. Cette œuvre interactive
projette sur la surface d'une vitre des nuages virtuels dont la couleur varie constamment selon le niveau de
pollution atmosphérique à Paris.
L'identité graphique de la Conférence des Nations-Unies sur le climat à été réalisée par un studio londonien
avec Processing. Les créatifs de cette agence de communication ont conçu un outil pour générer un logo
animé basé sur des principes d'interaction de force illustrant ainsi la complexité des échanges lors de cette
conférence.
Body navigation
Body navigation est une performance scénique. Elle a été réalisée lors d'une collaboration entre la
chorégraphe Tina Tarpgaard et le développeur Jonas Jongejan. Les danseurs sont filmés par une caméra
infrarouge qui repère leurs déplacements et des visuels générés par Processing sont instantanément projetés
autour d'eux.
Robert Hodgin explore les possibilités expressives du code, souvent en associant son et algorithme. Il génère
de nombreux films avec Processing qu'il distribue sur Internet. Ces expérimentations sont ensuite réutilisées
dans divers projets, comme le visualiseur actuellement installé dans iTunes, ou ces papillons générés avec
des diagrammes de Voronoi pour une exposition personnelle.
Dans le cadre de ce projet artistique, les internautes, jeunes et moins jeunes, ont été invités à dessiner un
mouton, référence non dénuée d'humour au Petit Prince d'Antoine de Saint-Exupéry. Ces illustrations ont
été regroupées dans une immense base de données accessible en ligne. Processing permet de parcourir les 10
000 dessins et de visualiser leur tracé.
Atelier de Bordeaux sur l'impression sur tissus d'illustrations conçues avec Processing.
Motifs génératifs
[Image 600 de large maximum au format png]
Les images des réalisations présentées dans ce chapitre sont la propriété de leurs auteurs respectifs.
L'installation proprement dite de Processing est assez simple et dépend de la plate-forme que vous utilisez.
Dans tous les cas, allez sur la page de téléchargement [Link] et cliquez sur le nom
de votre plate-forme.
Pour la suite de ce chapitre, dans les noms de fichiers et dossiers, le xxx fait référence à la version de
Processing utilisée.
Sous Windows
Pour Windows, il est préférable de ne pas utiliser l'option Without JAVA qui nécessitera d'installer
séparément Java. En cliquant sur Windows dans la page de téléchargement du site de Processing, vous allez
télécharger une archive [Link] . Une fois le téléchargement achevé, décompressez l'archive et
placez le dossier Processing extrait de l'archive dans le dossier C:\Program Files\.
Allez ensuite dans le dossier C:\Program Files\Processing et exécutez le fichier [Link] en cliquant
dessus.
Sous Mac OS X
La version Mac OS X est téléchargée sous la forme d'une image disque (fichier .dmg). Par défaut ce fichier
s'affiche sur le bureau et la fenêtre de l'image disque s'ouvre automatiquement. Au sein de cette fenêtre, il
suffit de prendre l'icône Processing et de la glisser sur l'icône du dossier Applications.
Sous GNU/Linux
Après avoir cliqué sur Linux pour télécharger le fichier [Link] correspondant à cette plate-forme,
il suffit de suivre pas à pas la procédure d'installation décrite ci-après.
Il est préférable d'enregistrer (ou copier) le fichier téléchargé dans votre répertoire personnel (exemple :
/home/MonDossierPersonnel).
en utilisant votre souris (notamment si vous utilisez la distribution Ubuntu - gnome) : effectuez un
clic droit sur le fichier pour faire apparaître le menu contextuel puis cliquez sur Extraire ici ( Extract
here ).
pour les plus experts, saisissez et exécutez dans un terminal la commande suivante :
Dans les deux cas, un dossier processing-xxx sera créé dans votre répertoire personnel, le xxx faisant
référence version du logiciel. Ainsi dans le cas de la version 1.2.1 de Processing le nom du dossier
s'appellera processing-1.2.1 et le chemin pour accéder à ce répertoire sera
/home/MonDossierPersonnel/processing-1.2.1.
Pour installer Processing, en mode graphique, il suffit de se placer dans le dossier créé et d'effectuer
un double clic.
Si par contre vous utilisez un terminal, saisissez la commande :
cd /home/VotreDossierPersonnel/Processing-xxx/
Après l'installation du logiciel, il faut s'assurer que le fichier processing contenu dans le dossier du
programme ( /home/MonDossierPersonnel/Processing-xxx) est bien exécutable. Ce n'est pas le cas par
défaut.
chmod +x processing
En mode graphique, effectuez un clic droit sur le fichier processing puis dans le menu contextuel qui
apparaît, cliquez sur propriétés. La boîte de dialogue suivante s'affichera :
Cliquez sur l'onglet Permissions puis cocher la case Autoriser l'exécution du fichier comme un programme.
Lancer Processing
Pour démarrer le programme Processing dans le terminal (en étant toujours dans le dossier du
programme, exemple /home/MonDossierPersonnel/processing-1.2.1/), lancer la commande :
./processing
Pour fonctionner, Processing requiert Java (au moins la version 5, également appelée 1.5) originaire de Sun
Microsystems.
Si Java n'est pas installé, vous pourrez télécharger et installer openjdk en vous rendant sur le site
[Link] ou mieux, en utilisant le système de paquetage de votre distribution de GNU/Linux.
Sous Ubuntu, exécuter la commande suivante (notez bien que cette étape est préalable à l'installation de JRE
présentée un peu plus loin) :
Ensuite, il se peut que vous ayez à changer la version de Java qui est proposée par défaut. Pour vous en
assurer, saisissez la commande suivante :
Une liste de choix devrait alors apparaître. Entrez le chiffre qui se trouve sur la même ligne que le chemin
qui contient le mot «sun», et appuyer sur entrée. Dans l'exemple présenté ci-dessous, la version
présélectionnée est identifiée par un astérisque situé au début d'une des lignes. Il faudrait donc saisir le
chiffre 4 pour sélectionner la bonne version.
Processing est basé sur le langage Java. C'est cette syntaxe qui sera utilisée lorsque vous allez programmer.
Processing vous facilite la maîtrise de ce langage en se chargeant de manière transparente des opérations
relativement complexes comme gérer les fenêtres, le son, la vidéo, la 3D et bien d'autres choses encore. Ce
logiciel propose une large palette de fonctionnalités prédéfinies qui simplifie la conception de programmes
créatifs, notamment pour les personnes ne maîtrisant pas les notions complexes de programmation et de
mathématiques.
Ce chapitre vous présente les bases de l'interface de Processing et les notions minimales de la syntaxe Java à
connaître pour bien débuter.
A ce jour, l'interface de Processing est disponible uniquement en anglais. Malgré cela, son utilisation reste
simple et il est très probable que les versions à venir proposeront une traduction en plusieurs langues, dont le
français. Les nombreux atouts de ce logiciel libre le rendent suffisamment incontournable pour commencer à
apprendre à l'utiliser sans plus attendre.
L'interface
L'interface d'utilisation de Processing est composée de deux fenêtres distinctes : la fenêtre principale dans
laquelle vous allez créer votre projet et la fenêtre de visualisation dans laquelle vos créations (dessins,
animations, vidéos) apparaissent.
1. Barre d'actions
2. Barre d'onglets
3. Zone d'édition (pour y saisir votre programme)
4. Console (destinée aux tests et messages d'erreur)
5. Fenêtre de visualisation (espace de dessin)
6. Barre de menu (non représentée sur la copie d'écran)
C'est le dossier dans lequel seront enregistrés les sketchs et les librairies (des modules externes proposant
des fonctionnalités supplémentaires). Par défaut ce dossier se nomme Processing et se trouve dans
Documents (sous Mac) ou Mes Documents (sous Windows). Sous GNU/Linux, il est dans votre dossier
personnel sous le nom de sketchbook.
Pour modifier ce dossier, allez dans le menu Files > Preferences. Dans la boîte de dialogue qui apparaît,
cliquez sur Browse (parcourir) pour choisir le dossier qui vous convient.
A tout moment, pour savoir quel est votre dossier de travail, sélectionnez, dans le menu Sketch > Show
Sketch Folder. Cette option est également accessible via le raccourci ctrl-k sous Windows/Linux ou cmd-k
sur Mac :
Bases du langage
Processing utilise le langage Java pour créer vos programmes. Ce langage, qui va être lu par votre ordinateur
après avoir cliqué sur le bouton de lancement du sketch, possède un certain nombre de règles de syntaxe qui
si elles ne sont pas respectées empêcheront l'exécution correcte du programme. Il y a aussi un certain
nombre de concepts de base nécessaires à connaître.
Processing est sensible à la casse, il fait la différence entre les majuscules et les minuscules : libre est
différent de Libre !
Le point virgule
A la fin de chaque instruction (dessiner un cercle, effectuer un calcul, etc.), vous devez mettre un « ; » afin
de signaler à l'ordinateur la fin de l'instruction. Dans l'exemple ci-dessous, on utilise les caractères « // »
pour insérer un commentaire qui sera ignoré lors de l'exécution (la présence de commentaires dans votre
programme facilite sa compréhension ultérieure).
//Dessine un cercle
ellipse(10,10, 10, 10);
Appels de méthodes
fill(128);
ellipse(50, 50, 60, 60);
La console (la zone 4 dans le schéma de l'interface présenté en début de ce chapitre) permet d'afficher du
texte brut à des fins de test et de débogage (correction d'erreurs). Pour afficher quelque chose dans cette
zone, il faut utiliser la méthode println();
println(1000);
Par extension, le terme console sert également à désigner la bande grise juste au dessus de la zone noire de
test/débogage : Processing y affiche un certain nombre de messages, notamment pour signaler des erreurs.
Processing permet d'effectuer des calculs mathématiques. Tout au long de l'utilisation de cet environnement,
vous serez amené à calculer des valeurs. Ne vous inquiétez pas : l'ordinateur le fera pour vous. Les
opérations d'addition, soustraction, multiplication et division peuvent être combinées. Il est également
possible d'utiliser des parenthèses pour définir l'ordre des opérations.
Attention aux nombres à virgule ! Dans Processing, les unités sont séparées des décimales par un point et
non par une virgule.
println(10 + 5);
println(10 + 5 * 3); // 5*3 (soit 15) puis additionne 10
println((10 + 5) * 3); // 10+5 (soit 15) puis multiplie 15 par 3
println(10.4 + 9.2);
Cette suite d'instructions saisie dans la fenêtre d'édition de Processing va produire dans la console le résultat
suivant :
Certaines opérations arithmétiques peuvent être contractées. Par exemple, i++ donne le même résultat que i
= i + 1 . Et x+=10 donne le même résultat que x=x+10.
Maintenant que vous connaissez les bases de l'interface de Processing, il ne vous reste plus qu'à apprendre à
écrire du code qui fonctionne pour dessiner et créer ce que vous souhaitez. C'est l'objet des prochains
chapitres.
Cet espace est créé par l'instruction size() qui prend deux arguments : size(largeur,hauteur);.
Par exemple, dans la fenêtre d'édition du logiciel Processing, saisissez la commande suivante :
Amusez-vous à changer les dimensions de cette fenêtre en modifiant les valeurs entre parenthèses pour en
voir le résultat.
Par défaut :
size();
Quand on travaille en 3 dimensions (3D), en plus des deux axes de coordonnées, on a un troisième axe de
coordonnées Z, exprimant la profondeur :
Dans ce cas précis, on utilise la commande size avec un troisième paramètre indiquant que l'on travaille
dans un espace en 3D size(100, 100, P3D);
Le point
Pour commencer à dessiner, nous allons partir d'un point. Sur l'écran, un point est l'équivalent d'un pixel
localisé dans la fenêtre de visualisation par deux axes de coordonnées, x et y correspondant respectivement à
la largeur (axe horizontal) et à la hauteur (axe vertical) de l'espace de dessin. En suivant ce principe, la
création d'un point dans Processing s'effectue à l'aide de l'instruction point(x,y). Dans cet exemple, le
point est très petit. Il est placé au centre de la fenêtre de visualisation.
point(50, 50);
Notez que le cadre de la fenêtre de visualisation (l'espace de dessin) a une dimension de 100x100, ce qui
explique que le point soit situé en plein milieu. Si on le dessinait en dehors du cadre (hors champ), avec par
exemple l'instruction size(150,150), on ne le verrait pas.
La ligne
Par définition, une ligne (AB) est constituée par une infinité de points entre un point de départ A et un point
d'arrivée B. Pour la construire, nous allons nous intéresser uniquement aux coordonnées x et y de A et de B.
Ainsi, si par exemple dans la fenêtre par défaut, le point A se situe dans la région en bas à gauche de votre
fenêtre, et que le point B se situe en haut à droite, les instructions suivantes, peuvent dessiner cette ligne
sous la forme line(xA,yA,xB,yB) :
Le rectangle
Un rectangle se dessine par quatre valeurs en faisant l'appel de rect(x,y,largeur,hauteur). La première
paire de valeurs x et y, par défaut (mode CORNER) correspond au coin supérieur gauche du rectangle, à
l'instar du point. En revanche la seconde paire de valeurs ne va pas se référer à la position du coin inférieur
droit, mais à la largeur (sur l’axe des x, horizontal) et à la hauteur (sur l’axe des y,
vertical) de ce rectangle.
Exemple :
Pour que la première paire de valeurs corresponde au centre (le croisement des deux diagonales aux
coordonnées 50, 50) du rectangle, il faut utiliser le mode CENTER comme suit :
rectMode(CENTER);
rect(50, 50, 80, 40);
L'ellipse
Comme pour le rectangle, l'ellipse se construit sous les modes CENTER (par défaut), et CORNER. Ainsi
l'instruction suivante produit un cercle dont les coordonnées du centre sont les deux premières valeurs entre
parenthèses. La troisième valeur correspond à la grandeur du diamètre sur l'axe horizontal (x) et la quatrième
à la grandeur du diamètre sur l'axe vertical : notez que si les 3e et 4e valeurs sont identiques, on dessine un
cercle et dans le cas contraire, une ellipse quelconque :
Le triangle
Le triangle est un plan constitué de trois points. L'invocation de
triangle(x1,y1,x2,y2,x3,y3) définit les trois points de ce triangle :
L'arc
Un arc ou section de cercle, peut se dessiner avec l'appel de arc(x, y, largeur, hauteur, début,
fin), où la paire x, y définit le centre du cercle, la seconde paire ses dimensions et la troisième paire, le
début et la fin de l'angle d'arc en radians :
Le quadrilatère
Le quadrilatère se construit en spécifiant quatre paires de coordonnées x et y sous la forme
quad(x1,y1,x2,y2,x3,y3,x4,y4) dans le sens horaire :
Courbe Bézier
La courbe de type Bézier se construit à l'aide de bezier(x1,y1,x2,y2,x3,y3,x4,y4)
Courbe lissée
L'appel de curveVertex() dessine plusieurs paires de coordonnées x et y, entre deux points de contrôle,
sous la forme curveVertex(point de contrôle initial,xN,yN,xN,yN,xN,yN, point de contrôle
final) ce qui permet de construire des courbes lissées :
beginShape();
curveVertex(0, 100);
curveVertex(10, 90);
curveVertex(25, 70);
curveVertex(50, 10);
curveVertex(75, 70);
curveVertex(90, 90);
curveVertex(100, 100);
endShape();
Formes libres
Plusieurs formes libres peuvent être dessinés par une succession de points en utilisant la suite d'instructions
beginShape(),vertex(x,y),...,endShape(). Chaque point se construit par ses coordonnées x et y. La
fonction CLOSE dans endShape(CLOSE) indique que la figure sera fermée, c'est-à-dire que le dernier point
sera relié au premier, comme dans l'exemple ci-dessous de dessin d'un hexagone :
beginShape();
vertex(50, 10);
vertex(85, 30);
vertex(85, 70);
vertex(50, 90);
vertex(15, 70);
vertex(15, 30);
endShape(CLOSE);
noStroke();
quad(10, 10, 30, 15, 90, 80, 20, 80);
Remplissage
De la même manière, il est possible de dessiner des formes sans surface de remplissage avec l'instruction
noFill() :
noFill();
quad(10, 10, 30, 15, 90, 80, 20, 80);
Par défaut, l'arrière-fond de la fenêtre de visualisation (l'espace de dessin) est gris neutre, les contours des
figures sont noirs, et la surface de remplissage est blanche. Vous apprendrez au prochain chapitre comment
modifier les couleurs à votre convenance.
Primitives 3D
Les formes prédéfinies disponibles en 3 dimensions (primitives 3D) peuvent être réalisées de manière simple
en appelant size(x, y, P3D) au début de notre sketch puis en employant en fonction de vos besoins les
instructions sphere(taille) et box(longueur, largeur, profondeur). Il est également possible de
produire des effets d'éclairage sur nos formes tridimensionnelles à l'aide de lights().
La sphère
size(100, 100, P3D);
noStroke();
lights(); // éclairer l'objet 3D
translate(50, 50, 0); // voir Chapitre "Transformations"
sphere(28);
La boîte
size(100, 100, P3D);
noStroke();
lights();
translate(50, 50, 0);
rotateY(0.5);
box(40);
Par exemple, 100% de rouge, 80% de vert et 20% de bleu vont donner ensemble la couleur orange. La
méthode fill() nous permet de spécifier la couleur des prochaines formes à dessiner. Chaque canal d'une
couleur peut être donné sur une échelle de 0 à 255. Ainsi, 80% de 255 donne 204, et 20% de 255 donne 51.
La couleur de fond
On peut changer la couleur de fond en appelant la méthode background(). Attention : rajouter
background() à la suite d'une composition déjà existante, l'effacerait !
background(0, 0, 0);
La couleur de remplissage
A chaque fois que l'on dessine une forme, on le fait avec la couleur de remplissage qui est choisie à ce
moment-là. On le fait en appelant la méthode fill().
noStroke();
fill(255, 204, 51);
rect(25, 25, 50, 50);
Processing nous offre différents formats pour exprimer la couleur. Si vous faites de la programmation Web,
vous connaissez sans doute le format hexadécimal. Selon ce procédé, la même couleur orange peut être
obtenue en écrivant :
fill(#ffcc33);
rect(25, 25, 50, 50);
Par ailleurs, il est possible de spécifier la valeur du canal alpha de la couleur utilisée, c'est-à-dire son degré
de transparence. Pour ce faire, on doit donc préciser quatre paramètres à la méthode fill(). Le quatrième
argument est la valeur alpha.
Si l'on souhaite choisir une couleur qui correspond à un ton de gris, il suffit de donner un seul paramètre à la
méthode fill(). C'est la valeur de gris, de 0 à 255.
fill(127);
rect(25, 25, 50, 50);
La couleur du contour
Pour changer la couleur du contour des formes que l'on dessine, on doit appeler la méthode stroke() avec
comme paramètres les canaux de la couleur désirée. Appeler noStroke() désactive la couleur de contour. A
titre d'illustration, voici un dessin de masque africain utilisant ces deux instructions :
size(200, 200);
smooth();
background(255); // on dessine un fond blanc
bezier(-30, -70, -5, -60, -5, 0, -5, 20); // courbe du sourcil droit
line(-5, 20, 5, 20); // ligne du nez pour joindre l'extrémité des courbes
size(100, 100);
background(255);
stroke(#000000);
fill(#FFFF00);
strokeWeight(1);
rect(10, 10, 10, 10);
stroke(#FF0000);
fill(#00FF00);
strokeWeight(5);
rect(40, 40, 20, 20);
Exercice :
L'espace colorimétrique
Définir des couleurs à partir des canaux rouge, vert et bleu constitue un moyen parmi d'autres de décrire
l'espace colorimétrique de votre dessin. Processing supporte également le mode TSV. TSV signifie « teinte,
saturation, valeur ». En anglais, on appelle ce mode HSB, pour « hue, saturation, brightness ». On choisit
une échelle de 0 à 100 pour chacun de ces 3 canaux. La teinte correspond à un chiffre indiquant la position
de la couleur sur l'échelle chromatique, soit un arc-en-ciel. Le rouge est à gauche, puis viens l'orange, le
jaune, le vert, le bleu et le violet.
Ici, on change le mode de couleur pour le TSV afin de créer un dégradé de teinte qui ressemble aux couleurs
d'un arc-en-ciel.
noStroke();
size(400, 128);
2.4. Le texte
On va maintenant dessiner des caractères textuels qui s'afficheront dans la fenêtre de visualisation. Attention
: écrire dans l'espace de dessin ne ressemble pas à l'écriture dans le sens classique du terme, notamment
comme dans un traitement de texte. Le texte dans Processing ressemblerait plutôt à du « graffiti urbain »,
c'est-à-dire à une sorte de peinture de caractères alphanumériques qui finiront tous par s’empiler les uns sur
les autres. C'est davantage un procédé « typo-graphique » qu'un travail d'écriture, avec une insistance sur
l'aspect graphique des mots ou des lettres que nous allons dessiner.
Bonjour Processing !
Tout comme les formes prédéfinies, telles les lignes ou les ellipses, il suffit d'une seule instruction dans
notre sketch pour dessiner du texte. Ouvrez une nouvelle fenêtre d'édition, tapez la ligne suivante, et
exécutez-la en cliquant sur le bouton run :
Vous devriez voir s'afficher la petite fenêtre de visualisation par défaut de 100 x 100 pixels, avec le mot «
»Salut ! » écrit en blanc :
Comme son nom l'indique, l'instruction text() dessine du texte dans la fenêtre de visualisation. Elle
requiert trois paramètres : {le message que nous voulons écrire}, {sa coordonnée x}, {sa coordonnée y}.
fill(0);
text("Salut", 10, 20);
fill(255);
text("tout", 10, 40);
fill(255,0,0);
text("le", 10, 60);
fill(0,0,255);
text("monde", 10, 80);
Ce programme devrait vous donner le résultat suivant, avec chacun des quatre mots
écrits avec leur propre couleur :
Il suffit d'indiquer une couleur, puis dessiner du texte avec cette couleur. Bien sûr vous pouvez ne choisir
qu'une seule couleur et dessiner plusieurs messages avec cette couleur, ou dessiner avec une combinaison de
couleurs comme dans cet exemple.
Empilement
Comme nous l'avons indiqué dans l'introduction de ce chapitre, les mots s'inscrivent à l'intérieur de la
fenêtre de visualisation tel un dessin et non pas tel un système de traitement de texte. On ne peut ni
sélectionner ni modifier directement ce texte à l'aide de la souris ou du clavier. La seule modification qui
peut être appliquée s'effectue au niveau de votre programme en précisant à l'aide d'instructions appropriées
que vous souhaitez par la suite effacer complètement le texte et d'écrire par dessus.
fill(0);
text("un mot peut", 10, 20);
text("en cacher", 10, 40);
fill(204);
rect(28,25,50,20);
fill(0);
text("un autre", 10, 60);
Nous avons écrit quatre messages, parfois avec la même couleur, parfois avec une autre.
Notez que le mot « cacher » a été caché justement par la couleur de remplissage qui a été
définie avec la même valeur que celle utilisée pour dessiner le fond.
Comme dans n'importe quel dessin, l'ordre des opérations est important pour déterminer le rendu final. Ce
principe s'applique même en dehors du logiciel Processing : « s'habiller, sortir, aller au travail » ne donnera
pas le même résultat que « sortir, aller au travail, s'habiller ».
Ici nous allons commencer avec une image légèrement réduite de l'île des peupliers à Ermenonville, trouvée
sur le site Commons de Wikimedia (base de données d'images et de médias appartenant au domaine public
ou sous licence libre) à l'adresse suivante : [Link]
Formats d'image
Trois formats de fichier d'image sont acceptés dans Processing : PNG, JPEG, ou GIF. Ceux qui ont de
l'expérience dans la conception de sites web devraient reconnaître ces trois formats, car ce sont les plus
répandus sur la Toile. Chaque format utilise ses propres méthodes de compression de l'image (réduction de
la taille mémoire de l'image occupée sur l'ordinateur), lui donnant à la fois des avantages et des désavantages
et que nous pouvons résumer de la manière suivante :
1. JPEG est souvent utilisé pour compresser des images de type photographique. Ce format ne permet
pas d'avoir des zones transparentes.
2. GIF est historiquement utilisé pour l'illustration de boutons et autres éléments graphiques de l'espace
de travail d'un programme. Sur les sites internet, ce format est utilisé pour les logos et de manière
générale pour les dessins réalisés par ordinateur (notamment ceux qui comportent des aplats de
couleurs). Ce format peut contenir des zones transparentes binaires (soit opaques soit transparentes,
sans possibilité d'opacité intermédiaire). Il existe des images gif animées, mais Processing ignorera
cet aspect.
Glisser-déposer
Nous allons maintenant importer le fichier de cette image dans l'environnement Processing. Pour bien
réussir cette étape, nous vous recommandons de sauvegarder d'abord votre sketch, de préférence dans le
dossier processing qui devrait se trouver par défaut dans le dossier Documents ou Mes documents de votre
ordinateur.
Localisez maintenant votre fichier d'image, et glissez-le directement sur la fenêtre Processing :
Lorsque nous glissons les fichiers de cette manière, Processing nous indique dans la bande grisée de la
console qu'il a ajouté ce fichier « dans le sketch ». En réalité, Processing a simplement copié cette image
dans un dossier nommé data, qui devrait maintenant se trouver à côté de votre [Link] que vous
venez de sauvegarder.
Pour accéder rapidement à ce dossier, afin par exemple d'y placer de nouveaux fichiers d'images, il suffit de
sélectionner, dans le menu Sketch, l'option Show Sketch Folder. Cette option est également accessible via le
raccourci Ctrl-k sur Windows et GNU/Linux ou Cmd-k sur Mac :
Maintenant que nous avons placé une image dans notre dossier data, nous pouvons désormais nous en servir
dans notre programme.
size(500,400);
PImage ile;
ile = loadImage("[Link]");
image(ile,50,10);
D'abord nous avons donné à notre espace de dessin une taille plus grande que notre image, juste pour mieux
comprendre comment celle-ci peut être positionnée dans le sketch final.
1. Créer une variable qui contiendra les données (en pixels) de notre image.
Processing page 34 / 155
2. Importer les pixels d'un fichier dans notre variable.
3. Dessiner les pixels de cette variable dans notre espace de dessin.
Tout d'abord, nous devons créer une variable Processing, avant d'importer notre fichier dedans. Mais avant
tout, à quoi sert une variable ? Et bien dans ce cas précis, il s'agit d'un nom interne à notre programme qui
contient l'ensemble des pixels de notre fichier [Link]. A chaque fois que nous écrirons par la suite le mot «
ile » dans notre programme, Processing comprendra qu'il s'agit de la suite de valeurs en pixels qui
composent notre image. C'est justement le rôle de cette action loadImage("nomdefichier") d'aller
chercher ces pixels dans le fichier et les importer dans notre variable nommé « ile ».
Vous avez peut-être également noté un mot étrange au tout début du code ci-dessus, le mot PImage. Celui-ci
indique à Processing le genre de la variable et lui permettra de consacrer assez de mémoire dans votre
ordinateur pour contenir l'ensemble des données de ce genre. Dans le cas de n'importe quelle variable, la
syntaxe à utiliser est {type de la variable} {nom de la variable} = {les valeurs de la variable}.
Par exemple, si par un tour de force il était possible d'importer un petit chien tout mignon dans Processing, il
suffirait d'écrire PetitChiot milou = loadDog("[Link]"); On écrit d'abord le type de la chose, le
nom de la chose, et enfin on lui donne sa valeur.
Ici, cette valeur est donnée par la fonction loadImage() qui va aller chercher les pixels de l'image dans le
fichier et les importera dans notre variable nommée ile.
Pour plus d'informations sur les variables et les différents types de variables, reportez-vous au chapitre dédié
à ce sujet.
Enfin, une fois notre variable remplie, nous la dessinons à une position {x,y} dans notre sketch. Si nous
voulons dessiner notre image à sa taille originelle, nous utilisons la version courte de l'instruction image qui
nécessite uniquement trois paramètres : {PImage}, {x}, {y}.
image(ile,50,10)
size(400,400);
PImage webcam;
webcam = loadImage("[Link]
image(webcam,10,20,width,height);
Si notre programme n'est pas animé, comme c'est le cas ici, il y aura juste une longue pause lorsque l'image
se charge dans Processing.
Par contre, faites bien attention à placer ce type d'instructions au début du sketch sinon vous risquez de
ralentir fortement le fonctionnement des autres parties du programme, celles-ci devant attendre le
téléchargement complet de vos images depuis Internet avant de s'exécuter. Dans des cas très spécifiques, si
vous avez besoin d'importer des images web en plein milieu de votre sketch, sachez qu'il existe des
techniques appropriées dénommées « fils d'exécution ». Ces techniques séparent le chargement de fichiers
médias depuis internet du reste des fonctions du programme. Il s'agit malheureusement d'un sujet trop
avancé pour ce manuel. Pour davantage d'informations sur les fils d’exécution, reportez-vous au forum du
site de Processing en faisant une recherche sur le mot « thread ».
Pour changer la taille de l'image, il suffit de rajouter deux paramètres à votre image, {largeur, hauteur}, ce
qui nous amène à 5 paramètres : {variableImage, x, y, largeur,hauteur}.
size(500,250);
PImage ile;
ile = loadImage("[Link]");
image(ile,10,10,20,15);
image(ile,20,20,50,30);
image(ile,45,45,100,75);
image(ile,95,95,1000,750);
Notez que nous avons importé qu'une seule fois l'image dans notre variable ile et que celle-ci peut être
dorénavant utilisée pour le restant de notre programme. Notez également que nous avons respecté les
proportions {x,y} de notre image dans le changement de la taille, mais que celles-ci auraient pu prendre
n'importe quelle valeur, ce qui reviendrait à étirer l'image sur un de ces deux axes.
Pour lever cette contrainte, certains formats de fichiers font appel à une couche alpha pour gérer la
transparence de certaines zones de l'image et ainsi laisser apparaître les éléments qui sont situés derrière
elles (un fond coloré ou illustré par exemple). Cette couche se superpose aux couches rouge, vert, bleu
utilisées pour composer l'image et indique l'intensité de la transparence pour chaque pixel, avec même la
possibilité de pixels semi-transparents dans le cas du format PNG.
Si vous voulez sauvegarder votre image avec une couche alpha, vous avez trois possibilités qu'il faut choisir
lors de l'exportation de votre image dans votre logiciel de traitement d'image préféré :
Chaque logiciel exportera les images à sa manière. Sachez juste qu'il existe une différence par exemple entre
GIF, PNG-8, et PNG-24, notamment sur la façon dont chaque format va traiter cette couche alpha. Le plus
sûr des trois, et qui vous donnera plus d'options, c'est le PNG-24.
Quel que soit le fond sur lequel elle sera placée, cette image s'y intègrera parfaitement parce qu'elle contient
justement une couche alpha décrivant les parties transparentes et non transparentes du carré de pixels qui la
composent. Notez que les pixels autour de Rousseau sont transparents, alors que son front et son cou sont
opaques.
N'hésitez pas à copier cette image au format png sur votre ordinateur depuis la version en ligne de ce manuel
: [Link] chapitre Les images (conçue à partir d'une illustration mise à
disposition sur le site Commons de Wikimedia, cette image est libre de droit).
Dans notre programme Processing, nous allons pouvoir constater que les pixels situés autour du personnage
sont effectivement transparents en superposant l'image de Rousseau (au format png) avec celle du paysage
précédemment utilisée (au format jpg) :
size(400,300);
PImage ile;
ile = loadImage("[Link]");
PImage rousseau;
rousseau = loadImage("[Link]");
image(ile,0,0);
image(rousseau,20,20);
size(500,130);
PImage ile;
ile = loadImage("[Link]");
tint(255,0,0);
image(ile, 10,10, 110,110);
tint(255,255,0);
image(ile, 130,10, 110,110);
tint(255,255,255,127);
image(ile, 250,10, 110,110);
tint(0,0,255,127);
image(ile, 320,10, 110,110);
Tout comme les instructions fill() et stroke(), l'instruction tint() peut prendre une, deux, trois, ou
quatre valeurs, selon ce que nous voulons faire. En indiquant trois paramètres, par exemple, nous pouvons
augmenter/diminuer l'intensité de la couche rouge, vert, ou bleu de notre image. En indiquant quatre
paramètres, nous pouvons augmenter/diminuer, en plus de ces trois couleurs, la valeur de
transparence/opacité de l'image.
smooth
La méthode smooth() permet d'activer le lissage des contours. Elle permet d'éviter l'effet d'escalier qui
apparaît sur les lignes diagonales.
strokeWeight
La méthode strokeWeight() permet de varier l'épaisseur d'une ligne ou d'un contour.
strokeCap
La méthode strokeCap() permet de définir l'apparence des extrémités d'une ligne. Cette méthode n'est pas
utile pour les formes. Elle peut avoir les valeurs SQUARE (extrémité carré), PROJECT (extrémité avec 2 petits
angles brisés) ou ROUND (extrémité arrondie). Par défaut c'est le mode ROUND qui est utilisé. Cette méthode ne
fonctionne pas avec P3D ou OpenGL.
La typographie
Ce chapitre va vous permettre de personnaliser l'usage des textes dans Processing en utilisant des polices de
caractères alternatives.
Dans l'illustration ci-dessus nous avons sélectionné la police Georgia. C'est à partir du nom de cette police et
de sa taille que Processing générera le fichier de la police à importer, ex : « [Link] ». Notons
enfin que l'extension « .vlw » associée à l'intitulé du fichier sera rajoutée à toutes les polices que nous
importerons de cette manière. Si par curiosité vous vous intéressez à l'origine de cette extension, son nom
fait référence sous forme d'un acronyme au « Visual Language Workshop » (vlw) du MIT Media Lab. C'est
ce laboratoire qui historiquement est à l'origine d'un certain nombre de principes et de travaux qui ont permis
à Processing de voir le jour.
Si nous voulons savoir où Processing a sauvegardé notre police, il suffit de sélectionner, dans le menu
Sketch, l'action Show Sketch Folder.
Cette action fera apparaître le dossier « data » dans lequel notre police a été sauvegardée. Son fichier
s'appelle « [Link] ». C'est ce nom que nous devons retenir pour intégrer la police dans notre
programme.
1. Importer le fichier [Link] dans une variable afin que notre programme connaisse le
nom de la police utilisée et sache la dessiner lorsqu'il affichera du texte. Ce fichier contient en effet
les informations décrivant la structure géométrique de la police pour pouvoir la reproduire ;
2. Sélectionner cette variable dans notre programme comme police active ;
3. Dessiner un caractère ou une phrase quelque part dans notre sketch à l'aide des instructions
appropriées pour le voir ensuite s'afficher dans la fenêtre de visualisation de Processing.
En option, il est possible de choisir la taille à laquelle nous voulons dessiner avec notre police, mais comme
nous avons déjà paramétré cet aspect lors de la création du fichier, il ne sera pas nécessaire de l'indiquer ici.
Voici le code complet d'un programme simple qui réunit toutes ces étapes pour dessiner une phrase dans la
fenêtre de visualisation. Par tradition, nous allons faire nos premiers pas dans l'écriture en écrivant « Salut
tout le monde ! ».
size(500,150);
PFont police;
police = loadFont("[Link]");
Tout d'abord, nous avons fixé la taille de notre fenêtre de visualisation (l'espace de dessin), comme dans
quasiment n'importe quel programme Processing.
Ensuite, nous avons importé notre fichier dans une variable Processing (dénommée police). A quoi sert une
variable ? Et bien dans ce cas précis, il s'agit d'un nom interne à notre programme qui fait référence au
fichier de la police [Link] que nous souhaitons utiliser. A chaque fois que nous écrirons par
la suite le mot police dans notre programme, Processing comprendra qu'il s'agit de faire appel à la police
Georgia Italic 48 contenue désormais dans ce mot.
Vous avez peut-être également noté un mot étrange en tout début de cette phrase, le mot PFont. Celui-ci
indique à Processing le genre de la variable et lui permettra d'ouvrir assez de mémoire pour contenir
l'ensemble des données de ce genre. Dans le cas de n'importe quelle variable, la syntaxe à utiliser est {type
de la variable} {nom de la variable} = {les valeurs de la variable}.
Par exemple, si par un tour de force il était possible d'importer un petit chaton tout mignon dans Processing
il suffirait d'écrire petitChaton mioumiou = loadPetitChaton("[Link]"); On écrit d'abord le
type de la chose, le nom de la chose, et enfin on lui donne sa valeur. Ici, cette valeur est donnée par la
fonction loadFont() qui va aller chercher la structure géométrique de la police dans le fichier et l'importera
dans notre variable nommée « police ».
La suite de notre programme est probablement un peu plus intuitive. Nous sélectionnons la police avec
laquelle nous voulons dessiner. Même s'il n'existe qu'une seule police actuellement dans notre programme, il
faut néanmoins passer par cette étape. Notez que vous pouvez importer autant de polices que vous voulez et
passer de l'un à l'autre, à l'image de ce qu'il est possible de faire avec les couleurs.
Dans cet exemple, nous avons indiqué la taille de la police juste pour vous montrer qu'il est possible de la
changer en cours de route.
Enfin, nous dessinons une petite phrase et indiquons la position {x,y} où notre texte doit se dessiner. On
obtient le résultat suivant :
Point d'origine
Pour rendre plus clair le rapport entre la position {x,y} de notre message et sa forme typographique, nous
avons également dessiné dans l'illustration ci-dessus une petite croix pour rendre plus explicite la façon dont
Processing positionne l'écriture :
PFont police;
police = loadFont("[Link]");
textFont(police);
Tout comme les rectangles, qui peuvent se dessiner depuis leur point supérieur gauche, depuis leur centre,
ou depuis ses quatre extrémités, l’écriture du texte peut également être positionnée à partir de plusieurs
points d'origine. Par défaut, le texte s'écrit depuis la ligne de base du texte, c'est-à-dire le point en bas à
gauche du texte, mais au-dessus des caractères descendants comme les lettres « y » ou « j ».
Vous pouvez changer la façon dont Processing alignera ce texte, en se servant de la fonction textAlign() :
size(500,250);
PFont police;
police = loadFont("[Link]");
textFont(police,24);
line(250,0,250,500);
line(0,125,500,125);
textAlign(RIGHT,TOP);
text("right+top", 250, 125);
textAlign(RIGHT,BASELINE);
text("right+baseline", 250, 125);
textAlign(LEFT,CENTER);
text("left+center", 250, 125);
Grâce aux transformations, il va être possible de déplacer cette origine, mais aussi de redéfinir l'orientation
des axes et même de changer la graduation de ces axes (on parle de changement d'échelle).
Par défaut, lorsque l'on dessine une forme (dans notre exemple un rectangle), Processing définit le repère
suivant :
size(200, 200);
noStroke();
fill(0);
rect(0, 0, 100, 100);
Déplacer
Le changement de la position de l'origine se fait par la commande translate(). Nous pouvons nous déplacer
sur l'axe x (« horizontalement ») et sur l'axe y (« verticalement ») et nous allons indiquer à translate() de «
combien » nous voulons nous déplacer sur chacun des axes. Dans l'exemple suivant, nous déplaçons
l'origine de notre repère de 50 pixels en x et de 50 pixels en y. Notons que translate() va seulement affecter
les formes géométriques qui sont dessinées après cette instruction.
size(200, 200);
noStroke();
fill(0);
translate(50, 50);
rect(0, 0, 100, 100);
size(200,200);
// Noir
fill(0);
translate(20,20);
rect(0,0,40,40);
// Gris
fill(128);
translate(60,60);
rect(0,0,40,40);
// Blanc
fill(255);
translate(60,60);
rect(0,0,40,40);
Tourner
Nous avons pu déplacer l'origine du repère de dessin. Nous allons maintenant appliquer une rotation sur les
axes de notre repère. Grâce à la commande rotate(), les axes x et y peuvent changer d'orientation. rotate()
prend en paramètre un nombre qui va représenter l'angle de rotation, c'est-à-dire de « combien » nos axes
vont tourner par rapport à notre fenêtre. Des valeurs positives indiquent une rotation dans le sens des
aiguilles d'une montre.
Processing permet de passer de transformer une unité en une autre grâce aux fonctions radians() et degrees().
Illustrons la fonction rotate() par un exemple simple. Nous allons faire pivoter un carré autour de l'origine.
size(200, 200);
noStroke();
fill(0);
rotate(PI/4);
rect(0, 0, 100, 100);
Comme pour translate(), rotate() se place avant les formes géométriques à dessiner. Il est possible de
combiner ces changements d'orientations, qui vont s'accumuler.
size(200,200);
smooth();
translate(width/2, height/2);
for (int i=0;i<360;i+=30){
rotate(radians(30));
quad(0, 0, 30, 15, 70, 60, 20, 60);
size(200,200);
scale(1.5);
rect(0,0,100,100);
size(200,200);
scale(1.0,1.5);
rect(0,0,100,100);
Comme pour rotate() et translate(), l'enchainement de scale() permet d'accumuler les mises à l'échelle.
Illustrons cette propriété par le sketch suivant, qui reprend l'idée des poupées russes en emboitant des carrés
par le jeu des scale() successifs.
// Noir
fill(0);
scale(1);
rect(0,0,200,200);
// Gris
fill(128);
scale(0.5);
rect(0,0,200,200);
// Blanc
fill(255);
scale(0.5);
rect(0,0,200,200);
Lorsqu'on utilise plusieurs types de transformations, leur ordre d'écriture va être important. Lorsque vous
êtes en voiture, « tourner à gauche » puis « continuer tout droit » est différent de « continuer tout droit » puis
« tourner à gauche ». Vous n'arrivez pas forcément au même endroit en suivant successivement ces deux
instructions. C'est la même chose pour les transformations dans Processing.
translate(100,0);
rotate(PI/5);
rect(0,0,100,100);
size(200,200);
smooth();
fill(0);
rotate(PI/5);
translate(100,0);
rect(0,0,100,100);
Nous allons utiliser pour cela deux fonctions qui s'utilisent toujours par paire : pushMatrix() et popMatrix().
Nous verrons en fin de chapitre pourquoi ces deux fonctions portent un nom si bizarre.
Pour les deux exemples qui suivent, nous allons identifier les transformations suivantes :
size(200,200);
smooth();
rectMode(CENTER);
// Sauvegarde de A
pushMatrix();
// Transformation B
rotate(PI/4);
// Restauration A
// A ce point-là, notre repère revient au centre de l'écran
popMatrix();
Il est possible d'imbriquer les sauvegardes de transformations, c'est-à-dire qu'à l'intérieur de n'importe quelle
paire de pushMatrix()/popMatrix() nous pouvons rappeler ces fonctions pour sauver l'état de la
transformation courante.
Reprenons l'exemple précédent en plaçant une paire pushMatrix()/popMatrix() qui encadre la première
transformation translate(width/2, height/2).
size(200,200);
smooth();
rectMode(CENTER);
noStroke();
// Sauvegarde de A
pushMatrix();
// Transformation B
translate(width/2,height/2);
// Sauvegarde de B
pushMatrix();
// Transformation C
rotate(PI/4);
// Restauration de B
popMatrix();
// Restauration de A
popMatrix();
Transformer en 3D
Toutes les transformations que nous venons d'aborder sont applicables en trois dimensions (3D). Processing
permet de passer en 3D au moment de l'appel à size() :
size(300,300,P3D);
Dans ce mode, Processing définit un axe z qui pointe vers le fond de l'écran.
Les transformations de déplacement et de mise à l'échelle vont s'écrire en intégrant un troisième paramètre.
Par exemple, pour se déplacer au centre de l'écran le long de x et y puis dessiner les formes comme si elles
étaient éloignées de nous, nous pourrions écrire la ligne de code suivante :
Pour les rotations, nous disposons de trois fonctions : rotateX, rotateY et rotateZ qui permettent
respectivement de tourner autour des axes x, y et z.
Processing intègre des fonctions de dessin de formes simples en 3D, notamment les cubes et les sphères.
Nous allons créer un cube dont la rotation autour des axes x et y va être paramétré par la position de la
souris.
void setup() {
size(200,200,P3D);
}
void draw() {
background(128);
rx = map(mouseX, 0,width,-PI,PI);
ry = map(mouseY, 0,height,-PI,PI);
translate(width/2,height/2,z);
rotateX(rx);
rotateY(ry);
box(30);
}
Dans ce sketch, nous avons introduit une nouvelle fonction map(), qui permet de transformer une valeur
d'une plage de valeurs à une autre plage de valeurs. Voici un exemple simple pour expliquer ce concept :
float v = 100;
float m = map(v,0,200, 0,1); // m vaut 0.5
Dans cet exemple, map()va transformer la valeur 100 qui est dans l'intervalle [0;200] et calculer la valeur
équivalente dans l'intervalle [0;1]. La valeur 0.5 est retournée dans m.
Dans notre sketch, cette fonction permet de transformer la valeur de mouseX dans l'intervalle situé entre 0 et
width en une valeur équivalente dans l'intervalle entre -PI et PI.
Les concepts de pushMatrix() et popMatrix() sont aussi applicables en 3D pour sauvegarder et restaurer les
transformations. C'est le meilleur moyen pour dessiner des univers en 3D, contenant plusieurs objets en
mouvement les uns par rapport aux autres sans avoir recours à des concepts mathématiques complexes.
Toutes les transformations dans Processing sont stockées dans un tableau de 16 nombres qui est appelé
matrice ou matrix en anglais. Ces nombres sont directement modifiés par des appels aux fonctions de
transformations. Si vous êtes curieux, vous pouvez imprimer ce tableau par la fonction printMatrix().
Il existe différents type de variables : des nombres entiers (int), des nombres à virgule (float), du texte
(String), des valeurs vrai/faux (boolean). Un nombre à décimales, comme 3,14159, n'étant pas un nombre
entier, serait donc du type float. Notez que l'on utilise un point et non une virgule pour les nombres à
décimales. On écrit donc 3.13159. Dans ce cas, les variables peuvent être annoncées de cette manière :
float x = 3.14159;
int y = 3;
Le nom d'une variable peut contenir des lettres, des chiffres et certains caractères comme la barre de
soulignement. À chaque fois que le programme rencontre le nom de cette variable, il peut lire ou écrire dans
ce compartiment. Les variables qui vont suivre vous donneront des exemples simples de leur utilisation.
Pour résumer, une variable aura un type, un nom et une valeur qui peut être lue ou modifiée.
int
Dans la syntaxe de Processing, on peut stocker un nombre entier, par exemple 3, dans une variable de type
int.
int entier;
entier = 3;
print(entier);
float
Il s'agit d'un nombre avec décimales, par exemple 2,3456.
float decimal;
decimal = PI;
print(decimal);
double
Il s'agit également de nombre avec décimales, mais qui fournissent davantage de précision que le type float.
double long_decimal;
long_decimal = PI;
print(long_decimal);
boolean vraifaux;
vraifaux = true;
println(vraifaux);
char
Cette variable sert à stocker un caractère typographique (une lettre). Notez l'usage de ce qu'on appelle des
guillemets simples.
char lettre;
lettre = 'A';
print(lettre);
string
Cette variable sert à stocker du texte. Notez l'usage des guillemets doubles.
String texte;
texte = "Bonjour!";
print(texte);
color
Sers à stocker une couleur. Cette variable est utile lorsqu'on veut réutiliser souvent les mêmes couleurs.
noStroke();
color blanc = color(255, 255, 255);
color noir = color(0, 0, 0);
Comparaison
La base de la condition, c'est la comparaison. Avant de pouvoir agir selon une condition, il faut d'abord
formuler la question que Processing doit se poser. Cette question sera quasiment toujours une question de
comparaison.
Si le résultat de la question est « oui », Processing exécutera une suite d'instructions. Si la réponse est non, il
exécutera une autre. Dans Processing, ce oui/non s'écrit « true » et « false ».
La syntaxe d'une condition est la suivante: if (TEST) { }. Le TEST correspond à l'opération (égalité, plus
petit, plus grand) que vous aurez choisie pour comparer deux valeurs et déterminer si la réponse à la
question est true ou false. Si la réponse est true, Processing exécutera les instructions entre les deux
accolades. L'instruction else permet de gérer le cas de figure dans lequel la condition n'est pas validée. Elle
exécute elle aussi tout ce qui se trouve à l'intérieur de ses accolades. Vous pouvez mettre autant
d'instructions que vous voulez entre ces deux types d'accolades.
Egalité
Pour vérifier l'égalité de deux valeurs, on utilise la formule suivante: if (valeur1 == valeur2) { }.
L'exemple suivant écrit "Il est midi" dans la console si la méthode hour() donne la valeur 12.
if (hour() == 12) {
println("Il est midi !");
} else {
println("Ce n'est pas midi !");
}
On peut vérifier qu'une valeur est plus petite ou plus grande qu'une autre en utilisant les opérateurs < et >.
L'exemple suivant va écrire dans la console si nous sommes le matin ou non.
La boucle for
Ce type de boucle permet de répéter une série d'instructions un nombre de fois défini. Elle incorpore une
variable qui va s'incrémenter à chaque passage dans la boucle. On utilise souvent i comme nom pour la
variable interne de la boucle. Elle comprend : un nombre de départ, un nombre maximal et une
incrémentation. Sa syntaxe est la suivante : for (int i = NombreDeDépart; i < NombreMaximal; i =
i + INCREMENT) { }.
L'exemple ci-dessous va afficher des rectangles blancs côte à côte qui auront chacun 10 pixels de large sur
toute la largeur de l'espace de dessin. Ils seront espacés de 5 pixels. Nous allons afficher le premier rectangle
aux coordonnées 0,0. Les suivants seront affichés aux coordonnées 15,0 puis 30,0 et ainsi de suite. Notre
boucle va incrémenter sa variable de 15 pixels à chaque étape. Comme nous voulons remplir toute la largeur
de l'espace de dessin, la valeur maximale sera égale à la largeur (width) de cette fenêtre de visualisation.
Les boucles for peuvent aussi être utilisées comme des compteurs. On leur donne un minimum, un
maximum et on incrémente la variable seulement de 1 à chaque étape de la boucle : ceci permet de compter
le nombre de fois que les instructions seront exécutées, d'où l'expression de compteur.
Cette méthode implique davantage de calculs mathématiques pour exploiter la variable au sein de la boucle.
Nous voyons dans l'exemple ci-dessus que les rectangles sont empilés les uns sur les autres. Puisque notre
variable i aura des valeurs de 0 à 5 et que nous l'utilisons telle quelle pour placer les rectangles dans
l'espace, ceux-ci seront placés aux coordonnées 0,0 ; 1,0; 2,0; 3,0; 4,0. Seul le dernier sera entièrement
visible. Pour obtenir le même résultat que l'exemple précédent, il faut multiplier la variable. Dans le cas
présent nous allons la multiplier par 15 (10 pour la largeur du rectangle et 5 de marge). Ils sont ainsi
disposés tous les 15 pixels. Nous pourrions également utiliser le chiffre du compteur pour réaliser d'autres
opérations.
Boucle de départ
Deux boucles
translate(7, 7);
Trois boucles
Dans cet exemple nous introduisons un espace 3D. Pour placer nos rectangles dans la profondeur, nous
devons utiliser la méthode translate().
translate(7, 7);
Voici une série de variations des exemples ci-dessous qui utilisent les méthodes fill(), scale() ou
rotate(). A vous d'expérimenter les transformations au sein de boucles.
Les listes permettent de stocker un nombre fixé d'avance de données ou d'objets dans une même variable.
Au lieu de créer 20 variables pour stocker 20 valeurs différentes d'un même genre, nous pouvons créer un
seul contenant pour ces 20 valeurs et y accéder une par une via cette seule et unique variable.
Le signe du double crochet signifie qu'il ne s'agit plus d'une variable avec un seul entier à l'intérieur, mais
d'une liste d'entiers avec plusieurs valeurs à l'intérieur. Ensuite nous remplissons cette liste dénommée
numbers (nous aurions très bien pu lui donner un autre nom) avec les valeurs notées entre les accolades.
L'ordinateur créera assez d'emplacements dans la mémoire et placera chacune des valeurs dans les cases
correspondantes :
C'est d'ailleurs pour cette raison qu'il faut indiquer le mot int, car Processing a besoin de connaître la taille
de chaque case de la liste (dans ce cas précis, nous lui indiquons à l'aide de cette instruction qu'il s'agit de
nombres entiers). S'il s'agissait d'images, comme on le verra plus loin, chaque case de la liste aurait besoin
de davantage de place.
Déclarer une liste se fera donc le plus souvent de la manière suivante : type[] nomDeLaListe = new
type[NOMBRE D'ÉLÉMENTS]. L'exemple ci-dessous crée une liste de trois nombres entiers. Attention ! Au
moment où la liste dénommée numbers est créée, celle-ci est constituée d'une suite de cases vides qui ne
contiennent aucune valeur.
Le chiffre 3 entre accolades indique que nous créons une liste de 3 cases actuellement vides.
Remplir la liste
Placer des valeurs dans une liste fonctionne de la même manière qu'assigner une valeur à une variable. Il
faut en plus préciser à quelle position de la liste on ajoute la valeur.
numbers[0] = 90;
numbers[1] = 150;
numbers[2] = 30;
La première position de la liste commençant par 0, si nous créons une liste de 3 valeurs, les cases les
contenant seront donc numérotées de 0 à 2. On passe d'une position de la liste à une autre en l'incrémentant
de 1.
println( numbers[0] );
A nouveau, notez que l'ordinateur commence à compter à la position 0 et non pas 1. Si nous demandons la
valeur numbers[2], Processing nous donnera la valeur à la troisième position et non pas à la deuxième. Un
bon moyen pour se rappeler cette particularité, c'est de considérer que Processing compte de la manière
suivante : zérotième, premier, deuxième, troisième, etc. La zérotième valeur concerne la valeur au début de
la liste.
numbers[0] = 90;
numbers[1] = 150;
numbers[2] = 30;
int somme = 0;
println(somme);
Le programme devrait afficher le résultat suivant dans votre console, tout en bas de la fenêtre Processing :
Ensuite, nous enclenchons une boucle qui se répétera 3 fois, en additionnant à chaque fois la prochaine
valeur à la somme. Ici nous pouvons voir la relation étroite qui existe entre une liste et une boucle for(). La
valeur i permet de passer une à une dans chacune des valeurs de la liste, en commençant avec la position
zéro, ensuite la position 1, et enfin la position 2.
Si vous vous mettez à analyser le code de programmes consultables en ligne, par exemple dans les sketchs
librement mis à disposition sur OpenProcessing, vous verrez beaucoup de code avec « quelqueChose[i] ».
PImage photo1;
photo1 = loadImage("photo_1.png");
image(photo1,0,0);
PImage photo2;
photo2 = loadImage("photo_2.png");
image(photo2,50,0);
PImage photo3;
photo3 = loadImage("photo_3.png");
image(photo3,100,0);
PImage photo4;
photo4 = loadImage("photo_4.png");
image(photo4,150,0);
PImage photo5;
photo5 = loadImage("photo_5.png");
image(photo5,200,0);
Certes, cet exemple reste encore relativement gérable dans la mesure où vous faites appel à seulement 5
images. Cela étant, les occasions d'erreurs de saisie sont nombreuses. En écrivant ces quelques lignes pour
ce manuel, nous-mêmes avons plusieurs fois effectué des erreurs de frappe, notamment en oubliant de
changer un chiffre que nous venions de copier d'une ligne précédente !
Une meilleure façon d'écrire cet exemple serait d'utiliser des listes :
images[0] = loadImage("image_0.png");
images[1] = loadImage("image_1.png");
images[2] = loadImage("image_2.png");
images[3] = loadImage("image_3.png");
images[4] = loadImage("image_4.png");
En utilisant une liste, on peut mettre toutes nos images dans une seule variable qui doit être initialisée qu'une
seule fois : PImage[] images = new PImage[5]. Ensuite, il suffit de remplir chaque valeur de fichier pour
chacun des emplacements dans la liste.
Mais même cette écriture est trop longue. Comment allez-vous faire, par exemple, lorsque vous aurez 200
images, voire 2.000 ? Allez-vous vraiment écrire 200 fois toutes ces lignes ? Et comment ferez-vous lorsque
vous voudrez changer le nom des fichiers importés ?
size(500,500);
En utilisant une répétition for(), nous pouvons désormais importer autant d'images que nous voulons.
Tout d'abord, nous créons la liste d'images. Il s'agit au départ d'une liste vide :
Ensuite nous récupérons la longueur de cette liste en demandant à la liste elle-même combien d'éléments elle
contient via [Link]() et utilisons cette longueur dans la répétition for().
Nous pouvons même automatiser l'importation des images en utilisant la valeur i pour composer le nom du
fichier des images dans le dossier data. En utilisant le signe « + », on peut concaténer deux mots ensemble,
ce qui veut dire que nous allons assembler deux mots/signes en un seul message.
En concaténant les mots « image_ », la valeur de la variable i, et « .png », nous obtenons un message qui
ressemblerait à quelque chose comme « image_42.png ». De cette manière, nous pouvons utiliser une seule
ligne de code pour faire rentrer autant d'images que nous voulons. Si la variable i contient la valeur de 9, le
nom du fichier importé sera image_9.png. Si la variable i contient la valeur 101, le nom du fichier importé
sera image_101.png.
Pour que cette technique marche, il faut juste préparer au préalable des fichiers d'images dans votre dossier
data. Voici, par exemple, un dossier data contenant 20 fichiers d'images :
A l'aide de l'instruction random, cette ligne de code affiche une image (0, 1, 2, 3, ...) qui sera placée à chaque
fois de façon aléatoire sur l'axe x et sur l'axe y de l'espace de dessin. Les deux valeurs width et height
permettent de connaître automatiquement la taille de la fenêtre de visualisation utilisée par le sketch. En
faisant appel à elles, on précise les limites verticales et horizontales maximales où doivent se positionner les
images, l'instruction random() ayant pour fonction de générer un nombre au hasard ne dépassant pas la
valeur mentionnée entre ses parenthèses.
Vous pouvez accéder directement aux pixels d'une image en demandant un accès direct à sa sous-variable
nommée « pixels ».
Imaginons que nous avons au départ l'image d'une mystérieuse dame dans un fichier nommé [Link]
size(512,256);
PImage lhooq;
lhooq = loadImage("[Link]");
image(lhooq,0,0);
int x = 119;
int y = 119;
noStroke();
fill(c);
rect(256,0,256,256);
stroke(0);
line(x-5,y,x+5,y);
line(x,y-5,x,y+5);
Les deux lignes les plus importantes sont soulignées en gras dans le code :
Ce que nous voyons comme une liste à deux {x,y} dimensions, PImage la voit en une seule dimension. Si
nous voulons trouver une valeur à la position {2,1}, en réalité il faut indiquer que nous voulons la position
17 de l'image. En effet, entre un point sur une ligne et le point correspondant sur la prochaine ligne, il existe
16 pixels. Autrement dit, PImage doit compter 16 pixels chaque fois qu'il veut descendre une ligne.
C'est pour cette raison que la formule pour identifier un pixel dans une image s'écrit {x + (largeur image} *
y}. Pour chaque ligne y, il existe une largeur de valeurs x qu'il faut dépasser.
Dans cet exemple, on dessine une grille de trois pixels par trois. Nous allons dessiner cette image plus
grande en l'étirant à 80 x 80 pixels afin de mieux la voir.
Notez également que vous pourriez aussi réaliser ce genre de peinture à numéro en utilisant des répétitions.
Les applications créatives des listes sont multiples. Il ne vous reste plus qu'à laisser le champ libre à votre
imagination.
Vous connaissez déjà plusieurs méthodes, mais uniquement en tant qu'utilisateur. Par exemple, rect(),
ellipse(), line() stroke() sont toutes des méthodes. En créant nos propres méthodes, nous nous
rapprochons d'une certaine manière du rôle créatif des concepteurs de Processing : liberté nous est donnée
d'inventer des formes ou des fonctionnalités qu'ils n'ont pas pu ou voulu écrire à l'origine.
Voici un exemple purement théorique de ce que la structuration d'un sketch à l'aide de méthodes pourrait
éventuellement donner au final si nous devions dessiner un joli paysage.
background(255);
joliPaysage();
arbre(cypres, 0,300);
lune(400,100);
gazon(0,300,width,100);
mouton(50,133);
mouton(213,98);
mouton(155,88);
L'objectif, c'est de regrouper des éléments complexes du programme dans des mots clés que vous pouvez
appeler autant de fois que vous le voulez, tout en les mélangeant avec les mots clés Processing. Ce procédé
appelé encapsulation vous éloigne apparemment de votre code, mais c'est pour vous en donner un nouvel
accès simplifié en le rendant davantage lisible. Cela permet également d'éviter les répétitions inutiles. Un
peu plus d'ordre, pour un peu moins de copier-coller.
Processing nous fournit déjà plusieurs méthodes que nous pouvons remplacer par nos propres versions. Ce
sera le cas des méthodes draw(), setup(), mousePressed()... que vous découvrirez dans d'autres chapitres.
Nous pouvons également créer des méthodes sur mesure en leur donnant le nom de notre choix. Dans ce cas,
il faut simplement éviter d'utiliser un nom qui est déjà pris.
Décomposer
Jusqu'ici, nous avons programmé dans Processing directement, en commençant à saisir du code depuis le
haut du programme et en laissant celui-ci s'exécuter jusqu'en bas. Lorsque nous voulons construire nos
propres méthodes, nous devons commencer à décomposer nos programmes en plusieurs parties séparées.
Cela nous permettra par exemple d'indiquer les parties qui doivent s'exécuter tout de suite lorsque nous
appuyons sur le bouton run de celles qui seront appelées par nos propres soins à l'intérieur du programme.
Par contre, en utilisant ce procédé de programmation, nous ne pourrons plus écrire des instructions
directement dans Processing sans au préalable les avoir intégrées au sein d'une méthode ou d'une classe.
Avec les méthodes, c'est tout ou rien.
void setup()
Processing nous offre une instruction ayant pour fonction de contenir le code de début de notre programme.
Il s'agit de la méthode setup() :
void setup() {
C'est à l'intérieur des accolades de la méthode setup() que nous allons placer tout le code qui doit être
exécuté au début de notre programme. Pour l'instant, ne cherchez pas à savoir à quoi sert le mot void,
sachez juste qu'il faut l'écrire, suivi du mot setup, puis de parenthèses, et enfin les accolades.
La plupart du temps, nous nous servirons de la méthode setup() pour définir la taille de notre sketch. Cette
taille ne peut être définie qu'une seule fois — ce qui tombe bien, car le démarrage n'a lieu qu'une seule fois
dans le vie d'un programme.
void setup() {
size(500,500);
}
void setup() {
size(600, 220);
background(153,204,255);
smooth();
void dessinerMouton() {
strokeWeight(3);
strokeJoin(ROUND);
stroke(0);
fill(255);
beginShape();
vertex(100, 40);
vertex(120, 20);
vertex(120, 60);
vertex(100, 80);
endShape(CLOSE);
fill(0);
ellipse(40, 60, 5, 5);
ellipse(60, 60, 5, 5);
ellipse(80, 60, 5, 5);
}
Le début de ce programme se décrit à l'intérieur de la méthode setup(). En effet, puisque nous utilisons une
méthode pour dessiner notre mouton, le reste du programme doit également être placé quelque part dans une
méthode. En début du programme, nous allons donc saisir :
void setup() {
}
Ensuite, au sein des accolades de la méthode setup(), nous définissons la taille de notre sketch et sa couleur
de fond.
size(600, 220);
background(153,204,255);
Processing page 72 / 155
Vous vous êtes peut-être posé la question du rôle de smooth() dans notre programme. Optionnelle, cette
ligne de code permet toutefois d'améliorer le rendu des lignes en lissant leur tracé : elles apparaissent ainsi
plus jolies sur l'écran de l'ordinateur.
smooth();
Enfin, nous dessinons notre mouton, en faisant appel à une méthode que nous avons définie plus bas dans le
programme.
dessinerMouton();
Chaque fois que Processing tombe sur le mot dessinerMouton(), il vérifie si ce mot existe en tant que
méthode quelque part dans le programme. Si cette méthode existe, il fait un détour par cette méthode et fait
tout ce qui s'y trouve.
S'il ne trouve pas cette méthode — et qu'elle n'existe pas ailleurs dans la liste des fonctionnalités proposées
directement par Processing —, votre programme s'arrêtera avec une erreur d'exécution.
Notez que vous pouvez écrire le mot clé dessinerMouton() autant de fois que vous voulez. Ici, dans ce
programme, dessinerMouton() est écrit au final 4 fois :
dessinerMouton();
translate(120, 60);
dessinerMouton();
translate(120, 60);
dessinerMouton();
translate(140, -60);
dessinerMouton();
void dessinerMouton() {
/* ... */
Enfin nous arrivons à notre méthode dessinerMouton() proprement dite. C'est ici que nous dessinons les
lignes et formes nécessaires pour obtenir le tracé de notre animal. Nous ne commenterons pas cette partie,
puisqu'il s'agit uniquement d'instructions que vous trouverez davantage décrites dans le chapitre sur les
formes.
Notez l'usage du mot-clé void devant le nom de notre méthode. Cela signifie qu'elle ne retourne rien. En
faisant appel à elle, nous savons qu'elle n'a pas pour fonction de nous fournir des données.
L'emploi d'une méthode avec une valeur de retour suppose que nous cherchons à obtenir quelque chose
d'elle en l'invoquant. Quand nous voulons savoir quelle heure est-il, nous demandons aux méthodes
second(), minute(), ou hour() de nous donner en retour leurs valeurs sous forme d'un chiffre entier (int).
Si ces méthodes ne nous donnaient rien (void) en retour, elles ne serviraient pas à grande chose.
Pour les méthodes qui doivent retourner une valeur à celle qui l'appelle, on indique un mot-clé avant pour
indiquer le type de valeur qui doit être retourné. Une méthode dont le type est int nous retourne une valeur
de type int correspondant à un nombre entier, une méthode dont le type est float nous retourne une valeur
de type float (nombre à virgule), et ainsi de suite.
Voici un exemple de méthode qui nous donne le nombre secondes depuis 00:00:00 ce matin.
int secondesAujourdhui() {
return hour() * 3600 + minute() * 60 + second();
}
void draw() {
println( secondesAujourdhui() );
}
Même si vous ne connaissez pas la méthode draw(), amusez-vous néanmoins à exécuter ce mini-
programme et regardez les informations qui s'affichent dans la console située en bas de votre fenêtre
d'édition de Processing. Vous verrez que la méthode draw() appelle en permanence la méthode
secondesAujourdhui() et utilise le résultat de cette méthode pour nous afficher les secondes.
multiplier(2, 2);
Une fois arrivé dans le corps de la méthode, Processing peut accéder à leur valeur, comme il le fait avec les
variables.
Ainsi dans l'exemple ci-après, lorsque cette méthode est appelée avec les argument 2 et 2, la valeur de a =
2, et celle de b = 2 également. La valeur de retour de cette méthode sera donc 4 (2 fois 2 égale 4).
Notez que c'est la position des arguments qui détermine quelle valeur sera affectée à quel argument.
Pour résumer notre exemple, on a créé une méthode qui retourne le résultat de la multiplication de ses deux
arguments. Un commentaire précède la définition de la méthode (une bonne pratique de programmation
pour se rappeler ultérieurement de la fonction d'un morceau de code).
/*
* Retourne le résultat de la multiplication de ses
* deux arguments.
*/
int multiplier(int a, int b) {
return a * b;
}
void setup() {
int resultat = multiplier(2, 2);
print(resultat);
}
Les variables — que ce soit des objets ou des types fondamentaux de données — ne sont pas forcement
accessibles à l'ensemble de votre programme ! Tout dépend de l'endroit où elles ont été déclarées. Une
variable déclarée à l'intérieur d'une méthode ne sera accessible que dans celle-ci :
void setup() {
int x = 10;
}
void draw() {
/* Le programme générera une erreur car la variable x
* n'existe qu'à l'intérieur de la méthode setup()
*/
x = x + 1;
}
Pour qu'une variable soit accessible à tout votre programme il faut la déclarer en en-tête comme ceci :
int x;
void setup() {
x = 10;
}
void draw() {
x = x + 1;
}
Ne vous inquiétez pas si ces définitions vous paraissent obscures à première lecture. Au fil de ce chapitre,
nous allons détailler ces notions à l'aide d'un exemple simple et concret : le tracé d'une puis de deux balles
(de simples cercles) à l'écran. Pour réaliser ce dessin, nous faisons appel à un modèle de balle (l'objet) et à
ses copies (les instances) qui possèdent chacune des caractéristiques différentes.
afficher
si l'on veut modifier ou ajouter des actions à l'ensemble de ces balles, on devra modifier autant de
fois le code qu'il y a d'éléments affichés,
au fur et à mesure que l'on rajoute des éléments à l'écran le programme s'allonge au point de devenir
ingérable (et si notre programme comportait 1'000'000 de balles ?).
Pour pallier à ces limitations, nous allons transformer notre balle en objet. Dès qu'une entité (balle, avatar,
forme, etc.) de votre programme devient trop complexe ou qu'elle doit exister en plusieurs exemplaires, il
faut en faire un objet.
Créer un objet
La création d'un objet se passe en deux étapes : la définition du modèle de l'objet et la création d'une copie
unique de l'objet (instance).
Le modèle
Processing utilise le mot clé class pour définir un objet. Sa syntaxe s'apparente à la définition d'une
méthode : class nomObjet {}. Toutes les caractéristiques et les actions sont écrites à l'intérieur. En
général on va écrire la définition d'un objet tout à la fin de notre code. Éventuellement si l'objet est
complexe, on créera un nouvel onglet dans la fenêtre d'édition de Processing (un nouveau fichier) afin de le
séparer du reste du code.
class Balle {
}
L'instance
Une fois le modèle défini, il faut créer une copie de ce modèle qui sera unique. Processing utilise le mot clé
new pour créer une instance d'un objet : new nomObjet();. Il faut stocker cet objet dans une variable afin
de pouvoir le manipuler ultérieurement.
Dans l'exemple ci-dessus, nous déclarons une variable maBalle et nous lui assignons une copie de l'objet
Balle. maBalle fait référence à cet objet et permet d'agir sur lui dans la suite du programme. Afin de rendre
l'objet disponible dans tout le programme, nous plaçons la déclaration en en-tête de l'application.
Les caractéristiques
Les objets ont des caractéristiques qui les définissent et les rendent uniques. Ce sont des variables qui sont
déclarées au début de l'objet.
Pour modifier une caractéristique après la création de l'objet, il faut procéder de la manière suivante:
[Link]éristique = valeur; Par exemple :
maBalle.x = 100;
Le constructeur
Le constructeur est une méthode appelée lorsque l'objet est créé. Il est l'équivalent de la méthode setup()
de l'application. Il porte toujours le nom de l'objet. Le constructeur va prendre un certain nombre de
variables en paramètre et les assigner à l'objet :
class Balle {
//Déclaration des paramètres de base de la balle
float x;
float y;
color couleur;
Lorsque nous allons créer l'instance (une copie) de l'objet, nous allons directement lui donner ses
caractéristiques propres en paramètre. L'exemple ci-dessous crée une balle blanche placée aux coordonnées
100, 100 de la fenêtre de visualisation.
Attention ! Nous venons uniquement de créer une copie du modèle de l'objet. Il n'est pas encore affiché à
l'écran.
Les actions
Les actions d'un objet représentent les différentes choses qu'il peut effectuer. Ce sont des méthodes
mentionnées (déclarées) à l'intérieur de l'objet. Appeler une action sur une instance d'un objet se fait de la
manière suivante: [Link]();
Dans notre exemple, notre balle comportera une seule action : être affichée. Nous allons utiliser les
instructions fill() et ellipse() pour la dessiner.
class Balle {
//Déclaration des paramètres de base de la balle
float x;
float y;
color couleur;
Pour afficher notre balle, il faut appeler sa méthode display() depuis sa copie dans la méthode draw() du
programme.
void draw() {
[Link]();
}
Programme final
void setup() {
smooth(); //Lissage des dessins
size(400, 200); //Taille de la fenêtre
}
void draw() {
background(0); //On dessine un fond noir
noStroke(); //On supprime le contour
class Balle {
//Déclaration des paramètres de base de la balle
float x;
float y;
color couleur;
//Constructeur de la balle
Balle (float nouvX, float nouvY, color nouvCouleur) {
x = nouvX;
y = nouvY;
couleur = nouvCouleur;
}
//Dessin de la balle
void display() {
fill(couleur);
ellipse(x, y, 40, 40);
}
}
void setup() {
smooth(); //Lissage des dessins
size(400, 200); //Taille de la fenêtre
}
void draw() {
background(0); //On dessine un fond noir
noStroke(); //On supprime le contour
class Balle {
//Déclaration des paramètres de base de la balle
float x;
float y;
color couleur;
//Constructeur de la balle
Balle (float nouvX, float nouvY, color nouvCouleur) {
x = nouvX;
y = nouvY;
couleur = nouvCouleur;
}
//Dessin de la balle
void display() {
fill(couleur);
ellipse(x, y, 40, 40);
}
}
N'hésitez pas à vous approprier ce programme en ajoutant autant de balles que vous voulez.
Processing offre deux manières distinctes de commenter son code : les commentaires en ligne, et les blocs
de commentaires multi-lignes.
Commentaires en ligne
Pour écrire un commentaire qui ne prend qu'une seule ligne, il suffit de placer les caractères // au début du
commentaire. Tout le texte qui est écrit à sa droite sur la même ligne sera considéré comme commentaire et
donc ne sera pas pris en compte par le programme lors de son exécution. Exemples de commentaires en
ligne :
void setup() {
// Définit la taille du programme
size(400, 300);
smooth(); // Active le lissage des contours
}
Blocs de commentaires
Si une explication nécessite un commentaire plus long, on peut l'écrire sur plusieurs lignes en le plaçant
entre les caractères /* et */. Par exemple :
/*
La méthode setup initialise le programme,
on peut y définir la taille de la fenêtre,
définir l'état initial du programme, etc.
*/
void setup() {
On peut commenter un bloc de ligne en allant dans le menu edit de Processing puis en cliquant sur
comment/uncomment. On peut procéder de même pour enlever le commentaire sur un bloc.
Lorsqu'un ensemble de lignes effectue une action commune (par exemple modifier deux variables x et y), on
évitera de mettre un commentaire pour chaque ligne et on utilisera de préférence un bloc de commentaires.
Par exemple :
Mais Processing n'est pas uniquement un environnement de dessin écrit, c'est également un environnement
interactif. Et pour qu'il y ait interactivité, il nous faut du temps, en d'autres termes, un moyen de prolonger
notre dessin pour que celui-ci puisse se modifier en suivant chronologiquement certaines étapes, selon
différents facteurs et conditions. C'est le rôle de la boucle infinie, appelée en permanence par la machine
pour réactualiser notre dessin. Dans Processing, cette boucle infinie s'écrit draw(). Elle est souvent
accompagnée par la méthode setup() qui permettra de préparer la fenêtre de visualisation (l'espace de
dessin), par exemple en lui donnant une taille au départ.
C'est l'absence de ces deux méthodes qui rend Processing inerte. Si votre code ne dispose pas de méthode
draw(), l'exécution du programme s'arrêtera à la fin du code de votre programme.
draw()
Commencez un nouveau programme Processing vide, tapez les lignes suivantes dans la fenêtre d'écriture et
appuyez sur le bouton run :
void draw() {
background( random(255) );
}
Ça y est, vous avez activé l'animation dans Processing. Vous devriez maintenant voir une fenêtre qui
clignote 30 fois par seconde avec une couleur grise aléatoire quelque part entre le noir et le blanc. C'est la
méthode random(255) qui donne en retour une valeur aléatoire entre 0 et 255. C'est cette valeur qui est
ensuite récupérée par les parenthèses de la méthode background() et appliquée sur le fond de la fenêtre de
visualisation de l'espace de dessin. Comme le tout se passe de manière répétée, on a l'impression d'assister à
une animation.
Par défaut, les instructions qui se trouvent entre les deux accolades de la méthode draw() seront appelées 30
fois par seconde. 30 fois par seconde Processing ouvrira cette méthode et regardera ce qui est écrit dedans
pour l'exécuter. Nous pouvons mettre autant d'instructions que nous voulons à l'intérieur de cette méthode.
Ces instructions seront jouées par Processing de manière cyclique, tel un métronome.
Attention aux erreurs d'écriture, car dès que Processing en rencontrera une, votre programme s'arrêtera net
— c'est la fin de votre animation. En revanche, si vous avez écrit une méthode draw() sans erreurs, elle sera
appelée en boucle, 30 fois par seconde, jusqu'à ce que l'utilisateur arrête le programme, qu'une panne
d'électricité arrive, ou que la fin du monde se produise. C'est donc grâce à cette méthode exécutant du code
en répétition que nous allons pouvoir créer des animations.
Processing page 82 / 155
Fréquence d'exécution
Il est possible de spécifier une valeur différente à notre métronome en utilisant la méthode frameRate().
Si vous modifiez l'exemple précédent comme suit, vous remarquerez que la vitesse de l'animation a été
diminuée (divisée par 3).
void draw() {
frameRate(10);
background( random(255) );
}
setup()
Souvent, voire la plupart du temps, il est nécessaire de placer certaines instructions au tout début du
programme. C'est la nature et la portée de ces instructions sur le programme qui nous incitent à les placer à
cet endroit. Par exemple, dans Processing, la taille de la fenêtre de visualisation du dessin ne peut être
définie qu'une seule fois dans un sketch ; ce paramétrage de l'espace de dessin ne peut donc être placé à
l'intérieur de la méthode draw() car cette méthode s'exécute plusieurs fois durant le déroulement du
programme.
A moins de se satisfaire de la dimension par défaut de 100x100 pixels, définir la taille de la fenêtre de
visualisation peut s'avérer très utile. C'est pour toutes ces raisons qu'une deuxième méthode complémentaire
a été créée : la méthode setup().
void setup() {
void setup() {
size(500, 500);
}
void draw() {
background(random(255));
}
Lorsque ce sketch est lancé, Processing exécute tout d'abord les instructions qui se trouvent à l'intérieur de la
méthode setup(). Ensuite, la méthode draw() commencera à être appelée de manière répétée, telle un
métronome.
Background()
Voici un programme qui remplit progressivement l'écran avec des ellipses.
void draw() {
ellipse(random(200), random(200), 20, 20);
}
Comme vous pouvez le constater dans les captures d'écran, cette animation finira par remplir notre espace de
dessin complètement par du noir. C'est peut-être l’œuvre conceptuelle ultime de toute notre carrière
artistique ; néanmoins il serait bien utile d'apprendre à animer une seule ellipse, la voir évoluer dans l'espace
ou changer de forme, sans que ses positions antérieures soient affichées en même temps.
Dans ce cas, il suffit d'ajouter un nettoyage de fond de l'espace de dessin à l'aide de la méthode
background(). Celle-ci prend une à trois valeurs de couleur, comme pour la méthode fill() ou stroke().
Voici une modification du programme qui permettra d'afficher maintenant une seule forme animée :
void setup() {
size(200, 200);
fill(0);
}
void draw() {
background(255);
ellipse( 100, 100, random(100), random(100));
}
En réalité, ce que nous demandons au programme, c'est 30 fois par seconde d'effacer l'intégralité de notre
dessin et de tracer une nouvelle forme par dessus avec un nouveau fond blanc.
Ajouter un fondu
Il existe une astuce, souvent utilisée dans la communauté des utilisateurs de Processing, qui consiste à
effacer le fond de l'image à l'aide d'un rectangle semi-transparent plutôt qu'avec l'instruction background().
Ce procédé permet d'obtenir un effet d'effacement graduel, de fondu.
void draw() {
fill(0, 0, 0, 20);
rect(0, 0, 200, 200);
fill(255);
ellipse(100 + random(-20,20), 100 + random(-20,20),
random(50), random(50));
}
Pour créer des animations, il faut savoir à quel moment nous nous trouvons par rapport à une ligne de temps.
Pour ce faire, nous pouvons soit utiliser l'heure qu'il est, soit compter (par exemple de un à dix).
void setup() {
size(60, 60);
noStroke();
}
void draw() {
background(0);
Les images sont dessinées les unes par-dessus les autres. L'appel à l'instruction background(0) remplit
l'espace de dessin avec la couleur définie en paramètre (le nombre 0 correspondant à du noir) ce qui revient
à chaque fois à effacer l'image précédente.
Par ailleurs, vous pouvez également avoir besoin de créer des animations cycliques dont la fréquence (le
nombre d'animations par cycle) s'adapte en fonction d'autres éléments, par exemple la taille de la fenêtre de
visualisation de l'espace de dessin. Pour déterminer à partir d'une valeur donnée ce nombre d'animations par
cycle, la solution la plus simple consiste à utiliser l'opérateur modulo %. En mathématique, le modulo permet
d'obtenir le reste d'une division par un nombre. Par exemple, l'expression println(109 % 10); affichera 9,
car 109 divisé par 10, donne 10 comme quotient et 9 comme reste. De manière plus générale, si on prend
deux nombres x et y, le reste de la division de x par y est strictement inférieur à y. L'opérateur modulo nous
permet donc de compter sans jamais dépasser un certain nombre (la base du modulo).
Dans le prochain exemple, nous allons utiliser la méthode millis() et l'opérateur % pour dessiner un cercle
qui parcourt très rapidement le sketch selon des trajectoires diagonales. Ce cercle laisse derrière lui une
traînée qui s'efface graduellement.
void setup() {
size(320, 240);
noStroke();
frameRate(60);
smooth();
}
void draw() {
fill(0, 0, 0, 10);
rect(0, 0, width, height);
fill(255);
ellipse(millis() % width, millis() % height, 20, 20);
}
L'effacement du dessin précédent s'effectue à l'aide d'un rectangle semi-transparent. Ce procédé permet
d'obtenir un effet de flou de mouvement contrairement à l'instruction background(). La présence de
l'instruction smooth() au début du programme s'explique par notre amour des courbes lisses.
Un conseil : basez vos animations sur la mesure du temps plutôt que sur le décompte du nombre d'images
dessinées. La vitesse de rendu peut très sensiblement se dégrader lorsque les capacités de l'ordinateur sont
occupées à gérer un compteur : les animations deviennent alors moins fluides, plus saccadées. Ces
limitations de performance n'existent pas lorsque l'on utilise les instructions associées à l'horloge interne de
l'ordinateur pour mesurer le temps qui passe.
Le code est relativement simple, le compteur d'images constituant l'essentiel du programme. A chaque degré
de rotation de la ligne correspond le numéro d'une image dessinée.
int compteur;
void setup() {
size(320, 240);
frameRate(60);
fill(0, 0, 0, 10);
stroke(255);
smooth();
compteur = 0;
}
void draw() {
compteur = compteur + 1;
int compteur;
void setup() {
size(320, 240);
frameRate(60);
fill(0, 0, 0, 10);
stroke(255);
smooth();
compteur = 0;
}
compteur = compteur + 1;
On spécifie ensuite le repère de l'espace de dessin pour dessiner au centre et on génère un rotation qui
dépend de compteur.
Une traine est visible dans l'animation. La superposition des lignes en s'effaçant graduellement donne un
effet moiré.
Le résultat final se présentera comme ci-dessous. Afin de mieux visualiser la trajectoire de la balle, nous
avons intégré dans l'animation un effet de traine.
Code de base
Comme point de départ, nous allons reprendre le programme de la balle du chapitre « Les objets » qui nous
permettait d'afficher une balle à l'écran et lui ajouter progressivement des morceaux de code. Les nouvelles
parties du sketch sont signalées en gras avec la mention //AJOUT ou //DEBUT AJOUT et //FIN AJOUT.
Pour vous familiariser avec le fonctionnement de ce nouveau programme, vous pouvez également copier
tout le bloc du code initial dans votre fenêtre d'édition de Processing et progressivement lui ajouter la classe
ou la méthode concernée.
void setup() {
smooth(); //Lissage des dessins
size(400, 200); //Taille de la fenêtre
}
void draw() {
background(0); //On dessine un fond noir
noStroke(); //On supprime le contour
class Balle {
//Déclaration des paramètres de base de la balle
float x;
float y;
color couleur;
//Constructeur de la balle
Balle (float nouvX, float nouvY, color nouvCouleur) {
x = nouvX;
y = nouvY;
couleur = nouvCouleur;
}
//Dessin de la balle
void display() {
fill(couleur);
ellipse(x, y, 40, 40);
}
}
Le déplacement
La balle doit pouvoir se déplacer sur les axes x et y. Nous allons créer deux variables dans le modèle de
l'objet qui caractériseront sa vitesse sur les axes x et y. Ensuite nous allons ajouter une nouvelle méthode
bouge() dans le modèle de l'objet qui sera appelée depuis la méthode draw() du programme. Cette méthode
va, à chaque fois que l'objet est affiché, modifier la position de la balle par rapport à sa vitesse. Il faudra
aussi initialiser les variables décrivant la vitesse dans le constructeur. Pour commencer, nous allons leur
donner une valeur fixe.
class Balle {
//Déclaration des caractéristiques de base de la balle
float x;
float y;
float vitesseX; //AJOUT
float vitesseY; //AJOUT
color couleur;
//Constructeur de la balle
Balle (float nouvX, float nouvY, color nouvCouleur) {
x = nouvX;
y = nouvY;
couleur = nouvCouleur;
vitesseX = 2; //AJOUT
vitessesY = 2; //AJOUT
}
//Dessin de la balle
void display() {
fill(couleur);
//DEBUT AJOUT
void bouge() {
x = x + vitesseX;
y = y + vitesseY;
//FIN AJOUT
}
Il faudra ensuite appeler la méthode bouge() depuis la méthode draw(). Par ailleurs, nous ajoutons un appel
à l'instruction background() pour effacer l'écran à chaque nouvelle image.
void draw() {
background(0); //On dessine un fond noir
noStroke(); //On supprime le contour
Les collisions
Pour le moment, dès que la balle touche le bord de l'écran, elle continue son chemin. Selon l'exemple de la
balle qui rebondit sur les coins de l'écran du chapitre « La ligne de temps », nous allons ajouter une méthode
testCollision qui inversera la vitesse de la balle lorsqu'elle touche les bords de l'écran.
class Balle {
//Déclaration des caractéristiques de base de la balle
float x;
float y;
float vitesseX;
float vitesseY;
color couleur;
//Constructeur de la balle
Balle (float nouvX, float nouvY, color nouvCouleur) {
x = nouvX;
y = nouvY;
couleur = nouvCouleur;
vitesseX = 2;
vitesseY = 2;
}
//Dessin de la balle
void display() {
fill(couleur);
ellipse(x, y, 40, 40);
}
void move() {
x = x + vitesseX;
y = y + vitesseY;
}
//DEBUT AJOUT
void testCollision() {
//Si la balle touche un mur, elle rebondit
if (x > width-20 || x < 20) {
Processing page 91 / 155
vitesseX = vitesseX *-1;
}
if (y > height-20 || y < 20) {
vitesseY = vitesseY * -1;
}
}
//FIN AJOUT
}
Code Final
Voici le code final, une fois toutes ces modifications effectuées.
void setup() {
smooth(); //Lissage des dessins
size(400, 200); //Taille de la fenêtre
}
void draw() {
fill(0, 0, 0, 1);
rect(0, 0, width, height);
noStroke();
class Balle {
//Déclaration des paramètres de base de la balle
float x;
float y;
float vitesseX; //AJOUT
float vitesseY; //AJOUT
color couleur;
//Constructeur de la balle
Balle (float nouvX, float nouvY, color nouvCouleur) {
x = nouvX;
y = nouvY;
couleur = nouvCouleur;
vitesseX = 2; //AJOUT
vitesseY = 2; //AJOUT
//Dessin de la balle
Processing page 92 / 155
void display() {
fill(couleur);
ellipse(x, y, 40, 40);
}
void bouge() {
x = x + vitesseX;
y = y + vitesseY;
}
void testCollision() {
//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;
}
}
}
N'hésitez pas à modifier certains paramètres du programme pour vous approprier davantage son
fonctionnement.
Dans le chapitre d'introduction aux objets, nous avons vu qu'on pouvait obtenir deux balles à l'écran
en déclarant une seconde copie de la balle et en l'affichant à son tour dans la méthode draw(). Ce
procédé devient toutefois lourd lorsque le nombre d'objets à reproduire est supérieur à deux.
Lorsqu'il y a plus de deux objets à animer, il est préférable d'utiliser des listes. Petit rappel du
chapitre consacré à cette notion : les listes permettent de gérer facilement un ensemble d'éléments
semblables que ce soit des chiffres, des images et même des objets.
Dans ce chapitre, nous allons poursuivre l'exemple de la balle rebondissante. Nous allons ajouter plusieurs
balles en utilisant des listes puis ajouter une méthode permettant de gérer les collisions entre les balles.
Code de base
Comme point de départ, nous allons reprendre le code de la balle du chapitre « Animer un objet » qui nous
permettait d'afficher une balle rebondissante à l'écran. Tout au long du chapitre, nous allons ajouter des
portions de code à l'exemple de base. Les nouvelles parties sont signalées en gras avec la mention //AJOUT
ou //DEBUT AJOUT et //FIN AJOUT. Pour vous familiariser avec le fonctionnement de ce nouveau
programme, vous pouvez également copier tout le bloc du code initial dans votre fenêtre d'édition de
Processing et progressivement lui ajouter la classe ou la méthode concernée.
void setup() {
smooth(); //Lissage des dessins
size(400, 200); //Taille de la fenêtre
}
void draw() {
noStroke();
class Balle {
//Déclaration des paramètres de base de la balle
float x;
float y;
float vitesseX; //AJOUT
float vitesseY; //AJOUT
color couleur;
//Constructeur de la balle
Balle (float nouvX, float nouvY, color nouvCouleur) {
x = nouvX;
y = nouvY;
couleur = nouvCouleur;
vitesseX = 2; //AJOUT
vitesseY = 2; //AJOUT
//Dessin de la balle
void display() {
fill(couleur);
ellipse(x, y, 40, 40);
}
void bouge() {
x = x + vitesseX;
y = y + vitesseY;
}
void testCollision() {
//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;
}
}
}
En premier lieu, nous allons déclarer une liste de balles et non plus une seule balle. Pour cela, nous allons
utiliser une variable nbreBalle pour stoker le nombre de balles utilisées dans le programme.
par
Processing page 95 / 155
//Déclaration d'une variable contenant le nombre de balles
int nbreBalle = 3;
Comme dans l'exemple des nombres entiers, nous venons uniquement de déclarer des copies du modèle de
balle. Il faut maintenant les créer dans le setup(). Nous allons dessiner trois balles au centre de l'écran.
Toutes les trois seront blanches.
void setup() {
smooth(); //Lissage des dessins
size(400, 200); //Taille de la fenêtre
//DEBUT AJOUT
//Cette boucle va créée trois balles
//blanches au centre de l'écran
for (int i = 0; i < nbreBalle; i++) {
balles[i] = new Balle(width/2, height/2, color(255));
}
//FIN AJOUT
}
Dans la méthode draw() , nous allons aussi créer une boucle qui va parcourir tous les éléments de la liste
pour les déplacer, tester leurs collisions et les afficher. Nous allons remplacer
par
Une dernière opération va consister à modifier le constructeur du modèle de la balle afin que chaque balle ait
une vitesse et une direction spécifiques. Pour ce faire nous allons utiliser la fonction random() qui permet de
générer des nombres aléatoires. Nous allons remplacer le constructeur ci-dessous :
//Constructeur de la balle
Balle (float nouvX, float nouvY, color nouvCouleur) {
x = nouvX;
y = nouvY;
couleur = nouvCouleur;
vitesseX = 2;
vitesseY = 2;
}
par celui-ci
//Constructeur de la balle
Balle (float nouvX, float nouvY, color nouvCouleur) {
x = nouvX;
y = nouvY;
couleur = nouvCouleur;
vitesseX = 2 + random(-1,1);
Code final
Voici le programme complet :
void setup() {
smooth(); //Lissage des dessins
size(400, 200); //Taille de la fenêtre
void draw() {
fill(0, 0, 0, 1); // Couleur avec transparence.
rect(0, 0, width, height);
noStroke();
class Balle {
//Déclaration des paramètres de base de la balle
float x;
float y;
float vitesseX;
float vitesseY;
color couleur;
//Constructeur de la 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 display() {
fill(couleur);
ellipse(x, y, 40, 40);
}
//Déplacement de la balle
void bouge() {
x = x + vitesseX;
y = y + vitesseY;
void testCollision() {
//Si la balle touche un mur, elle rebondit
if (x > width-20 || x < 20) {
vitesseX = vitesseX * -1;
}
if (y > height-20 || y < 20) {
vitesseY = vitesseY * -1;
}
}
}
N'hésitez pas à modifier certains paramètres du programme pour vous approprier davantage son
fonctionnement.
Dans ce chapitre, nous allons nous familiariser avec un minim de fonctionnalités audio disponibles par
défaut dans Processing.
Minim
Il a été décidé à un moment donné d'intégrer dans toute distribution Processing la bibliothèque audio Minim
pour pouvoir par défaut jouer des fichiers audio ou capter le son entrant par le microphone. A priori cette
bibliothèque est déjà installée sur votre machine. Pour vérifier sa présence et l'intégrer dans votre
programme, il suffit d'aller dans le menu Sketch > Import Library... > Minim audio.
Selon votre plate-forme et votre version, à la suite de cette action, Processing ajoutera des lignes de code
plus ou moins nombreuses en haut de votre programme. Par défaut, il faut au moins voir affichée
l'instruction suivante :
C'est cette instruction (que vous pouvez saisir à la main si vous le voulez) qui importera l'ensemble des
fonctionnalités de la bibliothèque Minim pour les rendre accessibles à notre programme. C'est à partir de
cette instruction import [Link].*; que notre sketch va pouvoir jouer du son.
Configurer Minim
Le lancement de notre sketch via le bouton Run ne suffit pas pour jouer un son. Au préalable, il faut prévoir
d'activer les fonctionnalités de gestion audio de Minim (son moteur audio en jargon informatique). Pour
jouer un son, Minim doit en effet auparavant demander un accès à la carte son de votre ordinateur. Ne vous
inquiétez pas, Minim s'occupe de toute cette cuisine interne pour vous, il suffit de lui dire de s'activer pour
cela. Le fait d'avoir activé Minim suppose de prévoir de le désactiver à la fin de notre programme.
Si vous ne comprenez pas tout ce que nous venons de dire, ce n'est pas trop grave. Sachez simplement qu'il
faut saisir le code suivant au début de chaque programme utilisant Minim :
import [Link].*;
Minim minim;
void setup() {
minim = new Minim(this);
}
void stop() {
[Link]();
[Link]();
}
Si par curiosité vous voulez savoir à quoi sert le mot « this » dans ce programme, sachez qu'il sert à
indiquer à Processing que nos instructions s'appliquent à « ce » programme. Minim a besoin de connaître
l'adresse de « ce » programme (le nôtre) pour le faire communiquer avec la carte son de notre ordinateur.
Encore une fois, si vous ne comprenez pas ce que nous venons de dire, ce n'est pas grave. Sachez seulement
que ces mots doivent être écrits au début et à la fin de chaque programme lorsque nous voulons produire du
son.
Importer un son
Tout comme les images photographiques ou la typographie, nous allons importer un fichier son dans
Processing pour pouvoir le jouer dans notre programme. Pour bien réussir cette étape, nous vous
recommandons de sauvegarder d'abord votre sketch.
Nos sons peuvent venir de plusieurs sources : des sons téléchargés, des sons que vous avez créés vous-même
via un logiciel comme Audacity, voire des sons que vous pouvez trouver par défaut dans votre système
d'exploitation.
Processing page 99 / 155
Identifiez et sélectionnez à présent le fichier son que vous souhaitez utiliser, et glissez-le directement sur la
fenêtre Processing :
Cette action placera le son de ce fichier dans le dossier « data » de votre sketch (un message s'affichant au
niveau de la console de Processing vous le confirmera). Si vous voulez voir ce que contient ce dossier, taper
sur ctrl-k (Windows/Linux) ou cmd-k (Mac), sinon choisissez dans le menu Sketch > Show Sketch Folder.
Formats audio
Vous pouvez utiliser trois formats audio avec Minim : WAV, AIFF, et MP3. Les deux premiers formats
peuvent être exportés par défaut via des logiciels libres comme Audacity. Le troisième format nécessite à ce
jour un plug-in pour Audacity, mais celui-ci est relativement facile à installer.
Comme pour les images, les différents formats ont leurs avantages et désavantages.
1. Les formats WAV et AIFF sont quasi identiques et sont deux formats non compressés. Ils peuvent
être lus sans trop de difficultés par Minim, car ils ne requièrent pas de décompression. Ils sont
souvent utilisés pour des sons courts, de type bruitage. Pour un morceau de musique de même durée,
ces deux formats occupent beaucoup plus de place mémoire que les fichiers au format MP3.
2. Le format MP3 est un format compressé. Il est souvent beaucoup moins volumineux que les fichiers
WAV et AIFF. Par contre, la lecture du format MP3 nécessite plus de ressources de calcul de votre
ordinateur, car le fichier doit être décompressé lors de sa lecture.
void draw() {
background(255);
ellipse(50,50,second(),second());
}
Nous utiliserons la valeur des secondes de l'horloge système pour définir les paramètres {largeur,hauteur}
de l'ellipse. Si les secondes sont égales à 42, nous aurons une ellipse de 42 x 42 pixels. Si les secondes sont
égales à 2, nous aurons une ellipse de 2 x 2 pixels.
Nous pouvons également ajouter une condition pour signaler davantage le changement des minutes : à
chaque fois que les secondes reviendront à zéro, nous marquerons l'événement avec un écran rouge.
void draw() {
if (second() == 0) {
background(255,0,0);
} else {
background(255);
}
ellipse(50,50,second(),second());
}
La condition if(second() == 0) {} compare les secondes avec la valeur 0. Si les deux sont égales, le
fond sera rouge, sinon (else) le fond sera blanc.
Pour commencer, nous allons ajouter autour de notre méthode draw() de l'horloge, toutes les méthodes
nécessaires pour la sonoriser (lignes de code mentionnées en gras).
import [Link].*;
Minim minim;
AudioSnippet ping;
void setup() {
minim = new Minim(this);
ping = [Link]("[Link]");
}
void draw() {
if (second() == 0) {
if ([Link]() == false){
[Link]();
}
background(255,0,0);
} else {
background(255);
}
ellipse(50,50,second(),second());
}
void stop() {
[Link]();
[Link]();
[Link]();
}
Nous avons déjà expliqué le démarrage et l'extinction du moteur Minim. Nous n'y revenons pas. Par contre,
nous attirons votre attention sur les parties 2, 4 et 5 du programme qui concernent l'importation et la lecture
du son.
Pour plus d'informations sur les variables et les différents types de variables, reportez-vous au chapitre dédié
à ce sujet.
Une fois la variable chargée avec le son, il suffit de le jouer. Dans le cas du AudioSnippet la commande pour
jouer un son s'appelle play(). Enfin, il peut être important de vérifier à un moment donné si le son n'est pas
déjà en train d'être joué. C'est le rôle de la commande isPlaying() de nous dire si oui (true) ou non
(false) nous sommes dans cette situation. Dans notre exemple, si nous avions oublié cette condition, le son
se serait lancé pendant soixante fois durant la totalité de la seconde où second() est égal à zéro.
import [Link].*;
Minim minim;
AudioSample ping;
AudioSnippet pop;
AudioPlayer song;
void setup() {
minim = new Minim(this);
ping = [Link]("[Link]");
pop = [Link]("[Link]");
song = [Link]("song.mp3");
}
void draw() {
void keyPressed() {
if (key == 'a') [Link]();
if (key == 'b') {
[Link]();
[Link]();
}
if (key == 'c') [Link]();
}
void stop() {
[Link]();
[Link]();
[Link]();
[Link]();
Processing page 104 / 155
[Link]();
}
Notez avant tout que les instructions d'importation et de lectures changent selon le type choisi. AudioPlayer
et AudioSample utiliseront tous les deux la méthode play() car leur lecture est toujours unique (un seul son
à la fois). Par contre, AudioSample nécessite la lecture de nombreux sons simultanés (on peut taper plusieurs
fois sur une batterie) et pour cette raison utilise une autre nomenclature, trigger(), pour décrire le
lancement d'un son. En anglais, le mot « trigger » signifie une gâchette.
Documentation
Pour plus d'informations sur les différentes fonctionnalités de Minim, ainsi qu'un grand nombre d'exemples
d'utilisation (avec leur code source librement mis à disposition), reportez-vous au site
[Link] ou à la documentation technique (plus difficile à lire)
consultable à l'adresse [Link]
L'opération effectuée, Processing ouvre automatiquement un dossier applet dans l'explorateur de fichiers de
votre ordinateur. Celui-ci contient plusieurs fichiers.
[Link] est la page web générée par Processing. En double cliquant dessus, votre navigateur
internet va se lancer et afficher l'animation que vous venez juste d'exporter.
[Link] est une icône utilisée lors du chargement de l'applet dans la page web.
{votre nom de sketch}.jar est l'applet à proprement parler. Il s'agit du code source de votre sketch qui
a été transformé et sauvegardé avec toutes les données.
{votre nom de sketch}.java est la version Java de votre code.
{votre nom de sketch}.pde est le code source original du sketch que vous avez saisi dans l'éditeur de
Processing.
Attention! A chaque exportation, Processing écrase automatiquement les fichiers portant le même nom. Par
précaution, si vous effectuez des modifications sur le fichier {votre nom de sktech}.html, pensez au préalable
à le renommer.
Si vous disposez d'un espace de stockage sur un serveur web, et que vous êtes familiers des transferts FTP,
vous pouvez téléverser le dossier applet (en le renommant, si besoin est) dans votre espace en ligne. Vous
pourrez ainsi rendre accessibles vos sketchs sur Internet.
Platforms permet de sélectionner la plateforme. C'est là toute la beauté de Processing : nous pouvons
exporter une application développée sur Mac pour GNU/Linux, par exemple.
Full Screen (Present mode) lancera l'application en plein écran lors du double-clic.
Show a Stop button , en mode Full Screen, affiche un bouton Stop sur l'écran pour arrêter
l'application.
Une fois l'application assemblée, la fenêtre du dossier du sketch s'affiche avec les dossiers propres à chaque
plateforme. Le fichier exécutable se trouve à l'intérieur, prêt à être lancé sur votre ordinateur.
5.2. L'impression
Pour l'instant, nous avons travaillé sur l'écran en générant des images et des animations. Nous allons
maintenant nous intéresser aux possibilités qu'offre Processing en matière d'impression : nous allons créer
un document PDF (Portable Document Format) contenant des formes géométriques vectorielles, document
qui pourra ensuite être imprimé sur du papier ou un autre médium.
Mode direct
Dans ce premier exemple, nous allons générer 500 cercles aléatoirement et les dessiner dans un document
PDF, qui sera sauvé dans notre dossier de travail.
Comment fonctionne ce programme ? Tout d'abord, nous commençons par importer toutes les classes de la
librairie [Link]. Nous utilisons la méthode size() qui permet de définir les caractéristiques de
notre espace de dessin : cette fois-ci, nous mentionnons quatre paramètres. Notez le mot-clé PDF qui indique
à Processing que nous allons dessiner dans le document "[Link]", passé en quatrième paramètre de la
méthode.
Avec ce mode direct de tracé, puisque nous dessinons directement dans le document et non plus sur l'écran,
nous n'avons plus besoin de la fenêtre de visualisation de Processing. Le programme se termine par la
commande exit(), qui indique au logiciel de terminer le programme tout seul, exactement comme si nous
avions appuyé sur le bouton stop de l'interface.
Le document généré au format pdf se trouve dans le dossier de sketch de votre application. Vous pouvez
double-cliquer dessus pour l'ouvrir.
Mode enregistrement
Nous allons voir maintenant comment dessiner à la fois sur l'écran et dans un fichier .pdf à l'aide des
commandes beginRecord() et endRecord(). Ces deux méthodes vont nous permettre de démarrer et
arrêter l'enregistrement des commandes graphiques dans un fichier PDF.
Dans l'exemple suivant, nous allons réaliser un outil graphique, une sorte de pinceau numérique dont la taille
du tracé dépend de la vitesse à laquelle nous déplaçons la souris. Au démarrage de l'application, dans le
setup(), nous indiquons le début de l'enregistrement par la commande beginRecord() qui prend en
paramètres le type d'export (pour l'instant Processing ne supporte que l'extension PDF) et le nom du fichier
en second paramètre. Lorsqu'on appuie sur la touche ESPACE, l'enregistrement est stoppé et l'application
s'arrête. Comme précédemment, le fichier généré est sauvegardé dans le dossier du sketch.
void setup()
{
size(400, 400);
smooth();
beginRecord(PDF, "[Link]");
}
void draw() {
if (drag)
{
float r = dist(pmouseX, pmouseY, mouseX, mouseY) + 5;
ellipse(mouseX, mouseY, r, r);
}
}
void mouseDragged() {
drag = true;
}
void mouseReleased() {
drag = false;
}
void keyPressed() {
endRecord();
exit();
}
La ligne suivante :
... permet de calculer la vitesse de la souris grâce à la méthode dist et aux variables pmouseX, pmouseY et
mouseX et mouseY. Nous ajoutons 5 pour ne pas avoir des cercles de rayon 0 sur l'écran (ce qui reviendrait à
avoir des cercles invisibles).
La variable drag sert à savoir si l'utilisateur est en train de déplacer la souris en maintenant le clic appuyé,
ce qui active à l'aide de draw() l'action de dessiner des cercles sous le pointeur de la souris.
import [Link].*;
PGraphicsPDF pdf;
float x = 0;
float y = 75;
void setup() {
size(400, 150);
smooth();
pdf = (PGraphicsPDF) beginRecord(PDF, "[Link]");
}
void draw() {
background(255);
fill(0);
ellipse(x, y, 30, 30);
x = x + random(5);
y = y + random(-5, 5);
if (x - 30 > width) {
endRecord();
exit();
}
[Link]();
}
Nous avons introduit la variable pdf pour stocker une référence au document que nous générons. Lorsque
nous avons fini de dessiner une image dans draw(), nous passons à l'image suivante par la commande
[Link](). Le programme est conçu pour s'arrêter lorsque la bulle sort de l'écran. Après l'exécution
du programme, le fichier sauvegardé du folioscope se trouve dans le dossier du sketch et porte le nom
[Link]. En l'ouvrant, vous pourrez constater qu'il comporte 164 pages, chacune d'entre elles présentant
notre balle en un instant donné de son mouvement dans l'espace de dessin.
En enregistrant la même image au format vectoriel, Processing ne va plus sauver chaque pixel un à un, mais
plutôt les caractéristiques de chaque forme dessinée : sa forme, sa position et sa couleur. Ainsi, lorsque nous
agrandissons l'image, l'ordinateur est capable de dessiner avec précision les détails d'une image qu'il n'aurait
pas été possible de produire avec une image pixelisée. Le pdf est un format de sauvegarde vectoriel.
Si jamais vous essayez d'utiliser les méthodes relatives à l'export PDF sans avoir importé la librairie, vous
allez rencontrer des erreurs qui s'afficheront dans la console et le programme ne pourra démarrer. Au lieu de
taper cette ligne de code, vous pouvez l'ajouter automatiquement en cliquant dans le menu Sketch > Import
Library... > PDF Export.
5.3. La vidéo
Processing vous offre la possibilité d'exporter votre sketch animé ou interactif sous forme d'animation vidéo
au format QuickTime. Pour créer des vidéos, nous allons utiliser un objet prédéfini MovieMaker de la
librairie [Link]. Attention, pour les utilisateurs sous Linux, cette fonction n'est à ce jour
pas disponible.
L'objet MovieMaker
L'objet MovieMaker est une classe prédéfinie de Processing qui permet de créer un fichier vidéo, et de lui
ajouter des images au fur et à mesure de l'exécution de votre programme. Pour pouvoir l'utiliser dans votre
sketch, il faut importer la librairie vidéo de Processing :
import [Link].*;
void setup() {
size(size(300,300);
/*
* Création de l'objet MovieMaker. La vidéo aura
* la même taille que notre esquisse
*/
mm = new MovieMaker(this, width, height, "[Link]");
}
void draw() {
ellipse(mouseX,mouseY,20,20); //On dessine une ellipse
Finaliser la vidéo
A ce stade, l'enregistrement de la vidéo se termine lorsque l'on quitte le programme. On peut indiquer à
l'objet MovieMaker d'arrêter l'enregistrement à tout moment. Dans notre exemple, nous allons ajouter une
action qui stoppe l'enregistrement vidéo lorsqu'on appuie sur n'importe quelle touche du clavier de votre
ordinateur.
void keyPressed() {
[Link]();
}
(Pour des raisons de lisibilité, le code de la ligne précédente a été réparti sur deux lignes. Si vous devez le
copier pour le réutiliser dans un sketch, supprimer le retour chariot pour placer l'ensemble des instructions
sur une seule ligne).
MovieMaker.H264 : Lent à encoder et décoder. Occupe par contre très peu d'espace-disque sur votre
ordinateur.
MovieMaker.MOTION_JPEG_B : Très rapide à encoder et décoder. Occupe également peu d'espace-
disque.
[Link] : Supporte le canal alpha permettant la gestion de la transparence, très utile
pour certaines images. Occupe énormément d'espace-disque, la vidéo étant compressée sans perte.
Actions
La valeur de la dernière touche appuyée est stockée dans la variable key proposée par défaut dans
Processing. Cette variable ne peut stocker qu'un seul caractère à la fois, symbolisé par l'écriture 'a' , 'b' ,
'c', ... Attention, key est sensible à la casse, c'est-à-dire qu'il fait une différence entre les minuscules et
majuscules.
Dans l'exemple suivant, nous allons afficher dans la fenêtre de visualisation le caractère correspondant à la
touche qui aura été appuyée sur le clavier de votre ordinateur. Pour ce faire, nous employons la méthode
text().
void draw() {
background(204);
fill(0);
textSize(70);
text(key,30,70);
}
Par ailleurs, nous pouvons capter dans notre programme le moment où l'utilisateur a appuyé ou relâché une
touche du clavier, par le biais des méthodes keyPressed() et keyReleased(). Ces deux méthodes vont être
automatiquement appelées par Processing au moment où l'état d'une touche change.
Dans l'exemple suivant, keyPressed() et keyReleased() changent la valeur de la variable y, utilisée pour
positionner le caractère à l'écran selon que la touche est appuyée ou relâchée.
int y = 0;
void draw() {
background(204);
line(10,100,120,100);
text(key,35,y);
}
void keyPressed(){
y = 180;
}
void keyReleased(){
y = 80;
}
Touches spéciales
Les touches spéciales comme les flèches (UP, DOWN, LEFT, RIGHT) ou ALT, CONTROL, SHIFT sont quant à elles
stockées dans la variable keyCode. Le test if (key == CODED) permet de vérifier si la touche appuyée est
une touche spéciale ou non. Dans un programme, il faudra distinguer les deux cas en fonction du type de
touche appuyée que l'on veut tester.
Dans l'exemple suivant, nous allons créer une machine à écrire un peu particulière, puisqu'il sera possible de
déplacer le texte grâce aux flèches.
A chaque fois qu'une touche sera appuyée, elle sera stockée dans une chaîne de caractère, pour pouvoir être
affichée dans le draw() à l'aide de la méthode text().
String s = "";
int x = 50;
int y = 50;
void setup() {
size(200,200);
}
void draw() {
background(255);
fill(0);
text(s, x, y);
}
void keyPressed() {
if (key == CODED){
if (keyCode == LEFT) x = x - 1;
if (keyCode == RIGHT) x = x + 1;
if (keyCode == UP) y = y - 1;
if (keyCode == DOWN) y = y + 1;
}
else {
s = s + key;
}
}
Dans l'exemple suivant, nous allons dessiner un cercle si la touche appuyée est 'c', un carré si la touche
appuyée est 'r'.
void draw()
{
rectMode(CENTER);
background(128);
if (keyPressed == true)
{
if (key == 'c') {
ellipse(50,50,90,90);
}
else if (key == 'r') {
rect(50,50,90,90);
}
}
}
Position de la souris
Les coordonnées de la souris dans la fenêtre sont accessibles par les deux variables mouseX et mouseY,
disponibles par défaut dans Processing. Elles permettent de connaître la position de la souris par rapport à
notre fenêtre de dessin, en prenant pour origine le coin gauche supérieur de la fenêtre. Dans l'exemple
suivant, nous allons créer un programme qui va dessiner un cercle à partir de la position de la souris.
void setup() {
size(200,200);
smooth();
}
void draw() {
ellipse(mouseX,mouseY,15,15);
}
A présent, nous allons modifier très légèrement l'exemple précédent en changeant dynamiquement le rayon
du cercle. Celui-ci est choisi au hasard grâce à la méthode random(), qui génère un nombre aléatoirement au
sein d'une plage de valeur. A chaque fois que Processing va exécuter draw(), la variable r sera remplie avec
un nombre au hasard compris entre 3 et 30 : 12, 25, 23, 11, 22, 4, 10, 11, 25 ... Le changement de valeur du
rayon va provoquer le tremblotement du cercle autour du curseur de la souris.
void draw() {
float r = random(3,30);
ellipse(mouseX,mouseY,r,r);
}
Dès que la souris sort de la fenêtre, la position de la souris n'est plus relayée à notre programme. Les cercles
se dessinent et s'accumulent à la dernière position captée par notre sketch.
Clics de souris
Nous pouvons intercepter les clics de souris grâce aux méthodes mousePressed() et mouseReleased().
Ces deux méthodes permettent de savoir si l'utilisateur a appuyé ou relâché un des boutons de la souris.
Reprenons l'exemple précédent en changeant la couleur de remplissage de notre cercle lorsque l'utilisateur
appuie sur un des boutons de la souris. Nous allons choisir un niveau de gris pris au hasard au moment du
clic que nous appliquerons au cercle à l'aide de la commande fill().
void setup() {
size(300, 300);
smooth();
}
void draw() {
float r = random(10, 80);
fill(grey);
ellipse(mouseX, mouseY, r, r);
}
void mousePressed() {
grey = random(255);
}
Processing nous permet d'identifier quel bouton de la souris a été appuyé. Pour cela, nous pouvons utiliser la
variable mouseButton qui va contenir soit LEFT, RIGHT ou CENTER correspondant au bouton droit, gauche et
central (si la souris dispose de tous ces boutons). Utilisons cette variable dans un exemple pour dessiner un
cercle qui change de couleur en fonction du type de bouton pressé.
void setup() {
size(200,200);
smooth();
}
void draw() {
background(255);
ellipse(100,100,200,200);
}
void mousePressed() {
if (mouseButton == LEFT) fill(0);
if (mouseButton == RIGHT) fill(255);
if (mouseButton == CENTER) fill(128);
}
Autres événements
Processing permet de capter deux autres événements souris, notamment lorsqu'elle est en mouvement au-
dessus de la fenêtre.
Dans l'exemple suivant, nous allons utiliser ces méthodes. Lorsque mouseMoved() est appelé suite à l'action
de l'utilisateur, on change la couleur de remplissage du cercle et quand c'est mouseDragged() qui l'est, on
ajuste sa taille.
int r = 100;
int c = 100;
void setup() {
size(255, 255);
smooth();
}
void draw() {
background(255);
fill(c);
ellipse(width/2, height/2, r, r);
}
void mouseMoved() {
c = mouseY;
}
void mouseDragged() {
r = mouseX;
}
Curseur
Parfois il est bien pratique de cacher le curseur de la souris, par exemple dans le cas d'une installation
artistique où le pointeur pourrait venir malencontreusement parasiter l'affichage de votre animation. Dans
Processing, il existe fort heureusement une instruction pour masquer le pointeur :
noCursor();
Il est également possible de modifier la forme du curseur pour signaler certains évènements à l'utilisateur,
par exemple changer la forme du curseur au survol d'un élément. Il suffit pour cela d'utiliser cursor() avec
comme paramètre une des valeurs suivantes : ARROW, CROSS, HAND, MOVE, TEXT, WAIT. L'exemple ci-après
void setup() {
fill(255);
rect(10, 10, 20, 80);
fill(175);
rect(40, 10, 20, 80);
fill(100);
rect(70, 10, 20, 80);
}
void draw() {
// Nous vérifions si on survole un des 3 rectangles
// et modifions le curseur en conséquence
if (mouseX > 10 && mouseX < 30 && mouseY > 10 && mouseY < 90) {
cursor(HAND); // Affiche une main
}
else
if (mouseX > 40 && mouseX < 60 && mouseY > 10 && mouseY < 90) {
cursor(ARROW); // Affiche une flèche
}
else
if (mouseX > 70 && mouseX < 90 && mouseY > 10 && mouseY < 90) {
cursor(WAIT); // Affiche un sablier
}
else {
cursor(CROSS); // Affiche une croix si on ne survole rien
}
}
Nous allons tout d'abord rappeler certaines notions abordées dans le chapitre consacré à la lecture du son
pour ensuite nous concentrer plus spécifiquement sur l'ajout d'une source sonore à l'aide d'un microphone.
Minim
Il a été décidé à un moment donné d'intégrer dans toute distribution Processing la bibliothèque audio Minim
pour pouvoir jouer au moins des fichiers audio ou capter le son entrant par le microphone. A priori cette
bibliothèque (également appelé librairie en jargon informatique) est déjà installée sur votre ordinateur. Pour
vérifier sa présence et l'intégrer dans votre programme, il suffit d'aller dans le menu Sketch > Import
Library... > Minim audio.
import [Link].*;
C'est cette instruction (que vous pouvez saisir à la main si vous le voulez) qui importera l'ensemble des
fonctionnalités de la bibliothèque Minim pour les rendre accessibles à notre programme. C'est à partir de
cette instruction import [Link].*; que notre sketch va pouvoir jouer du son.
Configurer minim
Le lancement de notre sketch à l'aide du bouton Run ne suffit pas pour jouer un son. Au préalable, il faut
prévoir d'activer les fonctionnalités de gestion audio de Minim (son moteur audio en jargon informatique).
Pour jouer un son, Minim doit en effet auparavant demander un accès à la carte son de votre ordinateur. Ne
vous inquiétez pas, Minim s'occupe de toute cette cuisine interne pour vous, il suffit de lui dire de s'activer
pour cela. Le fait d'avoir activé Minim suppose de prévoir de le désactiver à la fin de notre programme.
Si vous ne comprenez pas tout ce que nous venons de dire, ce n'est pas trop grave. Sachez simplement qu'il
faut saisir le code suivant au début de chaque programme utilisant Minim :
import [Link].*;
Minim minim;
void setup() {
minim = new Minim(this);
}
void stop() {
[Link]();
[Link]();
}
import [Link].*;
Minim minim;
AudioInput in;
void setup() {
minim = new Minim(this);
in = [Link]([Link], 512);
}
Il faut également prévoir d'arrêter la capture du son ainsi que la librairie Minim à la fin de l'exécution du
programme. A cet effet, nous employons la méthode stop();
void stop() {
[Link]();
[Link]();
[Link]();
}
void draw() {
background([Link]()*2550);
}
Un petit jeu
Nous allons à présent créer un jeu très simple qui va exploiter davantage les possibilités d'interaction avec
un microphone. Le jeu sera composé d'une balle partant de la gauche de l'écran et qui subit une force
d'attraction lente, mais permanente vers cette partie de l'espace de dessin. En faisant du bruit, l'utilisateur va
la pousser vers la droite, son but étant de passer la ligne d'arrivée.
Pour commencer, nous allons changer la taille de notre fenêtre de visualisation de l'espace de dessin, activer
le lissage du tracé et définir le contour des formes en lui appliquant la couleur blanche. Le code concerné est
signalé en gras.
Nous allons ensuite créer une variable qui stockera la position de la balle. Elle sera déclarée en en-tête du
programme pour être disponible dans l'ensemble du sketch. Nous lui assignons la valeur 0.
float ballX = 0;
void setup() {
...
Dans la méthode draw(), nous allons définir un fond noir et dessiner une balle qui réagit en fonction du
niveau du son. A chaque appel de la méthode draw() nous ajoutons le niveau sonore du microphone à la
coordonnée x de la balle. Elle va se mettre en mouvement au fur et à mesure que nous faisons du bruit.
void draw() {
background(0);
Pour éviter que la balle ne sorte de l'écran, nous allons ajouter deux conditions qui vont corriger sa position
si la variable ballX est plus petite que 0 ou plus grande que la largeur du sketch.
void draw() {
background(0);
if (ballX < 0) {
ballX = 0;
}
Nous allons ajouter une « ligne d'arrivée » ainsi qu'une condition qui spécifie que si la balle l'a franchi, elle
change de couleur.
void draw() {
background(0);
Afin de compliquer le jeu, nous allons ajouter un comportement à la balle qui la fait revenir en arrière en
permanence. A chaque appel de la fonction draw() nous allons diminuer légèrement sa position sur l'axe x.
void draw() {
background(0);
if (ballX < 0) {
ballX = 0;
}
A présent, il ne vous reste plus qu'à faire appel à votre imagination pour utiliser du son dans vos projets et en
exploiter les nombreuses possibilités : analyse des fréquences d'un son, création d'effets sonores sur mesure
à l'aide de fonctionnalités de synthèse audio, etc.
Pour exploiter l'entrée vidéo, vous pouvez utilisez la librairie video de Processing qui fait appel à la librairie
QuickTime, de la compagnie Apple Computer. Toutes les caméras supportées par QuickTime devraient
donc fonctionner sans aucune difficulté. Apple fournit cette librairie uniquement pour les systèmes
d'exploitation Mac OS X et Microsoft Windows. Sur GNU/Linux, il est préférable d'utiliser la librairie
GSVideo. Celle-ci fait usage de l'excellente GStreamer.
import [Link].*;
Ensuite nous allons déclarer une variable qui stockera notre objet Camera. Dans la méthode setup(), il faut
préciser laquelle des caméras présentes sera utilisée. Notez que vous devez déjà avoir connecté et installer
cette caméra vidéo sur votre ordinateur pour faire fonctionner cet extrait de code. Si le code génère une
erreur au moment de créer la caméra, essayez d'autres numéros de devices[].
Capture camera;
void setup() {
size(640, 480);
background(0);
L'étape suivante consiste à préciser, dans la méthode draw(), que nous affichons la dernière image obtenue
par la caméra en vérifiant qu'une nouvelle est bien disponible. En effet, les images sont reçues de la caméra
vidéo à une certaine fréquence, par exemple 30 fois par seconde, ce qui ne correspond pas forcément à celle
de notre sketch. Dans l'exemple ci-après, nous avons demandé à notre programme d'appliquer sur l'image
captée un filtre de solarisation (inversion des valeurs d'ombre et de lumière de l'image).
void draw() {
if ([Link]()) {
[Link]();
[Link](INVERT);
image(camera, 160, 100);
}
La variable de type Capture peut être utilisée de la même manière qu'une variable de type PImage : il est
possible de lire les pixels de l'image, la transformer, l'afficher plusieurs fois à l'écran, et bien d'autres choses
encore.
import [Link].*;
Capture camera;
void setup() {
size(640, 480);
background(0);
void draw() {
if ([Link]()) {
[Link]();
[Link](INVERT);
image(camera, 160, 100);
}
}
Augmenter la mémoire
Si vous créez des sketchs qui utilisent de la vidéo, de nombreuses images ou qui travaillent avec des données
volumineuses, il peut arriver que votre programme génère une erreur pour cause de mémoire insuffisante.
Voici l'erreur affichée par Processing dans la console.
Pour résoudre ce problème, vous devez ouvrir les préférences de Processing et changer la quantité de
mémoire allouée à votre sketch.
boolean afficheInfo;
void setup() {
afficheInfo = false;
}
void draw() {
background(0);
// Si vrai, on affiche le texte
if (afficheInfo) text("Info", 10, 20);
}
void keyPressed() {
// on affecte à afficheInfo l'inverse de sa valeur actuelle
afficheInfo = ! afficheInfo;
}
la variable frameCount permet de connaître le nombre de fois où draw() a été appelé depuis le
lancement du programme.
Ainsi, si l'on veut effectuer une action toutes les secondes, on la déclenchera dans le cas où le reste de la
division de frameCount par la valeur passée à frameRate() est bien égal à zéro. Dans l'exemple qui suit,
nous changeons la couleur de fond à chaque seconde en vérifiant que notre compteur est un multiple de 24.
color couleur;
void setup() {
couleur = 0;
frameRate(24);
}
void draw() {
background(couleur);
if (frameCount % 24 == 0) {
couleur = (int) random(255);
}
}
Exercice : modifiez le code ci-dessus pour que le changement de couleur ait lieu toutes les 3 secondes.
L'intervalle de temps (un intervalle que vous aurez déterminé à votre convenance)
Le temps de la dernière vérification de l'intervalomètre
Une action qui vérifie si le prochain intervalle a été franchi.
class Intervalometre {
int intervalle;
int dernier_tic;
Intervalometre(int intervalle_initial) {
intervalle = intervalle_initial;
dernier_tic = millis();
}
boolean verifierIntervalle() {
if (millis() > dernier_tic + intervalle) {
dernier_tic = millis();
return true;
} else {
return false;
Ici, la méthode verifierIntervalle() vérifie si l'intervalle de temps est écoulé depuis la dernière fois.
Elle retourne vrai ou faux. En d'autres termes, cela revient à décider d'exécuter une certaine action à chaque
fois que notre horloge fait tic.
La dernière étape de programmation de notre sketch va consister à déclarer une variable qui stockera notre
intervalomètre. Chaque appel de la méthode draw() exécutera verifierIntervalle() de notre objet
Intervalometre. Si cette méthode nous retourne vrai, nous allons faire apparaître un rectangle positionné
au hasard sur l'écran. L'intervalle de temps choisi dans cet exemple est de 100 millisecondes.
Intervalometre intervalometre;
void setup() {
intervalometre = new Intervalometre(100);
}
void draw() {
if ([Link]()) {
rect(random(0, width), random(0, height), 10, 10);
}
}
L'exemple suivant montre comment interrompre et reprendre ce mouvement à l'aide de la touche 's' et de la
barre d'espacement.
int position = 0;
int increment = 1;
void setup() {
}
void draw() {
background(0);
ellipse(50, position, 5, 5);
// on déplace le point de 1 pixel
position += increment;
// si on touche les bords
if (position > height || position < 0) {
// alors on inverse la valeur d'incrément
increment *= -1;
}
}
void keyPressed() {
if (key == ' ') {
// on relance le cycle
loop();
}
else if (key == 's' || key == 'S') {
// on arrête le cycle
noLoop();
}
}
Unexpected token
Cette erreur se produit fréquemment lorsque vous oubliez un « ; » en fin de ligne ou que vous n'avez pas
correctement fermé un bloc d'accolades. Le programme voit une instruction qui fait deux lignes et dont la
syntaxe est par conséquent erronée.
int nombreEntier = 1
float nombreVirgule = 0.1;
int nombreEntier = 1;
float nombreVirgule = 0.1;
void draw() {
void setup() {
void setup() {
Dans Processing, on ne peut jamais diviser un nombre par zéro. Au besoin, vérifier que le diviseur n'est pas
zéro avant de faire la division. C'est la fonction du morceau de code suivant :
int diviseur = 0;
if (diviseur != 0) {
println(1 / diviseur);
} else {
println("On ne peut pas diviser par zéro!");
}
int a = 10;
float b = 10.5;
a = b;
Dans le cas présent, pour que nous puissions affecter un nombre à virgule à une variable qui est prévue pour
stocker un nombre entier, il faut forcer Processing à la transformer. Le code correct est :
int a = 10;
float b = 10.5;
a = int(b);
ArrayIndexOutOfBoundsException
Cette erreur survient lorsque vous tentez d'accéder à un élément en dehors des limites d'un tableau. Dans
l'exemple suivant, le tableau à une taille de 3 (case 0, 1 et 2) et nous essayons d'accéder à la case 4.
println(nombres[4]);
Le code correct est le suivant (la 3e case correspond au rang 2 et non pas au rang 3 ou 4 puisqu'un tableau
commence toujours à partir d'une case de rang 0) :
int[] numbers = new int[3];
numbers[0] = 1;
numbers[1] = 20;
numbers[2] = 5;
println(numbers[2]);
Balle maBalle;
void setup() {
maBalle.x = 10;
}
class Balle {
int x;
int y;
}
void setup() {
maBalle.x = 10;
}
class Balle {
int x;
int y;
}
Une librairie, c'est une collection de classes que l'on peut réutiliser dans chacun de nos projets. Mise à
disposition sur Internet, une multitude de librairies intéressantes existe pour Processing. Pour pouvoir en
utiliser une, il suffit de la télécharger de son site internet, de décompresser l'archive et de le placer dans le
dossier libraries. Le dossier libraires se trouve dans le dossier de travail de Processing (menu Sketch puis
Show Sketch Folder).
Par ailleurs, plusieurs librairies sont déjà installées par défaut dans ce dossier lors de l'installation de
Processing.
Dans tous les cas, pour les utiliser dans un de vos sketchs, choisir son nom dans le menu Sketch > Library.
Ces librairies sont libres : les utilisateurs ont la liberté d'exécuter, de copier, de distribuer, d'étudier, de
modifier et d'améliorer leur code.
On peut, sur le site de Processing, accéder à un annuaire des principales librairies à l'adresse suivante :
[Link]
Nous utiliserons la librairie ShapeTween, car celle-ci est très simple à utiliser. Elle fournit une variété de
moyens d'animer des éléments. Ce genre d'outil est fort utile pour créer des animations fluides.
Pour désigner des animations et des transitions, le mot tween est souvent utilisé. Ce mot vient de l'anglais in
between et désigne les images que l'on dessine entre chacune des images-clés dans le cinéma d'animation
traditionnel. Il s'agit donc d'interpolation de mouvements. L'interpolation consiste à déduire des positions
intermédiaires entre des points connus.
On peut trouver un lien vers la page du projet ShapeTween à partir de la page Libraries sur le site de
Processing à l'adresse [Link] Sur cette page, vous trouverez le lien
intitulé [Link] :
Téléchargez l'archive et décompressez le fichier zip. Placez son contenu dans le répertoire libraries de votre
répertoire de sketch. Vous pouvez ouvrir ce dossier en utilisant le menu Sketch > Show sketch folder. Le
Essayer un exemple
Une bonne librairie fournit également une documentation de chacune des fonctionnalités et instructions
offertes (classes, méthodes et attributs). Elle comporte également le plus souvent des exemples. Si c'est le
cas, il suffit d'y accéder en parcourant le menu File > Sketchbook > Examples. Le nom de notre librairie
devrait s'y trouver. Notez que cette procédure fonctionne uniquement sur Mac OS X et Windows. Sur
GNU/Linux, les exemples des librairies installées par nous-mêmes ne s'affichent pas dans ce menu.
Si la librairie ne contient pas d'exemples, nous pouvons essayer d'en trouver sur la Toile afin de le copier-
coller directement de la page du site vers la fenêtre d'édition de Processing. Comme exercice, nous allons
copier-coller un exemple présenté sur le site internet de ShapeTween.
Sur le site Web de la librairie, on peut voir une liste d'exemples sous la rubrique Example Code. Cliquez sur
Basic Tween afin de voir un exemple très simple de mouvement contrôlé à l'aide de cette librairie. Copiez le
code proposé sur la page et collez-le dans votre fenêtre d'édition de Processing. Avec la librairie
ShapeTween, il est également possible de créer des mouvements qui accélèrent, puis décélèrent, mais les
autres exemples proposés sur le site de cette librairie contiennent des erreurs au moment d'écrire ces lignes
(le répertoire consacré aux exemples comporte la mention « en cours de construction »).
Après avoir vérifié que l'exemple proposé fonctionne, vous pouvez modifier l'exemple, le simplifier et
l'utiliser comme base pour des développements ultérieurs.
import [Link].*;
Tween ani;
void setup(){
size( 200, 200 );
ani = new Tween(this, 2, [Link]);
[Link]();
}
void draw(){
Processing page 137 / 155
background(200);
float x1 = 20;
float y1 = 30;
float x2 = 180;
float y2 = 190;
fill(0);
ellipse( x, y, 8, 8 );
}
void mousePressed(){
[Link]();
}
Si ces considérations sont importantes pour vous, soyez vigilants. Vérifiez toujours que le code source est
inclus avec une librairie, et que son code comporte bien un en-tête avec la mention d'une licence libre. Le
site de la Free Software Foundation fournit une liste de licences libres compatibles avec la GPL
[Link]
Les tutoriaux
La section "learning" du site de Processing ([Link] propose deux types de
contenus : un apprentissage du logiciel pas à pas à travers des exemples basiques et une série de codes plus
complets qui illustrent des cas pratiques.
Les codes de ces exemples sont, pour la plupart, fournis avec le logiciel. On les retrouve via le menu File >
Examples.
Dans ces pages de référence, ce sont d'ailleurs les rubriques Syntax et Parameters qui sont les plus
intéressantes. Elles permettent de savoir ce qu'il faut mettre dans les ( ) pour faire fonctionner la méthode et
sa syntaxe.
Vous pouvez aussi accéder aux références directement depuis l'environnement de Processing. Pour ce faire,
au niveau de la fenêtre d'édition du logiciel, sélectionnez une instruction dont vous souhaitez connaître
davantage la syntaxe et les fonctionnalités (attention le mot recherché doit être sélectionné en entier) puis
cliquez dans le menu Help > Find in Reference. Vous pouvez également effectuer cette opération avec le
raccourci clavier CTRL + MAJ + F (Windows & Linux) ou MAJ + CMD + F (Mac Os).
Le forum de [Link]
Le forum du site Processing ([Link] constitue une autre source d'aide et de
contribution. De nombreuses personnes l'utilisent pour exposer leurs problèmes et obtenir des réponses. On
y trouve aussi de nombreux morceaux de code que vous pourrez intégrer à vos programmes.
Encore marginaux dans le paysage francophone au début de l’aventure Processing, les initiatives autour de
la création algorithmique se sont considérablement développées ces dernières années dans les écoles.
Certains établissements dont l'identité repose sur un positionnement affirmé d’ouverture au numérique
comme l'Ecole d'Art d'Aix en Provence, ou encore l'Ecole de Recherche Graphique à Bruxelles, proposent à
leurs étudiants des programmes où les technologies et des outils tels que Processing sont au coeur des
apprentissages. Mais de plus en plus d’écoles d’art et de filières généralistes commencent à intégrer ces
pratiques à leurs cursus, alors que dans un premier temps priorité avait été donnée aux grands logiciels
propriétaires dans la mise en place de l’apprentissage des outils numériques de création.
L’envers du décor
Les outils numériques de création sont devenus très présents sinon majoritaires dans la pratique de nombre
de créatifs aujourd’hui, et il en est de même pour les étudiants. Les initier à la programmation avec pour
objet la création visuelle ou graphique, c’est leur faire appréhender concrètement la nature de l’image
numérique ainsi que les transformations qu’elle subit lors de ses multiples traitements par les algorithmes
des ordinateurs. Les faire programmer, c’est leur montrer l’envers du décor.
Par ailleurs, les grands logiciels propriétaires sont massivement utilisés et enseignés dans les écoles, sans
forcément susciter un accompagnement critique ni une réflexion sur ces derniers. Initier les étudiants à la
programmation, c’est aussi rendre possible un questionnement sur leurs autres pratiques de création
numérique en favorisant une mise en perspective.
Outil libre, Processing offre une alternative de choix aux grands logiciels propriétaires. Si l'on ne fait pas
toujours les mêmes choses et qu'on ne les fait pas de la même façon, il n'en demeure pas moins important de
donner aux étudiants la possibilité d'appréhender et de pratiquer cet autre type d'outils.
D’un point de vue plus critique, apprendre à programmer ses images au lieu de les coproduire avec des
logiciels sur lesquels on possède très peu de prise en terme de configuration, et au final une maitrise
partielle, redonne aux créatifs dont la production s'exprime sous forme numérique une grande part
d’intentionnalité, à laquelle ils avaient renoncé sans toujours en avoir conscience en travaillant avec les
solutions logicielles dominantes.
Processing page 140 / 155
Apprendre à programmer dans une école d’art, c’est en quelque sorte reprendre le contrôle de sa propre
production numérique. D’autre part, la nature libre de Processing détermine aussi la vitalité de sa
communauté d’utilisateurs, et des échanges générés sur le web autour de cette plateforme. Enseigner
Processing, c’est aussi initier à un état d’esprit, à un mode de fonctionnement ouvert, collaboratif et
favorisant l’auto-apprentissage.
Apprendre à programmer avec Processing ouvre un champ de création très vaste, puisque l’utilisateur n’est
pas limité aux possibilités offertes par un logiciel, mais seulement par sa propre capacité à mettre en oeuvre
ses idées dans l’écriture d’un logiciel. Ce retournement de situation invite à l’expérimentation et à la
recherche. L’utilisateur doit trouver les moyens, de mettre en ouvre ses intentions.
Dans les écoles d’art, de design ou encore d’architecture qui dispensent des cours de programmation
créative, c’est le développement de cette capacité à « inventer ses moyens » qui est enseignée par
l’apprentissage d’un langage, de sa syntaxe, de son vocabulaire, et de ses méthodologies spécifiques. Pour
les étudiants qui poursuivent plus loin dans ce champ, l’apprentissage de la programmation pourra leur
permettre d’inventer leurs propres outils de création graphique afin qu'ils répondent spécifiquement à leurs
besoins et intentions.
La simplicité d'utilisation de Processing en fait un médium idéal pour initier à la programmation un public
qui a priori n'y était pas prédestiné. Conçu dès le départ pour favoriser une démarche de recherche et
d'expérimentation par la pratique, voire l'expression plastique (le terme sketch servant à désigner les
programmes créés dans Processing renvoie bien à la notion d'esquisse), ce logiciel offre un environnement
adapté à l'apprentissage et à la capacité des créatifs à utiliser du code informatique.
Le langage de programmation utilisé est relativement compréhensible pour qui parle anglais et sa syntaxe
relativement aisée à apprendre, y compris pour un non-anglophone. D'autre part, la présence de nombreuses
ressources sur le web et la dynamique de la communauté des utilisateurs de Processing favorise une attitude
d'auto-apprentissage de la part de l'apprenant qui n'attend pas tout de l'enseignant.
Si nous citons cette ressource en ligne dans ce chapitre, c'est pour sa rubrique intitulée « Classes » où sont
regroupés des porte-folios de projets réalisés en classes ou en ateliers ainsi que des cours. Cette initiative
permet à la fois de se rendre compte du nombre croissant de contenus pédagogiques et de résultats d'activités
d'apprentissage dédiés à Processing, mais encore et surtout de la diversité des approches.
côté entrées, des capteurs, appareils qui collectent des informations sur leur environnement comme
la variation de température via une sonde thermique, le mouvement via un détecteur de présence, le
contact via un bouton poussoir, etc.,
côté sorties, des actuateurs, des appareils qui agissent sur le monde physique, telle une petite lampe
qui produit de la lumière, un moteur qui actionne un bras articulé, etc.
L'appareil Arduino
L'appareil Arduino est une plaquette électronique que l'on peut connecter par USB à un ordinateur afin de
téléverser du code sur le micro-contrôleur qui s'y trouve. Un micro-contrôleur, c'est un processeur (un mini-
ordinateur) de petite taille qui fournit des entrées et sorties analogiques et qui fonctionne selon le programme
que l'on aura enregistré dessus.
Cet appareil est autonome. Après avoir reçu le programme que vous aurez conçu, vous pouvez le
déconnecter de votre ordinateur et il fonctionnera tout seul (sous réserve de l'alimenter en énergie électrique
avec une pile ou mieux une cellule photovoltaïque). Comme le logiciel Arduino, ce circuit électronique est
libre. On peut donc étudier ses plans, et créer des dérivés. Plusieurs constructeurs proposent ainsi différents
modèles de circuits électroniques programmables utilisables avec le logiciel Arduino.
L'environnement de programmation vous est certainement familier. On y retrouve les éléments de la fenêtre
de travail de Processing : intitulés des menus, boutons, zone d'édition, console, etc.
Comme dans Processing, le programme est constitué d'une série d'instructions saisie dans la fenêtre du
logiciel. La spécificité d'Arduino se situe au niveau de la sauvegarde du code qui s'enregistre et s'exécute
habituellement depuis le micro-contrôleur et non pas sur votre ordinateur. Le programme se lance dès que
l'appareil Arduino est mis sous tension.
Une fois que vous maîtrisez la programmation Arduino, vous pouvez aller plus loin en connectant le micro-
contrôleur à d'autres logiciels, notamment à un sketch Processing que vous aurez conçu pour interagir avec
cet appareil électronique.
Par exemple, notre programme pourrait lire les informations obtenues de capteurs météorologiques, de
capteurs de mouvement ou de simples boutons de contrôle. Ensuite, à partir de ces informations et du
traitement qu'en ferait notre sketch, on pourrait contrôler des lumières, des moteurs, ou même des radiateurs
ou des ventilateurs. Les applications sont multiples. Tout dépend de l'objectif visé et de l'expérience
interactive recherchée.
La communication sérielle
Processing page 143 / 155
Les ordinateurs communiquent entre eux à l'aide d'impulsions électriques à travers des fils. Les impulsions
sont envoyées les unes après les autres, dans une série de bits. Un bit peut être soit vrai, soit faux. C'est le
chiffre un ou zéro. Les bits sont souvent groupés en paquets de huit. On appelle ces paquets des octets. Un
caractère de texte utilisant le jeu de caractères ASCII est exprimé sur huit bits.
Pour pouvoir échanger ces informations sous forme de bits avec l'extérieur, votre ordinateur utilise une ou
plusieurs entrées physiques (des ports en jargon informatique) lui permettant de se connecter à des
appareils périphériques (imprimante, souris, clavier, modem, etc.).
Tout cela pour vous dire que les impulsions électriques et les instructions informatiques ne sont pas si
éloignées que cela dans un ordinateur et qu'il est possible de communiquer facilement avec un Arduino à
l'aide de simples caractères textuels.
Cet exemple suppose notamment d'avoir appris à connecter votre Arduino à votre ordinateur, procédure qui
n'est pas présentée ici. L'objectif de ce chapitre est davantage de vous faire comprendre les potentialités
offertes par cet appareil électronique et les capacités d'interaction avec Processing. Pour en savoir plus, nous
vous invitons par la suite à consulter les sources d'information disponibles notamment sur Internet.
Envoyer et recevoir du sériel avec Processing est assez facile avec la librairie [Link]. Il faut
spécifier le bon numéro de port série (le numéro de ce port, peut être 0, 1, 2, 3...) , ainsi que la bonne vitesse.
Ici, notre vitesse est de 9600 bits par seconde.
/**
* Code Processing pour communiquer avec l'Arduino simplement.
*/
import [Link].*;
void setup() {
size(200, 150);
println("Liste des ports: \n" + [Link]());
String nom_du_port = [Link]()[numero_du_port];
mon_port = new Serial(this, nom_du_port, 9600);
}
Processing page 144 / 155
void draw() {
if (mon_port.available() != 0) {
// Conversion du int en char
dernier_recu = char(mon_port.read());
}
background(231);
fill(0);
text("Dernier octet reçu: " + dernier_recu, 10, 50);
text("Dernier octet envoyé: " + dernier_envoye, 10, 70);
int largeur = int(dernier_recu - 'a');
int multiplicateur = 5;
stroke(0);
noFill();
rect(10, 90, 26 * multiplicateur, 10);
noStroke();
fill(0);
rect(10, 90, largeur * multiplicateur, 10);
}
void keyPressed() {
if (key == ' ') {
mon_port.write('1');
dernier_envoye = '1';
}
}
void keyReleased() {
if (key == ' ') {
mon_port.write('0');
dernier_envoye = '0';
}
}
Les données sont envoyées sous la forme d'une seule lettre. En effet, la valeur lue de l'entrée analogique zéro
du Arduino est convertie en une lettre alphabétique comprise entre a et z. En utilisant une échelle de 25
lettres, on perd un peu de précision par rapport à la valeur chiffrée d'origine, mais cela permet également de
démontrer comment les lettres sont en fait encodées avec des chiffres.
Côté Arduino, on exprime donc la valeur lue au niveau de son entrée analogique zéro au moyen d'une lettre
comprise entre a et z. On allume également la diode (Led) associée à la sortie 13. Cette petite lumière est
intégrée directement à l'Arduino, aussi nul besoin de souder ou de monter un circuit sur une planche de
prototypage.
Cet exemple fonctionnera donc avec un Arduino sans aucun montage particulier. Vous pouvez toutefois
connecter un potentiomètre à l'entrée analogique zéro si vous souhaitez afficher autre chose que des données
aléatoires issues du « bruit » environnant. Notez que par bruit, nous désignons non pas des sons, mais les
variations électrostatiques de l'environnement dans lequel se trouve votre Arduino. Même si l'entrée
analogique zéro n'est connectée à aucun fil, des phénomènes électriques se produisent à travers l'air entre ce
port et le port « Gnd » de l'Arduino. Idéalement sur une carte Arduino, tous les ports analogiques inutilisés
devraient être connectés directement à la borne « Gnd » (Terre) pour éviter ce type d'effets.
Pour téléverser le code qui suit sur un Arduino, il faut installer le dernier logiciel Arduino, et se munir d'une
carte (Duemillanove, Uno, etc.). Pour explorer le potentiel de cette interface, il est utile d'en apprendre le
fonctionnement, ainsi que ses caractéristiques techniques sur le site officiel : [Link]
/**
* Ce code doit être téléversé sur le Arduino.
*
* Communique avec l'ordinateur pour lui envoyer la valeur
void setup() {
// Vitesse de la communication = 9600 bauds
[Link](9600);
pinMode(sortie_numerique, OUTPUT);
}
void loop() {
char octet_recu;
if ([Link]() > 0) {
// Lisons ce que l'on reçoit via le sériel
octet_recu = [Link]();
if (octet_recu == '1') {
digitalWrite(sortie_numerique, HIGH);
} else {
digitalWrite(sortie_numerique, LOW);
}
}
// Lecture de l'entrée analogique 0:
valeur_captee = analogRead(entree_analogique);
char envoyer = 'a' + map(valeur_captee, 0, 1023, 0, 25);
[Link](envoyer);
// On attend un peu pour laisser le temps au ADC de respirer
delay(10);
}
Une fois que le code pour l'Arduino est installé sur l'appareil, branchez-le en USB sur votre ordinateur, si ce
n'est déjà fait, et démarrez le sketch Processing. Vérifier dans le menu Arduino > Tools que les
configurations de « Board » et « Serial Port » sont correctes. Lorsque la fenêtre du sketch est ouverte dans
Processing et que vous appuyez sur la barre d'espacement, la LED associée à la sortie 13 (intégrée à la
plaquette Arduino) devrait s'allumer comme suit :
println(dernier_recu);
...
rect(10, 90, largeur * multiplicateur, 10);
println(dernier_recu);
}
... on peut visualiser dans la console de Processing le défilement des lettres qui correspondent aux variations
électrostatiques captées entre les bornes « 0 » et « Gnd » de la carte Artuino.
En examinant le code destiné au logiciel Arduino, vous pouvez constater qu'il s'apparente à Processing. Ce
n'est toutefois pas le même langage de programmation, il s'agit en fait de C++ et non pas de Java. La volonté
de simplifier le processus de programmation se retrouve toutefois dans les deux environnements : Arduino
offre aux créateurs la possibilité d'expérimenter relativement facilement la conception d'objets électroniques.
Dans notre exemple, nous avons créé un petit protocole de communication entre l'ordinateur et le micro-
contrôleur, entre Processing et Arduino. Relativement simple à réaliser et à comprendre, il n'est ni très
flexible ni très optimal. Si vous avez besoin d'un protocole plus robuste, nous vous invitons à visiter le site
de Arduino pour trouver plusieurs propositions intéressantes de librairies et d'exemples. Le protocole
Messenger ([Link] assez simple, pourra sans doute répondre
à vos besoins.
En savoir plus
Pour en savoir plus sur Arduino, nous vous invitons à consulter le manuel en français consultable librement
sur la plateforme Flossmanuals : [Link]
Un ouvrage collectif
Production originale en français, ce manuel est vivant : il évolue au fur et à mesure des contributions. Pour
consulter la dernière version actualisée, nous vous invitons à visiter régulièrement le volet francophone de
Flossmanuals sur le site [Link] et plus particulièrement sur la page d'accueil du manuel
[Link]
Le coeur du manuel d'environ 270 pages a été réalisé en 5 jours dans le cadre d'un Booksprint qui s'est tenu
à Paris du 6 au 10 septembre 2010 à l'initiative et avec le soutien de l'Organisation internationale de la
Francophonie ([Link]).
Expérimentée et popularisée par la Floss Manuals Fondation dans le cadre de ses activités de création de
manuels multilingues sur les logiciels et pratiques libres, la méthodologie du Booksprint permet de rédiger
en un temps très court des livres de qualité. Un groupe de 6 experts francophones de Processing originaires
d'Amérique du Nord, d'Europe et d'Afrique se sont retrouvés dans un même lieu pour rédiger ce manuel.
L’usage de la plate-forme de co-rédaction en ligne a permis également à d'autres personnes intéressées de
s’associer à distance à l’expérience.
Facilitateurs :
Adam Hyde
Elisa de Castro Guerra
Jean-Francois Renaud
Caroline Kassimo-Zahnd
Jerome Saint-Clair
Christian Ambaud
N'hésitez pas à votre tour à améliorer ce manuel en nous faisant par de vos commentaires dans la liste de
diffusion francophone de Flossmanuals, ou, si vous avez des talents de rédacteur et une bonne connaissance
de Processing, à vous inscrire en tant que contributeurs pour proposer la création de nouveaux chapitres.
Vous trouverez en fin d'ouvrage la liste complète des personnes ayant participé jusqu'à ce jour à la co-
rédaction du manuel.
Ce manuel est disponible depuis le site de Flossmanuals sous plusieurs formes : livre imprimé, pages web,
pdf et ePub, ce dernier format permettant de le consulter facilement sur des appareils portatifs.
Applet
En Java, un applet (ou une appliquette) est un programme que l'on peut intégrer dans une page web. En
exportant votre sketch sous cette forme, Processing permet d'exécuter votre dessin, animation, jeu interactif,
etc. de manière autonome sur la page d'un site internet.
Application
Voir programme.
Arduino
Arduino est une plate-forme libre de création d'objets électroniques composée d'un appareil d'entrée-sortie
configurable (dénommé un micro-contrôleur) et d'un environnement de programmation. Cet environnement
est dérivé de celui de Processing et il est possible d'exécuter des sketchs sur ce type d'appareils
programmables. Voir aussi Communiquant (objet).
Argument
Voir paramètres.
Assignation
Une assignation désigne le fait d'attribuer une valeur à une variable. On utilise l'opérateur = pour attribuer
une valeur à une variable.
Attribut
Un attribut, c'est une variable qui appartient à une classe ou un objet.
Bloc
Un bloc, désigné par deux accolades { } est un groupement d'instructions qui seront exécutées ensemble.
Elles sont utilisées pour délimiter les conditions, les boucles, les méthodes et les classes.
Booléen
Le booléen est un type de variable qui peut être vrai ou faux. Il permet de tester des conditions.
Boucle
Une boucle est un bloc dont les instructions vont être exécutées plusieurs fois à la suite soit selon un nombre
prédéfini de fois soit selon une condition. Les instructions for et while permettent de réaliser des boucles.
Chaque étape d'une répétition est appelée itération.
Commentaire
Un commentaire est une instruction qui sera ignorée par l'ordinateur au moment de l'exécution du
programme. Elle permet au programmeur d'ajouter des notes dans son code afin de le rendre davantage clair
: cette méthode facilite la compréhension ultérieure du programme en précisant l'utilité de telle ou telle
variable, méthode, etc.
Communiquant (objet)
Objet technologique dont la fonction est de faire transiter des informations entre le monde physique, le
monde des objets et les êtres vivants. Dans le cadre de ce manuel, ce terme s'applique notamment à des
objets conçus à partir de petits circuits électroniques autonomes chargés de capter des informations sur leur
environnement (mouvement, chaleur, contact...), de les transmettre et éventuellement de réagir en exécutant
des actions. Voir aussi Arduino.
Concaténation
La concaténation est une opération qui consiste à assembler plusieurs variables (texte, nombre, etc.) en une
seule chaîne de caractère. On utilise le symbole «« + » pour concaténer des variables.
Condition
Les conditions permettent d'exécuter une série d'instructions de manière conditionnelle après qu'une
instruction ait été validée ou non.
Console
La console est la zone située en bas de la fenêtre de l'environnement de développement (la fenêtre d'édition)
de Processing. Elle permet d'afficher du texte à des fins de test et de correction d'erreurs (débogage) pendant
que notre programme fonctionne.
Constructeur
Dans le jargon informatique, ce terme s'applique à la notion de classe en programmation. Le constructeur est
une méthode portant le même nom que la classe invoquée lorsqu'on crée une instance de cette classe. Cette
définition vous semble obscure ? Rassurez-vous ! Le plus simple est d'aller lire le chapitre intitulé « Les
objets » du manuel.
Contour
Le contour (méthode stroke()) définit la couleur utilisée pour dessiner la bordure d'une forme
géométrique.
Déboguer, débogage
Ce terme désigne l'action de tester un programme et d'en éliminer les erreurs et les fonctionnements
inadéquats. On distingue deux étapes : la suppression des erreurs de syntaxe, de langage et fautes de frappe
qui empêchent l'exécution du programme ; la correction de la logique du programme et le traitement des cas
de figure non prévus initialement.
Déclaration
La déclaration d'une variable consiste à réserver un espace mémoire par un nom pour un type donné. Une
déclaration et une assignation peuvent être combinées.
Espace colorimétrique
Un espace colorimétrique est une manière de gérer la définition des couleurs. Par défaut Processing utilise le
mode RVB (rouge, vert, bleu), mais offre aussi l'usage du mode TSV (teinte, saturation, valeur).
Folioscope
Un folioscope est une séquence d'images imprimées et reliées sous forme de livret qui peuvent être vues en
séquence animée lorsque l'on tourne les pages rapidement avec son pouce. Par analogie cela désigne les
animations images par image. En anglais, on utilise le terme flipbook.
Fonction
Une fonction est comme une méthode, mais à l'extérieur d'une classe. Étant donné qu'en Java, on ne peut pas
définir de fonction, nous avons évité ce terme dans ce manuel. Cependant, ce terme est beaucoup utilisé sur
le site Web de Processing, car le sketch se trouve en fait à l'intérieur d'une classe que nous ne voyons pas.
Voir méthode.
Hexadécimal
La notation hexadécimale est une manière de noter les chiffres en base 16. Dans cette notation, les chiffres
supérieurs à 9 sont représentés au moyen de lettres. On l'utilise notamment pour représenter des couleurs
pour le Web.
Incrémentation
Ajouter 1 à la valeur d'une variable de type int.
Instance
Une instance est un objet. Voir objet.
Itération
Voir boucle.
Java
Java est un langage de programmation orienté objet développé à l'origine par Sun Microsystems. Il a la
particularité d'utiliser une machine virtuelle ce qui le rend utilisable sur de nombreuses plateformes sans
nécessiter d'adaptations. Il est publié sous licence GNU GPL. Processing utilise le langage Java.
Librairie
Une librairie est un ensemble de classes qui sont réunies dans un fichier afin d'être utilisables dans plusieurs
sketchs.
Lissage
Le lissage est une technique qui permet d'éliminer les effets d'escaliers qui apparaissent lorsqu'on dessine
des lignes diagonales ou des courbes.
Liste
Une liste est un ensemble de données d'une certaine taille regroupées dans une même variable. Les valeurs
sont placées l'une après l'autre. Chaque donnée est identifiée par un numéro, commençant par 0, qui rend son
accès aisé.
Méthode
Une méthode est un ensemble d'instructions regroupées dans un même bloc de code et accessibles par un
simple mot clé.
Modulo
Le modulo est une opération qui permet d'obtenir le reste de la division euclidienne de deux nombres. Par
exemple le reste de la division de 11 par 3 est 2 (11 / 3 = 3, reste 2). De manière plus générale, si on prend
deux nombres x et y, le reste de la division de x par y est strictement inférieur à y. L'opérateur modulo
permet de compter sans jamais dépasser un certain nombre (la base du modulo). Ainsi, vous pouvez avoir
besoin de créer des animations cycliques dont la fréquence (le nombre d'animations par cycle) s'adapte en
fonction d'autres éléments, par exemple la taille de la fenêtre de visualisation de l'espace de dessin. Pour
déterminer à partir d'une valeur donnée ce nombre d'animations par cycle, la solution la plus simple consiste
à utiliser l'opérateur modulo %.
OpenGL
OpenGL est une librairie graphique 2D/3D capable d'exploiter les ressources d'une carte graphique pour
augmenter les performances. Processing peut au besoin utiliser cette technologie.
P3D
P3D est le mode de représentation 3D de base de Processing. Il est plus lent qu'OpenGL, mais plus simple
d'utilisation et plus facile à faire fonctionner sur différents types de systèmes d'exploitation (Linux, OS X,
Windows, etc.).
Paramètre
Les paramètres d'une méthode sont des valeurs d'entrée qu'on fournit à la méthode et qu'elle utilise en
interne pour effectuer des actions.
Programme
Un programme est un ensemble d'instructions informatiques et de ressources (fichiers images, sons, textes,
etc.) qui forme un tout et qui exécute une série d'actions prédéfinies dont le résultat peut être visuel, sonore,
interactif, etc. Sketch est le nom donné à un programme dans Processing.
Remplissage
La couleur de remplissage est la couleur utilisée pour dessiner l'intérieur des formes géométriques. On la
spécifie en appelant la méthode fill().
Série
Le port série sert à connecter votre ordinateur à un certain nombre d'appareils périphériques. Votre
ordinateur échange des informations avec ce matériel externe en envoyant des séries d'instructions sous
forme de bytes.
Sketch
Sketch est le nom donné à un programme dans Processing.
Tableau
Voir liste
Timer
En jargon informatique, un timer désigne un système (objet physique ou simple code informatique) qui
exécute une action à intervalle régulier.
Transformation
Une transformation géométrique est une modification de la position, de la rotation ou de l'échelle d'un
élément du dessin (ligne, rectangle, cercle, etc.). Elle s'effectue avant l'opération de dessin de l'élément.
Tween
En animation, un tween désigne l'action de calculer les positions intermédiaires entre deux points d'une
animation. Ce mot provient de l'anglais in between.
Radian
Le radian est une unité de mesure d'angle utilisée pour les calculs de trigonométrie. Toutes les méthodes de
calcul d'angle de Processing fonctionnent avec cette unité. Un cercle complet (360°) vaut 2 x PI, soit environ
6,2831. La méthode radians(NOMBRE) permet de convertir un nombre de degrés en radians.
Variable
Une variable est un espace réservé de la mémoire de l'ordinateur dans lequel l'utilisateur peut stocker des
informations. On lui donne un nom, un type et une valeur.