Dans cette activité, nous allons reconstituer un des jeux vidéos les plus anciens : Pong (voir l’article Wikipedia), avec le langage Processing.
Processing, d’abord créé par des artistes et pour des artistes, est devenu très populaire dans beaucoup de domaines mais aussi dans l’enseignement. Voir cet article sur Floss Manuals.
Processing peut être utilisé en ligne ou installé localement en le téléchargeant ici.
Ce sont les deux fonctions principales de Processing pour créer une animation.
setup
est exécutée une fois au lancement du programmedraw
est exécutée pour la construction de chaque image,
en général 25 fois par seconde.Il ne faut jamais appeler vous-même ces fonctions avec setup()
ou draw()
,
c’est le système de Processing qui s’en occupe. Notre travail, c’est de définir
ces fonctions.
void setup() {
... ici du code ...
}
void draw() {
... ici du code ...
}
size(w, h)
définit la taille de la fenêtre (il faut lui donner des entiers) et
ellipse(cx, cy, dx, dy)
dessine une ellipse. Quelle fonction mettre
dans setup
, quelle fonction mettre dans draw
?
Comment dessiner un cercle ?
// Pong
void setup() {
size(400, 300);
}
void draw() {
ellipse(200, 150, 50, 50);
}
C’est l’association entre un nom et une valeur. Nous appelleront x
et y
les coordonnées de la balle car si on veut que la balle bouge, il faut que
ses coordonnées varient.
Le type float
est le plus proche des nombres réels.
On déclare les variables en tête de fichier, avant setup
. Ensuite il faut
les initialiser dans setup
(leur donner une première valeur). Si on ne les
initialise pas, elles sont initialisées par défaut à 0
. Ensuite, on
remplace les coordonnées fixes du centre de l’ellipse par x
et y
,
Une déclaration, une initialisation et le remplacement peuvent sembler être une perte de temps, mais c’est ainsi que le mouvement va naître !
// Pong
float x; // abscisse du centre de l’ellipse
float y; // ordonnée
void setup() {
size(400, 300);
x = 200;
y = 150;
}
void draw() {
ellipse(x, y, 50, 50);
}
Les variables x
et y
doivent être modifiées. Dans quelle fonction,
setup
ou draw
?
draw
.
Comment s’y prendre pour stocker une nouvelle valeur dans les coordonnées du centre de la balle, disons 3 de plus que l’ancienne valeur ?
ma_variable = ma_variable + augmentation
.
Sauf que la balle laisse une « trace ». Il faut effacer l’écran
pour faire place nette avant chaque image avec background(code_monochrome)
.
// Pong
float x; // abscisse du centre de l’ellipse
float y; // ordonnée
void setup() {
size(400, 300);
x = 200;
y = 150;
}
void draw() {
x = x + 3;
y = y + 3;
background(0);
ellipse(x, y, 50, 50);
}
Quelle particularité possède le repère géométrique de Processing ? En fait, en informatique, la plupart des repères sont orientés ainsi. Devinerez-vous pourquoi ?
Quand ont lieu les rebonds ? Donner des valeurs de x
et y
pour
lesquelles vous voudriez que la balle change de direction ?
à 500?, un peu avant?, un peu après? utilisation inégalité plutôt qu’égalité.
=>
Structure conditionnelle
if (condition) {
code à exécuter;
}
Puisque l’on veut modifier la vitesse, il faut en faire une variable. On
appellera vitesse_h
la vitesse horizontale de la balle et vitesse_v
la vitesse verticale.
Quatre murs -> quatre conditions.
// Pong
float x; // abscisse du centre de l’ellipse
float y; // ordonnée
float vitesse_h; // vitesse horizontale de la balle
float vitesse_v; // vitesse verticale
void setup() {
size(400, 300);
x = 200;
y = 150;
vitesse_h = 3;
vitesse_v = 3;
}
void draw() {
if (x >= 375) {
vitesse_h = -vitesse_h;
}
if (y >= 275) {
vitesse_v = -vitesse_v;
}
if (x <= 25) {
vitesse_h = -vitesse_h;
}
if (y <= 25) {
vitesse_v = -vitesse_v;
}
x = x + vitesse_h;
y = y + vitesse_v;
background(0);
ellipse(x, y, 50, 50);
}
Quand on programme, on cherche toujours à éviter de se répéter. Voir cet article Wikipedia pour plus de détails, mais le mot « factorisation » a le même sens qu’en mathématiques.
$$2×3 + 2×4 = 2(3 + 4)$$
On se rend compte que le choc sur les murs de gauche et de droite a le même effet. Comment regrouper les deux conditions qui correspondent à ces murs ?
if ((x >= 375) || (x <= 25)) {...}
Que faire si on veut jouer avec une balle plus petite, disons de 30 pixels de diamètre ? Et avec une fenêtre de taille différente, plus grande si l’on veut jouer sur le grand écran du salon, plus petite si l’on veut jouer sur un téléphone ?
Écrire un programme où aucune valeur n’est « hardcodée » dans la
fonction draw
.
rect(_, mouseY, _, _)
afin que la raquette suive la souris.
Comment affiner les coordonnées des coins de la raquette pour que le pointeur
de la souris soit au centre du rectangle qui la représente ?
Rappelez-vous ! Pas de valeurs codées en dur dans draw
!
Besoin d’opérateurs logiques.
&& pour la conjonction (ET)
Que changer dans le mouvement de la balle (retour total ou rebond
Penser à une couleur pour le fond et essayer de l’obtenir en changeant
background(int)
par background(int, int, int)
.
fill(int, int, int)
décide la couleur des prochains objets dessinés.
Essayer de dessiner une balle jaune et une raquette bleue.
À vous de jouer, à vous d’implémenter vos idées (score à afficher avec
text(str, int, int)
, changement de couleurs à chaque rebond…).
Un memento plus complet est disponible ici. Il pointe vers différentes références.
// Tout ceci qui suit "//" sur une même ligne est un commentaire.
// Processing n'en tient pas compte.
setup(){ // Les actions situées entre les accolades de cette fonction
// ne sont effectuées qu'une seule fois au démarrage du sketch.
}
draw(){ // Les actions situées entre les accolades de cette
// fonction sont effectuées en boucle jusqu'à fin du sketch.
}
size(800,600); // Fixe la taille de la fenêtre:
// 800 pixels horizontalement et 600 verticalement.
ellipse(cx,cy,dx,dy); // Dessine une ellipse de centre (cx,cy)
// de diamètres dx et dy (nombre de pixels sur
// l'horizontale et sur la verticale).
// Attention, les y croissants vont vers le bas.
float mavar; // Déclare la variable nommée mavar, de type flottant (réel).
mavar = 10.0; // La variable réelle de nom mavar reçoit la valeur 10.0.
int monautrevar; // Idem avec monautrevar, de type entier.
monautrevar = 10; // Idem avec la valeur entière 10.
background(0); // Remplit la fenêtre avec le niveau de gris 0 (du noir).
// Une valeur de 255 correspond à du blanc.
if(la_condition){ // Les actions situées entre les accolades de cette
// structure ne sont effectuées que si la_condition
} // est vraie. Si la_condition est fausse, on passe
// directement aux actions situées après l'accolade
// fermante. Quelques exemples de conditions:
// (x<0) (x<=y) (x==0) ((x<0)&&(y>200))
rect(px,py,l,h); // Dessine un rectangle de point haut gauche de
// coordonnées (px,py), de largeur l et de hauteur h.
mouseY // Variable prédéfinie contenant la position de la
// souris (en nb de pixels, en partant du haut).
fill(255); // Spécifie la couleur courante de remplissage
// (ici du blanc) des objets graphiques.
// Cette couleur sera utilisée jusqu'à ce qu'on
// appelle à nouveau la fonction fill().
Adapté du poster de l’atelier du LINA (J. Bourdon, É. Languénou).