Pong en javascript – contrôle à la souris

Cinquième partie consacrée au développement d’un jeu vidéo html5 javascript: contrôle à la souris. L’objectif du jour est d’animer la raquette du joueur par le biais de la souris. La raquette du joueur suivra le pointeur de la souris.

 

Prérequis pour « contrôle à la souris »

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.

 

Rappel

Pour le déplacement de la raquette, nous avons créé deux indicateurs dédiés goUp et goDown . Ils sont rattachés aux 2 objets joueurs playerOne et playerTwo du namespace game.

const game = {
 ....
 playerOne : {
  width : 10,
  height : 50,
  color : "#FFFFFF",
  posX : 30,
  posY : 200,
  goUp : false,
  goDown : false
 },
    
 playerTwo : {
  width : 10,
  height : 50,
  color : "#FFFFFF",
  posX : 650,
  posY : 200,
  goUp : false,
  goDown : false
 },
 ....
};

goUp est l’indicateur de déplacement vers le haut et goDown est l’indicateur de déplacement vers le bas.

Ils sont fixés lorsque les touches fléchées du clavier sont pressées. Ensuite, ils sont utilisés par la fonction movePlayers pour incrémenter ou décrémenter, selon le cas, les coordonnées de la raquette du joueur dans le canvas html5.

Les coordonnées sont alors utilisées par la fonction displayPlayers du namespace game pour afficher la raquette du joueur au bon endroit.

 

Principe

C’est à partir des indicateurs goUp et goDown qu’est géré le déplacement. Ils incrémentent ou décrémentent les coordonnées de la raquette dont l’affichage est rafraichi ensuite.

Pour gérer le déplacement de la raquette à la souris, nous allons continuer à travailler avec ces deux indicateurs. Leurs valeurs seront modifiées lorsque le pointeur de la souris se déplacera.

Cela nécessite d’utiliser l’événement de déplacement de la souris mousemove. Lorsque cet événement se produira, une fonction modifiera les indicateurs de déplacement (goUp et goDown) rattachés aux objets player.

Le cas est le même que le déplacement avec le clavier. La mise à jour de la position de la raquette à partir des indicateurs goUp et goDown se fera avec la méthode movePlayers du namespace game.

L’impression de déplacement (la mise à jour de la position de la raquette sur l’écran) sera aussi réalisée par la méthode displayPlayers.

Le code

La première chose à faire est de déclarer une nouvelle variable mousePointer. Elle est chargée de stocker la position du pointeur de la souris.

Du fait du rôle et de l’existence du namespace game.control, encapsuler cette nouvelle variable dans ce namespace n’est pas déconnant.

game.control = {
   
 mousePointer : null,
   
 onKeyDown : function(event) {
  if ( event.keyCode == game.keycode.KEYDOWN ) { 
   game.playerOne.goDown = true;
  } else if ( event.keyCode == game.keycode.KEYUP ) { 
   game.playerOne.goUp = true;
  }
 },
   
 onKeyUp : function(event) {
  if ( event.keyCode == game.keycode.KEYDOWN ) {
   game.playerOne.goDown = false;
  } else if ( event.keyCode == game.keycode.KEYUP ) {
   game.playerOne.goUp = false;
  }
 }
}

Toujours dans le namespace game.controll,  créons une nouvelle fonction onMouseMove. Elle prend en argument un objet event contenant toutes les informations de la souris (notamment la position du pointeur) dont on a besoin.

La fonction mouseMove compare la position du pointeur de la souris à la position de la raquette du joueur.

Si le pointeur est au dessus de la raquette, alors on pose la variable goUp à true et la variable goDown à false. Elle indique ainsi la direction (HAUT) dans laquelle doit se déplacer la raquette.

Inversement, si le pointeur est en dessous de la raquette, alors on pose la variable goUp à false et la variable goDown à true. Elle indique la direction (BAS) dans laquelle doit se déplacer la raquette.

 

Le code de la fonction

