Créer le jeu Pong en javascript

Comment créer le jeu Pong? Vous avez toujours rêvé savoir comment développer un jeu vidéo en javascript et html5. Votre vœu est en passe d’être exaucé. Je débute une série d’articles dédiés au développement du jeu Pong. Certes, le jeu peut paraitre simpliste, mais il reste une excellente introduction à la création de jeux vidéo.

 

Prérequis pour créer le jeu Pong

– Savoir ce qu’est html;
– avoir des connaissances de base en javascript;
– il est conseillé d’avoir lu les articles Initialiser la création d’un jeu vidéo et Tutorial Canvas html5.

 

Arborescence de notre projet Pong

Comme tout développement, il est nécessaire de créer une arborescence de dossiers ou répertoires de manière à organiser les composants du jeu vidéo html5.

Commencez par créer le dossier du projet et nommez le Pong. Il encapsulera tous les éléments de votre jeu vidéo html5.

Dans le dossier Pong, créez :
– un dossier js dédié aux fichiers et librairies javascript;
– un dossier img dédié aux fichiers images (fond, sprites…);
– un dossier sound dédié aux fichiers audio relatifs aux bruitages de votre jeu;
– un dossier music dédiés aux fichiers audio relatifs aux musiques de votre jeu;
– un dossier css dédiés aux fichiers css.

Le fichier html du jeu pong.html est quant à lui à créer à la racine du dossier projet.

 

Le code de base

Le code de base consiste à créer :
– une fonction d’initialisation du jeu;
– une fonction dédiée à l’exécution de la boucle du jeu appelée à chaque rafraîchissement de l’écran;
– un namespace javascript appelé game.

Editez le fichier pong.html, puis ajoutez le code suivant.

<script>
(function () {

  let requestAnimId;
  
  let initialisation = function() {

    requestAnimId = window.requestAnimationFrame(main); // premier appel de main au rafraîchissement de la page
  }
  
  let main = function() {

    requestAnimId = window.requestAnimationFrame(main); // rappel de main  au prochain rafraîchissement de la page
  }
  
  window.onload = initialisation; 
 

})();
</script>

Je ne détaille pas ici le pourquoi de ce code. Pour en savoir plus, lisez l’article Initialiser la création d’un jeu vidéo qui traite le sujet de manière détaillée.

Pour bien structurer le code du jeu, je conseille l’usage des namespaces javascript. Bien qu’il n’y ait pas de namespace à proprement parler en javascript, il est possible les simuler à partie de simples objets. Je vous invite à lire l’article Les namespace javascript pour en savoir plus.

Pour ce qui est du cas présent, créez un namespace game dédié au jeu vidéo, comme ceci.

const game = {
 
};

Oui, c’est un objet au format json qui est utilisé.

 

Mise en place de l’environnement du jeu Pong

Les composants de l’environnement du jeu

Maintenant que le projet est créé, vous devez mettre en place l’environnement du jeu comprenant:
– le terrain de jeu;
– l’affichage du score;
– la balle;
– et les raquettes.

Créez tout cela, sans animer quoi que ce soit. Chacun des éléments créés sera statique.

Un environnement divisé en 3 couches

Je vous propose d’utiliser 3 canvas html5 superposés comparables aux layers de Flash:
– le premier dédié au terrain: un fond noir, et un filet;
– le deuxième dédié à l’affichage du score;
– le troisième et dernier dédié à l’animation des raquettes et de la balle.

Pourquoi utiliser 3 canvas html5 au lieu d’un seul ?
– la première raison est l’optimisation : avec un seul canvas html5, il va falloir rafraichir tous les éléments du jeu que sont les raquettes, la balle, le score, et le filet à chaque rafraichissement;
– la seconde raison est de l’ordre purement conceptuel : on regroupe des éléments de même nature dans un canvas html5 dédié.

Pour ceux qui souhaitent en savoir plus sur le canvas html5, consultez l’article Tutorial Canvas html5.

Pour rendre le code plus lisible, la création d’un objet dédié parait pertinente. Un objet que vous appelerez layer html5 et que vous pourrez cloner comme bon nous semble à partir d’un objet prototype javascript qui reste à créer.

