Pong en javascript – animer la balle

Comment animer la balle dans le jeu Pong. Troisième partie de cette série d’articles consacrée au développement d’un jeu vidéo html5 javascript. L’objectif est d’animer la balle en la faisant rebondir sur les murs latéraux du terrain de jeu.

 

Prérequis pour animer la balle dans le jeu Pong

Avoir lu les tutoriaux consacrés à l’initialisation du projet Coder le jeu vidéo Pong 1ere partie. 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.

 

Le principe

Pour animer la balle dans le jeu Pong, il va falloir faire évoluer ses coordonnées.

Pour un mouvement horizontal vers la droite de l’écran, seule la position sur l’axe des abscisses est incrémentée. Pour un mouvement horizontal vers la gauche de l’écran, la position sur l’axe des abscisses est décrémentée.

Le principe est le même pour un mouvement vertical. La différence est que seule la position sur l’axe des ordonnées est incrémentée ou décrémentée.

Pour un mouvement ni horizontal, ni vertical, c’est la position sur les deux axes qui évolue.

Le code pour animer la balle dans le jeu Pong

L’objet ball est défini dans l’article précédent. Cet Objet comporte une série de propriétés dont la position matérialisée par les 2 variables posX et posY .

const game = {
  .....
  ball : {
   width : 10,
   height : 10,
   color : "#FFFFFF",
   posX : 200,
   posY : 200
  },
  
  init : function() {
  .....

Les variations des valeurs des 2 propriétés posX et posY permettent de bouger la balle sur le terrain.

Qui dit mouvement, dit vitesse. Du coup, ajoutons une nouvelle propriété relative à la vitesse de la balle.

const game = {
 .....
 ball : {
  width : 10,
  height : 10,
  color : "#FFFFFF",
  posX : 200,
  posY : 200,
  speed : 1
 },
  
 init : function() {
 .....

La valeur de la vitesse correspond à un incrément en pixels de la position de la balle. Incrément appliqué à chaque rafraichissement de l’affichage. Plus la valeur de cette propriété sera grande, plus la balle paraitra se déplacer vite. Cela peut être un des moyens pour jouer sur la difficulté du jeu.

En testant la valeur de cette variable, on remarque un inconfort visuel avec des valeurs trop élevées.

La valeur 1 donnée à la propriété fait que la balle se déplace vers le bas et la droite de l’écran de jeu.

Il reste à créer une méthode ou fonction dédiée au mouvement de la balle dans l’objet ball. Cette fonction fait varier la position de la balle par le biais de deux nouvelles variables directionX et directionY. Les propriétés directionX et directionY ne prennent chacune que 2 valeurs relatives au sens de déplacement sur les axes X (abscisses) et Y (ordonnées).

Pour un déplacement vers la droite de l’écran sur l’axe X, directionX vaudra 1.
Pour un déplacement vers la gauche de l’écran sur l’axe X, directionX vaudra -1.
Pour un déplacement vers le bas de l’écran sur l’axe Y, directionY vaudra 1.
Pour un déplacement vers la haut de l’écran sur l’axe Y, directionY vaudra -1.

const game = {
 ....
 ball : {
  ....
  move : function() {
   this.posX += this.directionX * this.speed;
   this.posY += this.directionY * this.speed;
  },
 }
 ....
}

Ce n’est toutefois pas suffisant. Il faut rafraichir l’affichage de la balle lorsque sa position change. Simple, il n’y a qu’à rappeler la fonction displayBall existante.

displayBall : function() {
 game.display.drawRectangleInLayer(this.playersBallLayer, this.ball.width, this.ball.height, this.ball.color, this.ball.posX, this.ball.posY);
},

Pour rendre la relecture du code plus simple, encapsulons l’appel de ces 2 fonctions dans une autre. Nous l’appellerons moveBall et nous la rattacherons au namespace javascript game.js.

const game = {
 ....
 moveBall : function() { 
  this.ball.move();
  this.displayBall();
 }, 
 ....
}

La fonction telle qu’elle est, la balle se déplace vers le bas et la droite de l’écran de jeu. Puis elle disparait de l’écran de jeu. Il faut donc la faire rebondir sur les bords de l’écran.

Le principe pour les rebonds est simple :
– lorsque la position de la balle atteint le bord droit de l’écran. En d’autres termes si sa valeur dépasse la longueur de l’écran de jeu. On inverse sa direction (la valeur de directionX) doit être inversée;
– même chose si la position de la balle atteint le bord gauche de l’écran. en d’autres termes si sa valeur est inférieure à 0.
– lorsque la position de la balle atteint le bas de l’écran (en d’autres termes si sa valeur dépasse la largeur de l’écran de jeu). On inverse sa direction (la valeur directionY) doit être inversée.
– même chose si la position de la balle atteint le haut de l’écran (en d’autres termes si sa valeur est inférieure à 0).

Au final, le code de la fonction bounce rattachée à l’objet ball :

const game = {
 ....
 ball : {
  ....
  bounce : function() {
   if ( this.posX > game.groundWidth || this.posX < 0 )
    this.directionX = -this.directionX;
   if ( this.posY > game.groundHeight || this.posY < 0  )
    this.directionY = -this.directionY;         
  },
 }
 ....
}

Nous intégrons l’appel dans la fonction moveBall.

const game = {
 ....
 moveBall : function() { 
  this.ball.move();
  this.ball.bounce();
  this.displayBall();
 }, 
 ....

Puis à appeler la fonction moveBall depuis la boucle main d’exécution main.

....
const main = function() {

 game.moveBall();

 requestAnimId = window.requestAnimationFrame(main);
}
....

Il reste une petite chose à régler, si nous exécutons le code en l’état, la balle laisse une traînée derrière elle.

displayBall : function() {
 game.display.drawRectangleInLayer(this.playersBallLayer, this.ball.width, this.ball.height, this.ball.color, this.ball.posX, this.ball.posY);
} 

La traînée est liée à l’absence de rafraîchissement de l’affichage. Le rafraîchissement consiste simplement à effacer le contenu du layer où sont affichés balle et joueurs avant le réaffichage de l’un ou l’autre.

Nous ajoutons une méthode d’effacement à l’objet layer.

....
 layer : {
  name : "",
  canvas : "",
  context2D : "",
  posX : null,
  posY : null,
  width : "",
  height : "",
  backgroundColor : "",
  zIndex : "",
     
  clear : function() {
   this.context2D.clearRect(0, 0, this.canvas.width, this.canvas.height);
  }
 },
....

Puis nous créons une fonction d’effacement de layer dans le namespace game.

const game = {
 ....
 clearLayer : function(targetLayer) {
  targetLayer.clear();
 }
 ....

Enfin, nous appelons la fonction d’effacement du namespace game depuis la boucle principale (main) du jeu.

const main = function() {

 game.clearLayer(game.playersBallLayer);
 game.moveBall();

 requestAnimId = window.requestAnimationFrame(main);
}

Les raquettes et la balle sont dessinées dans le même layer. Du coup, la fonction clearLayer va effacer la balle mais aussi les raquettes. Il faut donc réafficher les raquettes à chaque fois puisque elles sont sur le même layer que la balle. Utilisez la fonction displayPlayers du namespace game .

const main = function() {

 game.clearLayer(game.playersBallLayer);
 game.displayPlayers();
 game.moveBall();

 requestAnimId = window.requestAnimationFrame(main);
}

Vous avez vu comment animer la balle dans le jeu Pong. La suite du programme va consister à animer les raquettes, à suivre ici.

Explore l'univers de la création de jeux vidéo

Saisis ton prénom et ton e-mail pour recevoir ton livre GRATUIT et commence ton voyage ludique dès maintenant.

Bravo, jette un œil à ta boite mail pour télécharger ton guide.