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 a été adapté dans différents langages :
Ici, nous allons utiliser la version en JavaScript : P5.js, créée par Lauren McCarthy. Pour le « vrai » Processing, voir cette page.
Un fichier « squelette » a été préparé :
squelette_p5.html. Ouvrez-le dans un nouvel onglet
pour observer le code de ce fichier mais aussi le code de sketch.js
.
squelette_p5.html
charge la bibliothèque P5.js ;squelette_p5.html
charge ensuite sketch.js
.sketch.js
contient le programme écrit en Processing
(ou plus précisément en P5.js).Une bonne pratique est d’avoir un onglet ouvert sur la documentation.
Ce sont les deux fonctions principales de 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 P5.js qui s’en occupe. Notre travail, c’est de définir
ces fonctions.
function setup() {
... ici du code ...
}
function draw() {
... ici du code ...
}
createCanvas(w, h)
définit la taille de la fenêtre (il faut lui donner des
entiers) ;background
et fill
indique les couleurs de fond et de remplissage au
format Rouge Vert Bleu (nombres de 0 à 255) ;ellipse(cx, cy, dx, dy)
dessine une ellipse.En général, quel type de fonction mettre dans setup
, quelle type de fonction
mettre dans draw
?
setup
correspond à la mise en place de l’animation, donc aux
initialisations.
draw
correspond à l’animation en elle même, donc aux dessins des
formes mobiles.
Comment dessiner un disque ?
Modifier le programme afin d’avoir un disque de rayon 20 pixels dans le coin en bas à gauche de l’animation.
// Pong
function setup() {
createCanvas(640, 480);
background(0,0,255);
fill(255,0,0);
}
function draw() {
ellipse(20, 460, 40, 40);
}
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 ?
Une variable est l’association entre un nom et une valeur.
Nous allons utiliser des variables pour les coordonnées de la balle car si nous voulons que la balle bouge, il faut que ses coordonnées varient !
Nous appelleront x
et y
les coordonnées de la balle.
setup
et avec le mot-clef
var
.setup
(leur donner une première valeur).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
var x; // abscisse du centre de l’ellipse
var y; // ordonnée
function setup() {
createCanvas(640, 480);
background(0,0,255);
fill(255,0,0);
x = 320;
y = 240;
}
function draw() {
ellipse(x, y, 40, 40);
}
Pour faire bouger la balle, 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
.
Comme la balle par du coin inférieur gauche, on ajoute 3 aux abscisse, et on retire 3 aux ordonnées.
// Pong
var x; // abscisse du centre de l’ellipse
var y; // ordonnée
function setup() {
createCanvas(640, 480);
background(0,0,255);
fill(255,0,0);
x = 320;
y = 240;
}
function draw() {
ellipse(x, y, 40, 40);
x = x + 3;
y = y - 3;
}
Sauf que la balle laisse une « trace ». Il faut donc effacer l’écran
pour faire place nette avant chaque image avec background(couleur_fond)
.
Mais à quel endroit dans le programme ?
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 ?
Pour éviter que la balle ne traverse le mur, nous utiliserons une inégalité
plutôt qu’une égalité.
En programmation, la structure qui correspond à ce que l’on veut faire est la structure conditionnelle, que l’on code ainsi en JavaScript :
if (condition) {
...code à exécuter quand la condition est vraie...;
}
Puisque l’on veut modifier la vitesse, il faut aussi la stocker dans une
variable. On appellera vitesse_h
la vitesse horizontale de la balle et
vitesse_v
la vitesse verticale. Il faut les déclarer et les initialiser.
Comme il y a quatre murs, nous aurons besoin de quatre conditions.
// Pong
var x;
var y;
var vitesse_h;
var vitesse_v;
function setup() {
createCanvas(640, 480);
background(0,0,255);
fill(255,0,0);
x = 20;
y = 460;
vitesse_h = 3;
vitesse_v = -3;
}
function draw() {
ellipse(x, y, 40, 40);
if (x >= 640) {
vitesse_h = -3;
}
if (y >= 480) {
vitesse_v = -3;
}
if (x <= 0) {
vitesse_h = 3;
}
if (y <= 0) {
vitesse_v = 3;
}
x = x + vitesse_h;
y = y + vitesse_v;
}
Note : Cette partie est difficile. Si vous êtes pressé, passez directement à la partie « raquette ».
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. Lequel ?
On peut regrouper les deux conditions qui correspondent à ces murs grâce à un
« ou » logique, qui s’écrit ||
en JavaScript.
if ((x >= 620) || (x <= 20)) {
vitesse_h = -vitesse_h;
}
Que faire si on veut jouer avec une balle plus grosse, 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
.
Dans le jeu Pong, il y a une « raquette » de chaque côté de l’écran. Nous
allons commencer par une seule raquette en utilisant la variable spéciale
mouseY
afin que la raquette suive la souris.
Taper quelque part rect(??, mouseY, ??, ??)
.
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 ! Si possible pas de valeurs codées en dur dans draw
!
Du côté de la raquette, nous n’allons faire rebondir la balle que si le joueur a placé la raquette au bon endroit. Quelles modifications apporter au programme ?
Penser à une couleur pour le fond et essayer de l’obtenir en changeant
background(...)
.
fill(...)
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(...)
, 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.
function setup() { // Les actions situées entre les accolades de cette fonction
// ne sont effectuées qu'une seule fois au démarrage du sketch.
}
function draw() { // Les actions situées entre les accolades de cette
// fonction sont effectuées en boucle jusqu'à fin du sketch.
}
createCanvas(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.
var mavar; // Déclare la variable nommée mavar.
mavar = 10.0; // Affecte à la variable mavar la valeur 10.0.
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).