Coder le jeu vidéo pong html5

 

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 au développement de jeu vidéo. A vos claviers. English version.


 

Pour les utilisateurs de Internet Explorer

Bien que cela commence à changer, Internet Explorer ne se fait pas ce qu’il y a de mieux dans le support du HTML5. Pour une meilleure expérience de développement de jeux vidéos, je vous encourage à passer à Google Chrome qui est un des navigateurs les plus rapides et qui supportent le mieux HTML5.

 

La série

Pour ceux qui souhaiteraient aller plus vite :
– mise en place de l’environnement du jeu (terrain, raquettes, balle et score) : ici;
– animation de la balle : ici;
– contrôle de la raquette avec le clavier : ici.

 

Prérequis

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

 

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.

Arborescence Projet

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 va consister à 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 () {
  // début du code isolé
  var requestAnimId;
 
  var initialisation = function() {
    // le code de l'initialisation
    requestAnimId = window.requestAnimationFrame(main); // premier appel de main au rafraîchissement de la page
  }
 
  var main = function() {
    // le code du jeu
    requestAnimId = window.requestAnimationFrame(main); // rappel de main  au prochain rafraîchissement de la page
  }
 
  window.onload = initialisation; // appel de la fonction initialisation au chargement de la page

  // fin du code isolé
})();
</script>

Je ne détaille pas ici le pourquoi de ce code. Pour en savoir plus, lisez l’article Initialiser le développement 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 :

var 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.

Vous allez créer 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.

Pour rendre le code plus lisible, la création d’un objet dédié parait pertinente, objet que vous appelerez layer html5 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.

Le code :

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.

Ce qui donne pour le code :

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é en évitant 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 va permettre de créer la couche de l’environnement dédiée au terrain dont le fond est de couleur noire et dans lequel 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 :

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

La création du terrain fait partie de l’initialisation du jeu et ne sera exécuté qu’une seule fois, pourquoi ne pas créer une fonction dédiée à l’initialisation ?

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

  init : function() {
  }

};

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

var 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:

var 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); 
    game.display.drawRectangleInLayer(this.groundLayer, this.netWidth, this.groundHeight, this.netColor, this.groundWidth/2 - this.netWidth/2, 0);
  }

};

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 () {
  // début du code isolé
  var requestAnimId;
 
  var initialisation = function() {
    // le code de l'initialisation
    game.init();
    requestAnimId = window.requestAnimationFrame(main); // premier appel de main au rafraîchissement de la page
  }
 
  var main = function() {
    // le code du jeu
    requestAnimId = window.requestAnimationFrame(main); // rappel de main au prochain rafraîchissement de la page
  }
 
  window.onload = initialisation; // appel de la fonction initialisation au chargement de la page
 
  // fin du code isolé
})();
</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.

Si vous avez aimé cet article, partagez le.
Si vous constatez des coquilles, ou avez des remarques à faire ou encore souhaitez manifester votre satisfaction de ce tuto, n’hésitez pas les commentaires sont faits pour ça.

 
Ci-dessous les codes complets de l’exemple :
game.html

<html>
 <body>
 </body>
<script src="game.js"></script>
<script src="game.display.js"></script>
<script>
(function () {
  // début du code isolé
  var requestAnimId;
 
  var initialisation = function() {
    // le code de l'initialisation
    game.init();
    requestAnimId = window.requestAnimationFrame(main); // premier appel de main au rafraîchissement de la page
  }
 
  var main = function() {
    // le code du jeu
    requestAnimId = window.requestAnimationFrame(main); // rappel de main au prochain rafraîchissement de la page
  }
 
  window.onload = initialisation; // appel de la fonction initialisation au chargement de la page
 
  // fin du code isolé
})();
</script> 
</html>

game.js

var 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); 
    game.display.drawRectangleInLayer(this.groundLayer, this.netWidth, this.groundHeight, this.netColor, this.groundWidth/2 - this.netWidth/2, 0);
  }
};

game.display.js

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;
  },
 
  drawRectangleInLayer : function(targetLayer, width, heigth, color, x, y) {
    targetLayer.context2D.fillStyle = color;
    targetLayer.context2D.fillRect (x, y, width, heigth);
  }
}

 

Posté dans html5, pongTaggé développer pong, pong html5, pong javascript, tutorial html5, tutoriel jeu vidéo, tutoriel pong  |  24 commentaires

24 réponses à "Coder le jeu vidéo pong html5"

Répondre