Le layer qui encapsule un canvas html5 rend sa manipulation plus naturelle dans le contexte d’un jeu vidéo javascript.

L’objet Layer prototype javascript

Tout d’abord, créez un sous-namespace display dans un fichier dédié game.display.js. Ce namespace javascript encapsule tout ce qui est relatif à l’affichage.

game.display = {
}

Intégrez à ce namespace javascript l’objet layer.

game.display = {
  layer : {
  }
}

Il reste à y intégrer les propriétés spécifiques suivantes :
– un nom via la propriété name;
– un canvas html5 via la propriété canvas;
– un context 2D (isssu du canvas) via la propriété context2D;
– un position sur le plan via les propriétés posX et posY;
– des dimensions via les propriétés width et heigth;
– une couleur de fond via la propriété backgroundColor;
– une position pour la superposition sur d’autres layer du plan via la propriété zIndex.

game.display = {
  layer : {
    name : "",
    canvas : "",
    context2D : "",
    posX : null,
    posY : null,
    width : "",
    height : "",
    backgroundColor : "",
    zIndex : ""
  }
}

Ensuite, une fonction du namespace javascript intégré au layer html5 prenant en paramètres la plupart des propriétés permettra de les initialiser. Ce constructeur crée le canvas html5 à partir des paramètres en entrée.

Petites explications :
– les opérations de tracé ne se font pas directement à partir du canvas html5, mais à partir de son contexte 2D;
– le contexte s’obtient depuis le canvas html5 par le biais de la fonction getContext(‘2d’);
– l’objet Layer encapsule tout cela (propriétés canvas et context2D);
– la fonction createLayer va initialiser tout cela.

Comme vous pouvez le voir, le constructeur reste une simple fonction qui renvoie un objet layer.

createLayer : function(name, width, height, zIndex, backgroundColor, x, y) {
  var layer = Object.create(this.layer);
 
  layer.canvas = window.document.createElement("canvas");
 
  layer.canvas.id = name;
 
  if ( backgroundColor != undefined )
    layer.canvas.style.background = backgroundColor;
 
    layer.zIndex = zIndex
    layer.canvas.style.zIndex = zIndex;
 
    layer.width = width
    layer.canvas.width = width;
 
    layer.height = height
    layer.canvas.height = height;
 
    if ( x != undefined )
      layer.posX = x;
 
    if ( y != undefined )
      layer.posY = y;
 
    layer.context2D = layer.canvas.getContext('2d');
 
    return layer;
},

Vous êtes dans un contexte de pages html. De ce fait, pour faciliter la mise en page ou l’agencement des différents éléments du jeu vidéo html5 que peuvent être le score, l’écran du jeu ou d’autres éléments que vous n’avez pas encore identifiés, les rattacher à un conteneur serait pertinent. L’intégration du canvas html5 rattaché à un conteneur pour une mise en page particulière en sera grandement facilité. Evitez de manipuler directement sa position mais plutôt celle de son conteneur.

Je vous propose de rajouter au namespace javascript display la propriété container.

game.display = {
  container : "",
   
  layer : {
    name : "",
    canvas : "",
    context2D : "",
    posX : null,
    posY : null,
    width : "",
    height : "",
    backgroundColor : "",
    zIndex : ""
  },
 
  createLayer : function(name, width, height, htmlContainer , zIndex, backgroundColor, x, y) {
    var layer = Object.create(this.layer);
 
    layer.canvas = window.document.createElement("canvas");
 
    layer.canvas.id = name;
 
    if ( backgroundColor != undefined )
      layer.canvas.style.background = backgroundColor;
 
    layer.zIndex = zIndex
    layer.canvas.style.zIndex = zIndex;
 
    layer.width = width
    layer.canvas.width = width;
 
    layer.height = height
    layer.canvas.height = height;
 
    if ( x != undefined )
      layer.posX = x;
 
    if ( y != undefined )
      layer.posY = y;
 
    layer.canvas.style.position = "absolute";
    if ( x != undefined )
      layer.canvas.style.left = x;
 
    if ( y != undefined )
      layer.canvas.style.top = y;
 
    if ( htmlContainer != undefined ) {
      htmlContainer.appendChild(layer.canvas);
    } else {
      document.body.appendChild(layer.canvas);
    }
 
    layer.context2D = layer.canvas.getContext('2d');
 
    return layer;
  }
}

