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.


 

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;
– animation 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.

Commençons par créer un dossier projet nommé Pong qui encapsulera tous les éléments de votre jeu vidéo.

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 placé à 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.

Editons le fichier pong.html, puis ajoutons 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éons 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éé, nous mettons en place l’environnement du jeu comprenant :
– le terrain de jeu;
– l’affichage du score;
– la balle;
– et les raquettes.

Nous créons 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, vous pouvez consulter l’article Tutorial Canvas.

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

Cet objet manipulera un canvas html5 en rendant sa manipulation plus lisible dans le contexte d’un jeu vidéo javascript.

L’objet Layer prototype javascript

Tout d’abord, créons 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égrons à 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éres 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, il est nécessaire de créer une fonction du namespace javascript intégré au layer html5 prenant en paramètres la plupart des propriétés pour pouvoir les initialiser. Ce constructeur créée le canvas html5 à partir des paramètres indiqués.

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;
},

Nous sommes 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 nous n’avons pas encore identifiés, il conviendrait de les rattacher à un conteneur. L’intégration du canvas html5 rattaché à un conteneur dans 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 j’ai choisi 800 sur 600 pixels;
– l’épaisseur du filet, pour l’exemple j’ai choisi 6 pixels;
– la couleur du terrain, ici noire;
– la couleur du filet, ici blanc.

Commençons par créer 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 nous créons un objet Layer dédié au terrain intégré au namespace game créé précédemment et à la fonction init.

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 reste à intégrer le filet blanc qui prend la forme d’un rectangle blanc.

Il va donc falloir intégrer 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, nous avons :

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, il ne reste plus qu’à intégrer 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

*