Pong en javascript – vitesse et trajectoire

Onzième partie consacrée au développement du jeu vidéo html5 pong: vitesse et trajectoire de la balle. L’intelligence artificielle a un côté parfait. Il n’est quasi pas possible de la battre. Pour rendre les choses un peu plus jouables, et donc agréable pour le joueur, l’objectif est rendre imparfait cette intelligence artificielle. Comment ? En modifiant la vitesse de la balle mais aussi sa trajectoire avec la raquette.

Prérequis pour la vitesse et la trajectoire de la balle

Avoir lu les tutoriaux consacrés à 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 et au 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. Le renvoi de la balle par les raquettes Coder le jeu video pong – Renvoi de la balle. La gestion des effets sonores Coder le jeu video pong – Ajout des effets sonores. La gestion de l’IA Coder le jeu vidéo Pong – Intelligence artificielle. La gestion du score et de l’engagement Coder le jeu vidéo Pong – Score et engagement. La gestion des parties Coder le jeu vidéo Pong – Début et fin de partie.

Modification de la trajectoire de la balle

Jusqu’à présent, la trajectoire de la balle est simple puisqu’elle se déplace dans quatre directions obliques possibles. Pour modifier cette trajectoire, vous utilisez deux propriétés de l’objet balle : directionX et directionY . Elles indiquent dans quelle sens elle se déplace mais aussi à quel rythme.

En effet, les valeurs absolues (sans le signe) de directionX et directionY indiquent aussi le pas de déplacement en pixels sur le terrain.

Actuellement, elles sont de 1 : le pas sur l’axe des abscisses est identique à celui sur l’axe des ordonnées. La trajectoire de la balle est de 45° par rapport à l’horizontale.

Pour changer cette trajectoire, modifiez le pas l’axe des abscisses ou des ordonnées. Pour  qu’il soit différent d’un axe à l’autre il faut:
– pas de 1 sur l’axe X, pas de 2 sur l’axe Y. La trajectoire de la balle fait qu’elle monte ou descend plus vite qu’elle ne déplace vers la droite ou la gauche;
– à l’inverse, pas de 2 sur l’axe X, pas de 1 sur l’axe Y . La trajectoire de la balle fait qu’elle monte ou descend plus lentement qu’elle ne déplace vers la droite ou la gauche.

Pour modifier la trajectoire de la balle, vous devez donc agir sur ces deux variables. N’oubliez pas que c’est la raquette qui modifie la trajectoire lorsqu’elle renvoie la balle. Plus la balle est excentrée sur la raquette lors de la frappe, plus le changement de trajectoire est important.

Pour effectuer ce changement de trajectoire, il faut déterminer à quel endroit la raquette  est percutée. Et définir des zones d’impacts.

Une zone d’impact est une zone de la raquette qui, percutée par la balle, modifie sa trajectoire. Chaque zone d’impact modifie de manière unique la trajectoire de la balle.

Comme illustré ci-dessous, la raquette est divisée en 5 points d’impact distincts.  Chacun agit sur la trajectoire de la balle, chacun fait sa propre modification de trajectoire.

Il est donc nécessaire de savoir à quel endroit la balle frappe la raquette au moment de l’impact. Ceci passe par le biais d’une fonction. En fonction de l’ordonnée de la balle par rapport à celui de la raquette, elle indique quelle zone a été touchée par la balle.

Pour l’exemple, définissez les 5 zones d’impact qui seront renvoyées par la fonction ballOnPlayer rattachée au namespace game.
– TOP pour le haut de la raquette;
– MIDDLETOP à mi chemin entre le centre et le haut de la raquette;
– MIDDLEBOTTOM à mi chemin entre le centre et le bas de la raquette;
– BOTTOM pour le bas de la raquette;
– et CENTER pour le centre de la raquette.

En javascript, la fonction ballOnPlayer.

const game = {
....
  ballOnPlayer : function(player, ball) {
    var returnValue = "CENTER";
    var playerPositions = player.height/5;
    if ( ball.posY > player.posY && ball.posY < player.posY + playerPositions ) {
      returnValue = "TOP";
    } else if ( ball.posY >= player.posY + playerPositions && ball.posY < player.posY + playerPositions*2 ) {
      returnValue = "MIDDLETOP";
    } else if ( ball.posY >= player.posY + playerPositions*2 && ball.posY < player.posY + 
      player.height - playerPositions ) {
      returnValue = "MIDDLEBOTTOM";
    } else if ( ball.posY >= player.posY + player.height - playerPositions && ball.posY < player.posY + 
      player.height ) {
      returnValue = "BOTTOM";
    }
    return returnValue;
  },
....
}

Comme décidé auparavant, le changement de trajectoire se fait lorsque la balle est frappée par une raquette. Plus spécifiquement lorsqu’il y a collision entre la balle et la raquette.

Jusqu’à présent, c’est la fonction game.collideBallWithPlayersAndAction qui prendt en charge les collisions. Elle continue de le faire, cependant elle opére le changement de trajectoire.

Le changement de trajectoire est dévolu à une autre nouvelle fonction utilisatrice de la fonction game.ballOnPlayer que vous appelez changeBallPath.