Notez que dans le code ci-dessus, en plus de l’intégrer dans le namespace javascript layer, le constructeur prend un nouveau paramètre htmlContainer auquel le canvas est rattaché via le code.

game.display = {
    ......
    if ( htmlContainer != undefined ) {
      htmlContainer.appendChild(layer.canvas);
    } else {
      document.body.appendChild(layer.canvas);
    }
    ......
}

En l’absence de htmlContainer, le canvas html5 est rattaché au document html racine document.body.

 

1ère couche de l’environnement : le terrain

L’objet Layer défini auparavant permet de créer la couche de l’environnement dédiée au terrain. Le fond est de couleur noire et une ligne droite verticale est tracée au milieu, comme ceci.

Les paramètres du terrain sont :
– la taille du terrain, pour l’exemple 800 sur 600 pixels;
– l’épaisseur du filet, pour l’exemple 6 pixels;
– la couleur du terrain, ici noire;
– la couleur du filet, ici blanc.

Créez 5 variables dédiées au début de la fonction créée pour isoler le code du jeu.

const game = {
  groundWidth : 700,
  groundHeight : 400,
  groundColor: "#000000",
  netWidth : 6,
  netColor: "#FFFFFF"
};

Maintenant, créez un objet Layer dédié au terrain intégré depuis la fonction init du namespace game.

const game = {
  groundWidth : 700,
  groundHeight : 400,
  groundColor: "#000000",
  netWidth : 6,
  netColor : "#FFFFFF",
 
  groundLayer : null,
 
  init : function() {
    this.groundLayer = game.display.createLayer("terrain", this.groundWidth, this.groundHeight, undefined, 0, "#000000", 0, 0); 
  }
 
};

En l’état, vous avez un layer noir. Il vous reste à intégrer le filet blanc qui prend la forme d’un rectangle blanc. Pour ce faire, ajoutez une fonction de tracé de rectangle drawRectangleInLayer au namespace javascript display.

game.display = {
  container : "",
   
  layer : {
    .....
  },
 
  createLayer : function(name, width, height, htmlContainer , zIndex, backgroundColor, x, y) {
    .....
  },
 
  drawRectangleInLayer : function(targetLayer, width, heigth, color, x, y) {
    targetLayer.context2D.fillStyle = color;
    targetLayer.context2D.fillRect (x, y, width, heigth);
  }
}

Petite explication : la fonction fillRect (appelée depuis context2D) permet de dessiner des rectangles colorés dont la couleur est sélectionnée grâce à la fonction fillStyle.

A l’usage, vous avez.

<html>
 <body>
 </body>
<script src="game.js"></script>
<script src="game.display.js"></script>
<script>
(function () {

  let requestAnimId;
  
  let initialisation = function() {

    game.init();
    requestAnimId = window.requestAnimationFrame(main); // premier appel de main au rafraîchissement de la page
  }
  
  const main = function() {

    requestAnimId = window.requestAnimationFrame(main); // rappel de main au prochain rafraîchissement de la page
  }
  
  window.onload = initialisation; 
  

})();
</script> 
</html>

Pour terminer, intégrez le tout dans le fichier racine du jeu pong.html.

<html>
 <body>
 </body>
<script src="game.js"></script>
<script src="game.display.js"></script>
<script>
(function () {

  let requestAnimId;
  
  let initialisation = function() {

    game.init();
    requestAnimId = window.requestAnimationFrame(main); // premier appel de main au rafraîchissement de la page
  }
  
  const main = function() {

    requestAnimId = window.requestAnimationFrame(main); // rappel de main au prochain rafraîchissement de la page
  }
  
  window.onload = initialisation; 
  

})();
</script> 
</html>

Pour voir en live le code, cliquez sur Pong . Voilà, c’en est terminé pour le terrain. Il reste maintenant à tracer le score ainsi que les raquettes objet de l’épisode 2 à 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.