Pong en javascript – renvoi de la balle
Sixième partie consacrée au développement d’un jeu vidéo html5 javascript: renvoi de la balle. L’objectif du jour est de renvoyer la balle avec la raquette du joueur.
Prérequis pour renvoyer la balle
Lire les tutoriaux suivants :
– l’initialisation du projet Coder le jeu vidéo Pong;
– la mise en place de l’environnement du jeu constitué du terrain, du filet, des raquettes, de la balle et du score Coder le jeu vidéo Pong – Raquettes et Balle;
– l’animation de la balle Coder le jeu vidéo Pong – Animer la balle;
– le contrôle de la raquette par le joueur à l’aide du clavier Coder le jeu vidéo Pong – Animer les raquettes;
– le contrôle de la raquette par le joueur à l’aide de la souris Coder le jeu vidéo Pong – Controle à la souris.
Je vous conseille aussi la lecture de l’article consacré aux collisions des sprites : Javascript HTML5 collision de sprites
Le principe de renvoi de la balle
Cela consiste à changer la trajectoire de la balle lorsqu’elle entrera en collision avec la raquette. Si la raquette ne la rattrape pas, elle est considérée comme perdue et réapparait de l’autre côté du terrain.
A chaque cycle d’affichage, il faut tester s’il y a collision entre la balle et la raquette. S’il y a collision, la balle rebondit sur la raquette et change de trajectoire.
Comment va changer la trajectoire de la balle ?
La balle évolue dans 4 directions différentes.
– vers le haut et la droite, en incrémentant son abscisse et en décrémentant son ordonnée;
– vers le bas et la droite, en incrémentant son abscisse et en incrémentant son ordonnée;
– vers le bas et la gauche, en décrémentant son abscisse et en incrémentant son ordonnée;
– vers le haut et la gauche, en décrémentant son abscisse et en décrémentant son ordonnée.
La raquette du joueur est toujours celle de gauche. La balle arrive toujours par la droite du terrain de jeu. Il y a donc deux cas possibles de collision avec la raquette.
– la balle se dirige vers le bas et la gauche de l’écran
– la balle se dirige vers le haut gauche de l’écran
L’ordonnée de la balle continue d’évoluer dans le même sens avant et après la collision :
– lorsque la balle descend, elle continue de descendre lorsque la raquette la percute;
– lorsque la balle monte, elle continue de monter lorsque la raquette la percute.
Avant percussion avec la raquette, la balle se dirige de la droite vers la gauche donc son abscisse diminue.
Lorsqu’elle percute la raquette, elle doit se diriger de la gauche vers la droite donc son abscisse doit augmenter.
Dans les deux cas de collision, l’incrément de l’abscisse (game.ball.directionX) de la balle s’inverse.
Vous pouvez envisager des changements de trajectoire plus complexes . En fonction de l’endroit où la balle tape la raquette, mais ceci fera l’objet d’un prochain article.
Le code javascript
Créez une nouvelle méthode pour détecter les collisions entre la balle et la raquette. Dès lors, se pose une question. A qui rattacher cette fonction ? La balle, la raquette, non rattachée….
Une fonction non rattachée pose le problème de la réutilisation du code pour des développements futurs pour d’autres jeux : dans ce cas, elle sera spécifique au jeu.
Les raquettes, la balle sont des objets qui seront réutilisables en partie. Ils préfigurent ce que sont des sprites. Du moins, ces objets ont des propriétés communes qui pourraient être rassemblées dans un objet classe pour réutilisation.
Commencez par créer une nouvelle méthode collide au sein de l’objet ball. Fonction dédiée à la détection de collisions avec d’autres objets graphiques.
Pour en savoir plus sur la méthode de gestion des collisions, celle-ci est abordée en détail dans l’article Javascript HTML5 collision de sprites.
En adaptant le code de l’article Javascript HTML5 collision de sprites, on obtient.
const game = {
....
ball : {
....
collide : function(anotherItem) {
if ( !( this.posX >= anotherItem.posX + anotherItem.width || this.posX <= anotherItem.posX
|| this.posY >= anotherItem.posY + anotherItem.height || this.posY <= anotherItem.posY ) ) {
// Collision
return true;
}
return false;
},
....
}
Lors de l’appel de cette nouvelle fonction et si elle renvoie la valeur true, il y a collision. La trajectoire de la balle devra être modifiée.
Cette fonction renvoie un booléen :
– true s’il y a collision;
– false s’il n’y a pas collision.
Il ne reste plus qu’à intégrer la fonction collide dans le code existant, notamment la fonction principale.
Notez qu’il y a deux tests de collision à faire. Un pour chaque raquette (playerOne et playerTwo).
Pour une meilleure lisibilité, encapsulez ces tests dans une fonction comme ceci au sein du namespace game. Y intégrer l’action voulue : le renvoi de la balle (l’inversion de sa trajectoire sur l’axe des abscisses).
const game = {
....
collideBallWithPlayersAndAction : function() {
if ( this.ball.collide(game.playerOne) )
game.ball.directionX = -game.ball.directionX;
if ( this.ball.collide(game.playerTwo) )
game.ball.directionX = -game.ball.directionX;
},
....
}
Puis appelez cette fonction dans la boucle principale d’exécution qu’est main.
const main = function() {
// le code du jeu
game.clearLayer(game.playersBallLayer);
game.movePlayers();
game.displayPlayers();
game.moveBall();
game.collideBallWithPlayersAndAction();
// rappel de main au prochain rafraichissement de la page
requestAnimId = window.requestAnimationFrame(main);
}
La balle est renvoyée lorsqu’elle percute la raquette sur sa face avant. Cependant, une petite imperfection subsiste. On voit la balle en surimpression de la raquette avant que l’adversaire (raquette à droite de l’écran playerTwo) ne la renvoie.
Cette petite imperfection revient au code de détection des collisions qui ne prend pas en compte la largeur et la hauteur du sprite cible de la collision. Le correctif est très rapide.
const game = {
....
ball : {
....
collide : function(anotherItem) {
if ( !( this.posX >= anotherItem.posX + anotherItem.width || this.posX <= anotherItem.posX - this.width
|| this.posY >= anotherItem.posY + anotherItem.height || this.posY <= anotherItem.posY - this.height ) ) {
// Collision
return true;
}
return false;
},
....
}
Et le tour est joué. Le prochain article va consister à ajouter du son lors des chocs de la balle avec les murs et les raquettes. A suivre ici.