Elle reprend les changements tels qu’ils sont indiqués sur le schéma ci-dessus en distinguant le positionnement de la raquette (gauche ou droite).

const game = {
....
  changeBallPath : function(player, ball) {
    if ( player.originalPosition == "left" ) {
      switch( game.ballOnPlayer(player, ball) ) {
        case "TOP":
          ball.directionX = 1;
          ball.directionY = -3;
          break;
        case "MIDDLETOP":
          ball.directionX = 1;
          ball.directionY = -1;
          break;
        case "CENTER":
          ball.directionX = 2;
          ball.directionY = 0;
          break;
        case "MIDDLEBOTTOM":
          ball.directionX = 1;
          ball.directionY = 1;
          break;
        case "BOTTOM":
          ball.directionX = 1;
          ball.directionY = 3;
          break;
      }
    } else {
      switch( game.ballOnPlayer(player, ball) ) {
        case "TOP":
          ball.directionX = -1;
          ball.directionY = -3;
          break;
        case "MIDDLETOP":
          ball.directionX = -1;
          ball.directionY = -1;
          break;
        case "CENTER":
          ball.directionX = -2;
          ball.directionY = 0;
          break;
        case "MIDDLEBOTTOM":
          ball.directionX = -1;
          ball.directionY = 1;
          break;
        case "BOTTOM":
          ball.directionX = -1;
          ball.directionY = 3;
          break;
      }
    }
....
}

Pour terminer, integrez à la fonction game.collideBallWithPlayersAndAction ces possibles changements de trajectoire.

const game = {
....
  collideBallWithPlayersAndAction : function() { 
    if ( this.ball.collide(game.playerOne) ) {
      game.ball.directionX = -game.ball.directionX;
      this.playerSound.play();
    }
    if ( this.ball.collide(game.playerTwo) ) {
      game.ball.directionX = -game.ball.directionX;
      this.playerSound.play();
    }
  },
....
}

devient

const game = {
....
  collideBallWithPlayersAndAction : function() { 
    if ( this.ball.collide(game.playerOne) ) {
      this.changeBallPath(game.playerOne, game.ball);
      this.playerSound.play();
    }
    if ( this.ball.collide(game.playerTwo) ) {
      this.changeBallPath(game.playerTwo, game.ball);
      this.playerSound.play();
    }
  },
....
}

La vitesse de la balle

La vitesse a déjà été évoquée dans l’article Animer la balle.

A ce propos, l’objet ball intègre une propriété speed qui indique la vitesse de déplacement de la balle fixé jusqu’à présent à 1.

Cette vitesse speed est en réalité un coefficient qui s’applique aux variables directionX et directionY.

Si ce coefficient est inférieur à 1, la balle ralentit.
Si ce coefficient est supérieur à 1, la balle accélère. Et plus ce coefficient est élevé, plus la balle va vite. Ce coefficient peut être associé à la vitesse de la balle.

Dans le code existant, il s’applique déjà mais n’a aucun effet puisqu’il est fixé à la valeur 1. Depuis la méthode move de l’objet ball.

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

Avec une vitesse suffisamment élevée, l’intelligence artificielle devient battable.

Le plus simple est que la balle accélère au fur et à mesure qu’un échange dure. Augmentez la valeur de game.speed à intervalle régulier par le biais d’une nouvelle méthode speedUp de l’objet ball.

ball : {
....
  speedUp: function() {
    this.speed = this.speed + .1;
  },
....
}

Pour appliquer l’accélération, il suffit de l’appeler à intervalles réguliers grâce à la fonction javascript setInterval.

Ce choix est purement arbitraire, il est aussi possible de donner un coup d’accélération lorsque la balle percute une raquette.

La fonction setInterval prend en paramètres :
– une fonction à appeler;
– un intervalle exprimé en millisecondes qui correspond au temps qui sépare deux appels de la fonction donnée en premier paramètre.

Pour plus de lisibilité, encapsulez le code dans une fonction au nom parlant speedUpBall rattachée au namespace game.

const game = {
....
  speedUpBall: function() { 
    setInterval(function() {
      game.ball.speedUp();
    }, 5000);
  }
....
}

Il n’y a plus qu’à l’appeler à l’initialisation du jeu.

const game = {
....
  init : function() {
  ....
    game.speedUpBall();
  },
....
}

Et à réinitialiser la valeur de la vitesse de la balle lorsqu’elle est lancée depuis la fonction reinitGame.

const game = {
....
  reinitGame : function() {
    this.ball.inGame = false;
    this.ball.speed = 1;
    this.playerOne.score = 0;
    this.playerTwo.score = 0;
    this.scoreLayer.clear();
    this.displayScore(this.playerOne.score, this.playerTwo.score);
  },
....
}

Vous avez maintenant une IA que vous pouvez battre. Le jeu commence à devenir plus intéressant puisqu’il est désormais jouable.

Vous avez vu la vitesse et la trajectoire de la balle. Dans l’article suivant, un petit ravalement de façade ici.

Apprenez à créer un jeu vidéo en une soirée.

Accessible à tous. Pour moins de 10€.
Dernières places disponibles pour l'année 2024.

Ce format court sera abandonné en 2025.

Voir l'événement

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