tite fractale

Prise en main de P5.js

1. Introduction

Dans cette activité, nous allons reconstituer un des jeux vidéos les plus anciens : Pong (voir l’article Wikipedia), avec le langage Processing.

pong

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.

2. Mise en place

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.

Une bonne pratique est d’avoir un onglet ouvert sur la documentation.

3. setup() et draw()

Ce sont les deux fonctions principales de pour créer une animation.

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 ...
}

4. Une balle sur le terrain

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 ?

Dessiner une ellipse ayant ses deux diamètres égaux.

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 ?

Les ordonnées croissantes sont vers le bas. Cela correspond aux directions de lecture des occidentaux : de gauche à droite puis de haut en bas.

5. Déplacement de la balle

5.1. Variables

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.

  1. Déclarer les variables en tête de fichier, avant setup et avec le mot-clef var.
  2. Initialiser les variables dans setup (leur donner une première valeur).
  3. Remplacer 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

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);
}

5.2. Mouvement

Pour faire bouger la balle, les variables x et y doivent être modifiées. Dans quelle fonction, setup ou draw ?

Dans 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 ?

Grâce à ce que l’on appelle une incrémentation (affectation à une variable de la même valeur qu’avant, plus une certaine 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 ?

6. Rebonds

6.1. Analyse du problème

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...;
}

6.2. Le code

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;
}

7. Factorisations

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)$$

7.1. Factorisation des conditions

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;
}

7.2. Factorisation des dimensions

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.

8. Raquette

8.1. Forme et déplacement

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 !

8.2. Collision

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 ?

9. Personnaliser les couleurs

9.1. Le fond

Penser à une couleur pour le fond et essayer de l’obtenir en changeant background(...).

9.2. La balle

fill(...) décide la couleur des prochains objets dessinés. Essayer de dessiner une balle jaune et une raquette bleue.

10. Approfondissement

10.1. Autres idées

À vous de jouer, à vous d’implémenter vos idées (score à afficher avec text(...), changement de couleurs à chaque rebond…).

10.2. D’autres tutoriels

11. Memento

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).




J.Bourdon et É.Languénou, rédigé par Christophe Gragnic, le 15/11/2019, 09h36'56".






Page générée le 27/05/2021, 09h53'27" (source).
historique de la page
historique global