Mis à jour le mardi 28 novembre 2017
  • 28 heures
  • Facile

Ce cours est visible gratuitement en ligne.

Ce cours existe en livre papier.

Vous pouvez obtenir un certificat de réussite à l'issue de ce cours.

Vous pouvez être accompagné et mentoré par un professeur particulier par visioconférence sur ce cours.

J'ai tout compris !

Un jeu en jQuery

Connectez-vous ou inscrivez-vous gratuitement pour bénéficier de toutes les fonctionnalités de ce cours !

Vous étiez nombreux à attendre un chapitre consacré à la réalisation de jeux en jQuery. Eh bien, vous y êtes ! Vous allez apprendre à :

  • Afficher un décor en mouvement pour donner l'illusion d'un déplacement ;

  • Déplacer des objets sur l'écran en utilisant les touches fléchées du clavier ;

  • Gérer plusieurs couches graphiques ;

  • Détecter des collisions ;

  • Ajouter des sons.

Prêts ? Allons-y !

Le document de base

Avant d'aller plus loin, je vais vous montrer à quoi va ressembler le jeu. Regardez la figure suivante pour en avoir un petit aperçu.

Le jeu dans sa version finale
Le jeu dans sa version finale

La route défile du bas vers le haut. Le joueur pilote la voiture jaune et doit éviter les voitures rouges qui apparaissent aléatoirement sur l'écran. La voiture jaune se dirige avec les touches Droite et Gauche du clavier. La zone de jeu n'est autre qu'une balise <div> dans laquelle on place les différents éléments graphiques :

  • Deux portions de route #fond1 et #fond2, toutes deux de classe .fond ;

  • La voiture jaune #vj ;

  • La voiture rouge #vr.

Je vous propose de télécharger les images que j'ai utilisées, mais vous pouvez bien évidemment prendre vos propres images.

L'arrière-plan : route.png
L'arrière-plan : route.png
La voiture jaune : vj.png
La voiture jaune : vj.png
La voiture rouge : vr.png
La voiture rouge : vr.png

Des informations textuelles sont affichées au-dessus de l'aire de jeu à l'aide d'une balise <span>. Voici le code HTML utilisé :

Collisions : <span id="info">0</span>
<div id="jeu">
  <img id="fond1" class="fond" src="route.png">
  <img id="fond2" class="fond" src="route.png">
  <img id="vj" src="vj.png"> <!-- La voiture jaune -->
  <img id="vr" src="vr.png"> <!-- La voiture rouge -->
</div>

Ces éléments sont mis en forme à l'aide de quelques instructions CSS. L'aire de jeu #jeu est dimensionnée à 400 × 400 pixels. Elle est entourée d'une bordure noire continue épaisse de 2 pixels. Étant donné que deux images vont être affichées l'une en dessous de l'autre, sa propriété overflow est initialisée à hidden pour dissimuler les barres de défilement. Le positionnement à l'intérieur de l'aire de jeu se fait de façon relative.

#jeu{
  width: 400px;
  height: 400px;
  border: 2px black solid;
  overflow: hidden;
  position: relative;
}

Les images qui représentent la route sont positionnées de façon relative et leur z-index est initialisé à 10. Quant aux images des voitures, elles sont positionnées de façon absolue et leur z-index est initialisé avec d'autres valeurs. Vous comprendrez pourquoi en lisant la suite.

.fond{
  margin-bottom:-5px;
  z-index: 10;
  position: relative;
}
#vj{
  z-index: 100;
  position: absolute;
  top: 10px;
  left: 48px;
}
#vr{
  z-index: 80;
  position: absolute;
  top: -200px;
  left: 0px;
}

Dans les chapitres précédents, nous avons déjà croisé la propriété CSS z-index. Je vais quand même rappeler que cette propriété permet d'empiler plusieurs éléments les uns sur les autres. L'élément qui est le plus en avant-plan est celui qui a un z-index le plus élevé. Inversement, l'élément qui est le plus en arrière-plan est celui qui a un z-index le plus faible, comme le montre la figure suivante.

Les éléments s'empilent en fonction de leur propriété z-index
Les éléments s'empilent en fonction de leur propriété z-index