game.control = {
   
 mousePointer : null,
   
 onKeyDown : function(event) {
  if ( event.keyCode == game.keycode.KEYDOWN ) { 
   game.playerOne.goDown = true;
  } else if ( event.keyCode == game.keycode.KEYUP ) { 
   game.playerOne.goUp = true;
  }
 },
   
 onKeyUp : function(event) {
  if ( event.keyCode == game.keycode.KEYDOWN ) {
   game.playerOne.goDown = false;
  } else if ( event.keyCode == game.keycode.KEYUP ) {
   game.playerOne.goUp = false;
  }
 },
   
 onMouseMove : function (event) {
  this.mousePointer = event.clientY;
 
  if ( this.mousePointer > game.playerOne.posY ) {
   game.playerOne.goDown = true;
   game.playerOne.goUp = false;
  } else if ( mousePointer < game.playerOne.posY ) {
   game.playerOne.goDown = false;
   game.playerOne.goUp = true;
  } else {
   game.playerOne.goDown = false;
   game.playerOne.goUp = false;
  }
}

Remarquez que la propriété mousePointer prend comme valeur la position du pointeur de la souris à laquelle on soustrait une valeur numérique.

Tout cela n’est pas suffisant, il faut maintenant invoquer la fonction onMouseMove sur tout mouvement de la souris. Et ceci passe par le biais de l’évènement onmousemove.

const game = {
 ....
 initMouse : function(onMouseMoveFunction) {
  window.onmousemove = onMouseMoveFunction;
 }
};

Si vous exécutez le jeu en l’état, vous constaterez que tout ne marche pas comme prévu. La raquette ne s’arrête pas à la position du pointeur. Elle se déplace jusqu’au bord du terrain en fonction du mouvement fait par le pointeur de la souris.

En effet, l’appel de la fonction onMouseMouve (fonction donnant le mouvement à la souris) n’est appelée que sur déplacement de la souris. Du coup, une fois qu’un mouvement est donné et que le pointeur ne bouge plus, la raquette continue sa course.

Il suffit donc d’appeler la fonction onMouseMouve à chaque rafraichissement de la page dans la fonction main. Lors de l’appel depuis la fonction principal, l’objet event n’est pas donné en paramètre puisqu’il est donné par l’événement onmousemove.

Si vous ne faites pas attention à cela, vous allez vous retrouver avec une erreur javascript undefined interrompant la fonction mouseMove.

Le remède est de tester que l’objet event existe comme suit.

game.control = {
 mousePointer : null,
 ....
  
 onMouseMove : function(event) {
   
  if ( event ) {
   game.control.mousePointer = event.clientY;
  }
 
  if ( game.control.mousePointer > game.playerOne.posY ) {
   game.playerOne.goDown = true;
   game.playerOne.goUp = false;
  } else if ( game.control.mousePointer < game.playerOne.posY ) {
   game.playerOne.goDown = false;
   game.playerOne.goUp = true;
  } else {
   game.playerOne.goDown = false;
   game.playerOne.goUp = false;
  }
 }
};

Simple non ? Remarquez qu’en l’état, le déplacement de la raquette ne s’arrête pas au pointeur de la souris, elle se déplace jusqu’aux extrêmes sans s’arrêter.

Ceci est du à la méthode game.movePlayers ci-dessous :
– on déplace la raquette vers le haut tant que sa position est supérieure à zéro, soit la limite en haut de l’espace de jeu;
– on déplace la raquette vers le bas tant que sa position est inférieure à la largeur de l’espace de jeu (game.groundHeight – game.playerOne.height), soit la limite en bas de l’espace de jeu.

const game = {
 ....
 movePlayers : function() {
  if (game.playerOne.goUp && game.playerOne.posY > 0)
   game.playerOne.posY-=5;
  else if (game.playerOne.goDown && game.playerOne.posY < game.groundHeight - game.playerOne.height)
   game.playerOne.posY+=5;
 },
 ....
}

Il suffit de changer ces 2 tests en faisant simplement un contrôle relatif à la position du pointeur de la souris stocké dans la variable game.control.mousePointer et alimentée lors de l’appel de la fonction game.control.onMouseMove. Ce qui donne.

const game = {
 ....
 movePlayers : function() {
  if (game.playerOne.goUp && game.playerOne.posY > game.control.mousePointer)
   game.playerOne.posY-=5;
  else if (game.playerOne.goDown && game.playerOne.posY < game.control.mousePointer)
   game.playerOne.posY+=5;
 },
 ....
}

L’affaire est quasiment terminée : en l’état rien ne se passe puisque l’initialisation de l’usage de la souris n’est pas encore fait. Il suffit pour cela d’appeler la fonction game.initMouse (game.control.onMouseMove); dans la méthode init du namespace javascript game.

Petit hic: le contrôle au clavier ne fonctionne plus. C’est un effet de bord lié à la modification du test dans la méthode movePlayers. Il faut donc avoir deux tests (la version précédente et la version modifiée) dont l’un ou l’autre est appelé selon le type de contrôle utilisé.

Créez une nouvelle propriété controlSystem au sein du namespace game.control indicatrice du type de contrôle utilisé: MOUSE ou KEYBOARD.

Cette nouvelle propriété est valorisée lorsque l’un ou l’autre type de contrôle est utilisé, en occurrence les événements rattachés et plus particulièrement les fonctions appelées sur ces événements: les méthodes onKeyDown et onMouseMove du namespace javascript game.control.

game.control = {
 
 controlSystem : null,
 mousePointer : null,
 
 onKeyDown : function(event) {
   
  game.control.controlSystem = "KEYBOARD";
 
  if ( event.keyCode == game.keycode.KEYDOWN ) { 
   game.playerOne.goDown = true;
  } else if ( event.keyCode == game.keycode.KEYUP ) { 
   game.playerOne.goUp = true;
  }
 },
 ....
 onMouseMove : function(event) {
    
  game.control.controlSystem = "MOUSE";
 
  if ( event ) {
   game.control.mousePointer = event.clientY;
  }
  
  if ( game.control.mousePointer > game.playerOne.posY ) {
   game.playerOne.goDown = true;
   game.playerOne.goUp = false;
  } else if ( game.control.mousePointer < game.playerOne.posY ) {
   game.playerOne.goDown = false;
   game.playerOne.goUp = true;
   } else {
   game.playerOne.goDown = false;
   game.playerOne.goUp = false;
  }
 }
}

Ensuite, utilisez cette nouvelle propriété pour choisir le test à réaliser.

const game = {
 ....
 movePlayers : function() {
  if ( game.control.controlSystem == "KEYBOARD" ) {
   // keyboard control
   if ( game.playerOne.goUp ) {
    game.playerOne.posY-=5;
   } else if ( game.playerOne.goDown ) {
    game.playerOne.posY+=5;
   }
  } else if ( game.control.controlSystem == "MOUSE" ) {
   // mouse control
   if (game.playerOne.goUp && game.playerOne.posY > game.control.mousePointer)
    game.playerOne.posY-=5;
   else if (game.playerOne.goDown && game.playerOne.posY < game.control.mousePointer)
    game.playerOne.posY+=5;
   }
 }
 ....
}

Le tour est joué, il n’y a plus qu’à tester. Lors du prochain article, vous apprendrez à renvoyer la balle avec la raquette, à suivre 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.