La classe Balle
Plutôt que de manipuler directement le contexte du canvas, nous allons encapsuler les propriétés et les méthodes nécessaires pour gérer les balles dans une classe d’objet Balle
.
Dans le fichier classes/Balle.mjs
, ajoutez le code suivant :
1import { Balles } from './Balles.mjs'; // Importe la classe Balles depuis le fichier Balles.mjs2
3export class Balle { // Définition de la classe Balle et exportation de la classe4
5 /**6 * Fonction constructeur de la classe Balle7 *8 * Si les paramètres x, y, velociteX, velociteY, rayon et couleur ne sont pas définis,9 * ils sont initialisés avec des valeurs aléatoires10 *11 * @param { HTMLCanvasElement } canvas : Le canvas12 * @param { CanvasRenderingContext 2D } context : Le contexte de rendu 2D du canvas13 * @param { number } x : La position horizontale de la balle14 * @param { number } y : La position verticale de la balle15 * @param { number } velociteX : La vitesse de déplacement horizontale16 * @param { number } velociteY : La vitesse de déplacement verticale17 * @param { number } rayon : Le rayon de la balle18 * @param { string } couleur : La couleur de la balle19 * @returns { Balle } : Une instance de la classe Balle20 */21 constructor(canvas, context, x, y, velociteX, velociteY, rayon, couleur) {22
23 // Si le canvas ou le contexte de rendu 2D ne sont pas définis, on sort de la fonction24 if (canvas === undefined || context === undefined) return;25
26 this.canvas = canvas;27 this.context = context;28 this.x = x ? x : this.random(0, Balles.width);29 this.y = y ? y : this.random(0, Balles.height);30 this.rayon = rayon ? rayon : this.random(10, 20);31 this.couleur = couleur ? couleur : this.randomRGB();32 this.velociteX = velociteX ? velociteX : this.random(-7, 7);33 this.velociteY = velociteY ? velociteY : this.random(-7, 7);34 }35
76 collapsed lines
36 /**37 * Fonction qui génère un nombre aléatoire compris entre min et max38 * @param { number } min : La valeur minimale39 * @param { number } max : La valeur maximale40 * @returns { number } : Un nombre aléatoire compris entre min et max41 */42 random(min, max) {43 return Math.floor(Math.random() * (max - min)) + min;44 }45
46 /**47 * Fonction qui génère une couleur RGB aléatoire48 * @returns { string } : Une couleur RGB aléatoire49 */50 randomRGB() {51 return `rgb(${this.random(0, 255)},${this.random(0, 255)},${this.random(0, 255)})`;52 }53
54 /**55 * Fonction qui dessine la balle sur le canvas56 */57 dessiner() {58 this.context.beginPath();59 this.context.fillStyle = this.couleur60 this.context.arc(this.x, this.y, this.rayon, 0, 2 * Math.PI);61 this.context.fill();62 }63
64 /**65 * Fonction qui déplace la balle sur le canvas en fonction de sa vitesse66 * Si la balle atteint un bord du canvas, sa vitesse est inversée67 */68 deplacer() {69 if ((this.x + this.rayon) >= Balles.width) { // Si la balle atteint le bord droit du canvas70 this.velociteX = -(this.velociteX); // La vitesse horizontale est inversée71 }72
73 if ((this.x - this.rayon) <= 0) { // Si la balle atteint le bord gauche du canvas74 this.velociteX = -(this.velociteX); // La vitesse horizontale est inversée75 }76
77 if ((this.y + this.rayon) >= Balles.height) { // Si la balle atteint le bord bas du canvas78 this.velociteY = -(this.velociteY); // La vitesse verticale est inversée79 }80
81 if ((this.y - this.rayon) <= 0) { // Si la balle atteint le bord haut du canvas82 this.velociteY = -(this.velociteY); // La vitesse verticale est inversée83 }84
85 // On modifie les positions horizontales et verticales en fonction de la vitesse, ce qui donnera l'illusion que la balle se déplace86 this.x += this.velociteX;87 this.y += this.velociteY;88
89 }90
91 /**92 * Fonction qui vérifie si la balle est en collision avec une autre balle93 *94 * Si c'est le cas, la couleur des deux balles est modifiée avec une couleur aléatoire95 *96 * @param { Balle[] } balles : Un tableau contenant toutes les balles97 */98 collision(balles) {99 for (const ball of balles) {100 if ((!(this.x === ball.x && this.y === ball.y && this.velX === ball.velX && this.velY === ball.velY))) {101 const dx = this.x - ball.x;102 const dy = this.y - ball.y;103 const distance = Math.sqrt(dx * dx + dy * dy);104
105 if (distance < this.rayon + ball.rayon) {106 ball.couleur = this.couleur = this.randomRGB();107 }108 }109 }110 };111}
Prenez un moment pour étudier le code de la classe Balle
.
Notez que nous avons ajouté des méthodes pour dessiner la balle et pour la déplacer.
La classe Balles
Nous allons également encapsuler les balles dans une classe Balles
.
Cette classe contiendra un tableau d’objets Balle
et va gérer l’animation des balles.
Dans le fichier classes/Balles.mjs
, ajoutez le code suivant :
1import { Balle } from './Balle.mjs'; // Importe la classe Balle depuis le fichier Balle.mjs2
3export class Balles { // Définition de la classe Balles et exportation de la classe4
5 static width = 0; // Propriété statique width initialisée à 06 static height = 0; // Propriété statique height initialisée à 07
8 /**9 * Fonction constructeur de la classe Balles10 *11 * @param { HTMLCanvasElement } canvas : Le canvas12 * @param { number } nombreBalles : Le nombre de balles à générer13 * @param { number } width : La largeur du canvas14 * @param { number } height : La hauteur du canvas15 * @returns { Balles } : Une instance de la classe Balles16 */17 constructor(canvas, nombreBalles, width, height) {18
19 this.canvas = canvas; // Le canvas20 this.context = canvas.getContext('2d'); // Le navigateur crée un contexte de rendu 2D pour le canvas21
22 Balles.width = canvas.width = width; // La largeur du canvas est égale à la largeur de la fenêtre23 Balles.height = canvas.height = height; // La hauteur du canvas est égale à la hauteur de la fenêtre24
25 this.enMouvement = false; // La propriété enMouvement est initialisée à false. On utilisera cette propriété pour savoir si les balles sont en mouvement26 this.animationRequest = null; // La propriété animationRequest est initialisée à null. On utilisera cette propriété pour stocker l'identifiant de la requête d'animation27
28 this.context.fillStyle = 'rgba(0,0,0,0.25)'; // La couleur de remplissage est un gris semi-transparent29 this.context.fillRect(0, 0, this.width, this.height); // Un rectangle semi-transparent est dessiné sur tout le canvas30
31 this.balles = []; // Un tableau vide pour stocker les balles32
33 for (let i = 0; i < nombreBalles; i++) {34 this.balles.push(new Balle(this.canvas, this.context)); // On ajoute une nouvelle balle à chaque itération35 }90 collapsed lines
36 }37
38 /**39 * Getter de la propriété nombre40 * @returns { number } : Le nombre de balles41 */42 get nombreBalles() {43 return this.balles.length;44 }45
46 /**47 * Setter de la propriété width48 * @param { number } value : La largeur du canvas49 */50 set width(value) {51 Balles.width = value;52 this.canvas.width = value;53 }54
55 /**56 * Setter de la propriété height57 * @param { number } value : La hauteur du canvas58 */59 set height(value) {60 Balles.height = value;61 this.canvas.height = value;62 }63
64 /**65 * Fonction qui dessine les balles sur le canvas66 * et gère les collisions entre les balles67 * et les bords du canvas68 */69 render() {70 this.enMouvement = true; // On passe la propriété enMouvement à true71
72 this.context.fillStyle = 'rgba(0,0,0,0.25)'; // La couleur de remplissage est un gris semi-transparent73 this.context.fillRect(0, 0, Balles.width, Balles.height); // Un rectangle semi-transparent est dessiné sur tout le canvas74
75 // Pour chaque balle dans le tableau balles76 this.balles.forEach(balle => {77 balle.dessiner(); // On dessine la balle78 balle.deplacer(); // On déplace79 balle.collision(this.balles); // On gère les collisions80 });81
82 // On stocke l'identifiant de la requête d'animation dans la propriété animationRequest83 this.animationRequest = requestAnimationFrame(this.render.bind(this));84 }85
86 /**87 * Fonction qui ajoute une nouvelle balle au canvas88 * @param { number } x : La position horizontale de la balle89 * @param { number } y : La position verticale de la balle90 */91 ajouterBalle(x, y) {92 this.balles.push(new Balle(this.canvas, this.context, x, y));93 }94
95 /**96 * Fonction qui démarre l'animation des balles97 */98 demarrer() {99 if (this.enMouvement) return;100 this.render();101 }102
103 /**104 * Fonction qui arrête l'animation des balles105 * en annulant la requête d'animation106 * et en passant la propriété enMouvement à false107 * pour indiquer que les balles ne sont plus en mouvement108 */109 stop() {110 if (!this.enMouvement) return;111 cancelAnimationFrame(this.animationRequest);112 this.enMouvement = false;113 }114
115 /**116 * Fonction qui réinitialise le canvas117 * en supprimant toutes les balles118 * et en appelant la méthode render pour redessiner le canvas119 */120 reinitialiser() {121 this.balles.splice(0, this.balles.length);122 this.render();123 }124
125}
Prenez un moment pour étudier le code de la classe Balles
.
Deuxième conclusion
Nous avons maintenant encapsulé les balles dans des classes d’objets Balle
et Balles
.
Cela nous permet de mieux organiser notre code et de le rendre plus lisible et maintenable.
Dans la prochaine partie, nous allons finaliser le programme principal et ajouter des interactions utilisateur.