Dans le code sur lequel nous sommes en train de travailler, la route a un z-index égal à 10, la voiture rouge un z-index égal à 80 et la voiture jaune un z-index égal à 100. La voiture jaune sera donc en avant-plan, la route en arrière-plan et la voiture rouge sera affichée au-dessus de la route, mais en dessous de la voiture jaune si vous ne savez pas l'éviter.

Ça y est : la structure et la mise en forme du document sont maintenant en place ! Il ne reste plus (!) qu'à écrire quelques lignes de jQuery pour mettre tout cela en mouvement.

Gérer les déplacements

Créer un décor en mouvement

La route doit défiler du bas vers le haut de l'aire de jeu. Avez-vous une idée de la technique à utiliser ? La méthode animate(), bien entendu !

D'accord, la méthode animate() va me permettre de déplacer la route vers le haut, mais comment faire en sorte que l'affichage boucle sur lui-même afin que la route se déroule vers le haut sans jamais s'arrêter ?

Deux astuces vont mener à ce résultat :

  1. En insérant l'appel à la méthode animate() dans une fonction et en réexécutant cette fonction via la fonction de rappel de la méthode animate(), on obtient une boucle sans fin.

  2. En redonnant la position initiale aux images de classe .fond dans la fonction de rappel de la méthode animate(), un nouveau déplacement vers le haut peut être initié.

Voici le code utilisé :

function deplace()
{
  $('.fond').animate({
    top: '-=360'
  },
  1000,
  'linear',
  function(){
    $('.fond').css('top', 0);
    deplace();
  });
}

Dans ce code, les deux images de la route sont déplacées de façon linéaire vers le haut de 360 pixels en 1000 millisecondes. Lorsque ce déplacement est terminé, la fonction de rappel est exécutée. Les images sont replacées à leur position d'origine et la fonction deplace() est à nouveau exécutée.

Pourquoi avoir utilisé deux images ?

La méthode animate() déplace de 360 pixels vers le haut la première image. En ajoutant une deuxième image identique à sa suite, on évite qu'une zone blanche n'apparaisse dans la partie inférieure de l'aire de jeu, comme à la figure suivante.

La deuxième image assure la continuité de la route
La deuxième image assure la continuité de la route

Il suffit d'exécuter la fonction deplace() pour que la route se déplace sans fin vers le haut. Mais si vous ne l'activez pas une première fois, rien ne se passera sur l'écran. Vous devez donc insérer l'instruction deplace(); un peu avant la balise </script>.

Afficher et déplacer la voiture rouge

La voiture rouge doit se déplacer de bas en haut et apparaître aléatoirement. Voici le code utilisé :

function deplace()
{
  $('#vr').animate({top: '-=600'}, 2500, 'linear', function(){
    var vrX = Math.floor(Math.random()*194)+70;
    var vrY = 400;
    $('#vr').css('top',vrY);
    $('#vr').css('left',vrX);
  });
  // Ici se trouve l'appel à la méthode animate()
  // pour animer la route
};

N'ayez pas peur de ce code. Il n'y a rien de sorcier là-dedans !

La première instruction déplace linéairement la voiture rouge vers le haut de 600 pixels en 2500 millisecondes. C'est le même principe que pour déplacer la route, sauf qu'ici on déplace la voiture de 600 pixels vers le haut afin qu'elle disparaisse complètement de l'écran. Faites le test avec une valeur plus petite que 400, vous comprendrez. On modifie également le temps de défilement : l'image a plus de chemin à parcourir, il faut donc laisser le temps au joueur d'éviter la voiture. Lorsque le déplacement est terminé, une nouvelle voiture rouge doit être affichée. Pour cela, on tire aléatoirement un nombre compris entre 70 et 194+70, soit 264. Ce nombre est mémorisé dans la variable vrX. Il correspond à l'abscisse (la coordonnée horizontale) de la voiture rouge lorsqu'elle sera affichée pour la première fois. Cette abscisse doit se trouver sur la route. Les valeurs 70 et 264 ont été obtenues en utilisant un logiciel graphique.

Les abscisses minimale et maximale d'affichage de la voiture rouge
Les abscisses minimale et maximale d'affichage de la voiture rouge

Déplacer la voiture jaune

La voiture jaune se déplace horizontalement, avec les touches Gauche et Droite du clavier. Il suffit donc de capturer l'appui sur ces touches et d'effectuer le traitement nécessaire. Pour cela, nous appliquerons la méthode événementielle keydown() au document :

$(document).keydown(function(e){

Les touches Gauche et Droite ont pour code ASCII 37 et 39. Il suffit donc de tester la valeur de e.which pour savoir quelle touche a été pressée. S'il s'agit de la touche Droite, et si la voiture n'est pas trop à droite, celle-ci est déplacée de 30 pixels grâce à la propriété CSS left :

if (e.which == 39)
{
  vjX = parseInt($('#vj').css('left'));
  if (vjX < 280)
    $('#vj').css('left', vjX+30);
}

Si la touche Gauche est pressée, et si la voiture n'est pas trop à gauche, celle-ci est déplacée de 30 pixels grâce à la propriété CSS left :

if (e.which == 37)
{
  vjX = parseInt($('#vj').css('left'));
  if (vjX > 70)
    $('#vj').css('left', vjX-30);
}

Simple et efficace !

Détecter les collisions

Comment savoir si les voitures sont entrées en collision ? En comparant leurs coordonnées respectives tout simplement. Voici le code utilisé :

function collision()
{
  vjX = parseInt($('#vj').css('left'));
  vrX = parseInt($('#vr').css('left'));
  vjY = 10;
  vrY = parseInt($('#vr').css('top'));
  if (((vrX > vjX) && (vrX < (vjX+66)) && (vrY > vjY) && (vrY < (vjY+150)) &&(ok == 1))
  || ((vjX > vrX) && (vjX < (vrX+66)) && (vrY > vjY) && (vrY < (vjY+150)) && (ok == 1)))
  {
    collision = parseInt($('#info').text()) + 1;
    $('#info').text(collision);
    ok = 0;
  }  
}

Les premières lignes placent les coordonnées de la voiture jaune dans les variables vjX et vjY et celles de la voiture rouge dans les variables vrX et vrY. Les lignes 7 et 8 représentent le test de collision. La première ligne traite des collisions sur le côté gauche.

Une collision à gauche s'est produite
Une collision à gauche s'est produite

Elle compare les coordonnées des deux voitures en supposant que la voiture rouge est plus à droite que la voiture jaune sur l'aire de jeu. Si la voiture rouge entre en collision par la gauche, le test est vérifié et les lignes 10 à 12 s'exécutent. De la même manière, la deuxième ligne compare les coordonnées des deux voitures en supposant que la voiture rouge est plus à gauche que la voiture jaune sur l'aire de jeu. Si la voiture rouge entre en collision par la droite, le test est vérifié et les lignes 10 à 12 s'exécutent.

À quoi correspond la variable ok dans les deux tests de collision et dans les instructions exécutées en cas de collision ?

Sans cette variable, en cas de collision, plusieurs collisions seraient détectées au fur et à mesure que la voiture rouge se déplace vers le haut. Pour que la variable ok remplisse sa fonction, vous devez l'initialiser à 1 au tout début du code ainsi qu'en fin de déplacement de chaque voiture rouge :

$(function() {
  var ok = 1;
  ...

… et :

function deplace()
{
  $('#vr').animate({top: '-=600'}, 2500, 'linear', function(){
  var vrX = Math.floor(Math.random()*194)+70;
  var vrY = 400;
  $('#vr').css('top',vrY);
  $('#vr').css('left',vrX);
  ok = 1;
});
...

Lorsqu'une collision se produit, le nombre de collisions est incrémenté de 1 dans la balise <span id="info">. Pour que cette fonction soit exécutée à intervalles réguliers (ici, toutes les 20 millisecondes), nous utilisons la fonction setInterval() :

setInterval(collision, 20);

Ajouter des sons

Que diriez-vous d'ajouter un effet sonore à chaque collision ? Ceci est encore une fois d'une simplicité désarmante, à condition d'utiliser un navigateur récent, compatible avec le langage HTML5. Commencez par insérer une balise <audio> dans le document :

<audio preload="auto" id="son">
  <source src="beep.mp3" type="audio/mp3">
  <source src="beep.ogg" type="audio/ogg">
</audio>

Comme vous pouvez le voir, on utilise deux formats de son : MP3 et OGG. Ceci afin d'assurer la compatibilité du code avec la plupart des navigateurs du marché. Chaque navigateur utilisera le type de fichier qu'il sait lire. Par exemple, Internet Explorer choisira le fichier MP3, Firefox et Google Chrome le fichier OGG.

Vous trouverez sans peine de nombreux effets spéciaux sur le Web, mais encore une fois je vous propose de télécharger celui que j'ai utilisé pour ce chapitre.

Pour jouer le son, utilisez l'instruction jQuery suivante :

$('#son')[0].play();

Si vous placez cette instruction dans la fonction collision(), juste après le if qui teste si une collision s'est produite, l'effet sonore se produira à chaque fois que les voitures entrent en collision :

if (((vrX > vjX) && (vrX < (vjX+66)) && (vrY > vjY) && (vrY < (vjY+150)) && (ok == 1)) 
|| ((vjX > vrX) && (vjX < (vrX+66)) && (vrY > vjY) && (vrY < (vjY+150)) && (ok == 1)))
{
  $('#son')[0].play();
  ...

Le code complet

Je vous propose de tester le rendu final en cliquant ici. De plus, voici le code complet de l'application. Amusez-vous bien !

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>jeu</title>
  <style type="text/css">
    #jeu{
      width: 400px;
      height: 400px;
      border: 2px black solid;
      overflow: hidden;
      position: relative;
    }
    .fond{
      margin-bottom:-5px; 
      z-index: 10;
      position: relative;
    }
    #vj{
      z-index: 100; 
      position: absolute; 
      top: 10px; 
      left: 48px;
    }
    #vr{
      z-index: 80; 
      position: absolute; 
      top: -200px; 
      left: 0px;
    }
  </style>
</head>

<body>
  Collisions : <span id="info">0</span>
  <div id="jeu">
    <img id="fond1" class="fond" src="route.png">
    <img id="fond2" class="fond" src="route.png">
    <img id="vj" src="vj.png">
    <img id="vr" src="vr.png">
  </div>
  <audio preload="auto" id="son"><source src="beep.mp3" type="audio/mp3"><source src="beep.ogg" type="audio/ogg"></audio>

  <script src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
  <script>
    $(function() {
      var ok = 1;
      function deplace()
      {
        $('#vr').animate({top: '-=600'}, 2500, 'linear', function(){
          var vrX = Math.floor(Math.random()*194)+70;
          var vrY = 400;
          $('#vr').css('top',vrY);
          $('#vr').css('left',vrX);
          ok = 1;
        });
        $('.fond').animate({top: '-=360'}, 1000, 'linear', function(){
          $('.fond').css('top',0);
          deplace();
        });
      };
	   
      $(document).keydown(function(e){
        if (e.which == 39)
        {
          vjX = parseInt($('#vj').css('left'));
          if (vjX < 280)
          $('#vj').css('left', vjX+30);
        }
        if (e.which == 37)
        {
          vjX = parseInt($('#vj').css('left'));
          if (vjX > 70)
            $('#vj').css('left', vjX-30);
        }
      });

      function collision()
      {
        vjX = parseInt($('#vj').css('left'));
        vrX = parseInt($('#vr').css('left'));
        vjY = 10;
        vrY = parseInt($('#vr').css('top'));
        if (((vrX > vjX) && (vrX < (vjX+66)) && (vrY > vjY) && (vrY < (vjY+150)) && (ok == 1)) 
        || ((vjX > vrX) && (vjX < (vrX+66)) && (vrY > vjY) && (vrY < (vjY+150)) && (ok == 1)))
        {
          $('#son')[0].play();
          collision = parseInt($('#info').text()) + 1;
          $('#info').text(collision);
	  ok = 0;
        }
      }
      deplace();
      setInterval(collision, 20);
    });
  </script>
</body>
</html>
Exemple de certificat de réussite
Exemple de certificat de réussite