Pong en javascript – interface et décor

Quartorzième partie consacrée au développement d’un jeu vidéo html5 javascript:le décor dans le jeu vidéo Pong. Je vous propose de mettre un décor plus fouillé et plus abouti.

Prérequis pour le décor dans le jeu Pong

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. Le contrôle de la raquette par le joueur à l’aide de la souris Coder le jeu vidéo Pong – Controle à la souris. Le renvoi de la balle par les raquettes Coder le jeu video pong – Renvoi de la balle. La gestion des effets sonores Coder le jeu video pong – Ajout des effets sonores. La gestion de l’IA Coder le jeu vidéo Pong – Intelligence artificielle. La gestion du score et de l’engagement Coder le jeu vidéo Pong – Score et engagement. La gestion des parties Coder le jeu vidéo Pong – Début et fin de partie. La gestion de la vitesse de la balle Coder le jeu vidéo Pong – Vitesse et trajectoire. La version modernisée Coder le jeu vidéo Pong – Graphisme moderne. Adaptation à un écran mobile Coder le jeu vidéo Pong – Adaptation à la taille de l’écran.

Le principe du décor dans le jeu Pong

Hormis le nécessaire au redimensionnement des composants, pas de développement supplémentaire, du html principalement.

Dans un premier temps, je vous propose de:
– centrer le terrain de jeu;
– ajouter un bandeau de part et d’autre du terrain: l’un pour intégrer un menu pour le jeu, l’autre pourrait être dédié à l’accueil de publicité.

Rendre visible un bloc div vide

Dans cet article, vous allez manipuler à certains moments des blocs html div vides. Pas simple de visualiser le résultat.

Je vous propose de les rendre visibles en ajoutant un contour fin coloré par le biais d’un style.

border: 1px solid #0000FF;

Pour l’intégrer au div html.

<div id="divGame" style="border: 1px solid #0000FF;"></div>

Ni plus, ni moins.

Ajout des bandeaux

Le canvas html5 est associé/intégrée à un bloc html nommé divGame.

Pour créer les 2 bandeaux à sa gauche et à sa droite, ajoutez 2 nouveaux blocs div n’omettez pas les styles pour leur visibilité.

<div id="left" style="border: 1px solid #0000FF;"></div>
<div id="divGame" style="border: 1px solid #0000FF;"></div>
<div id="right" style="border: 1px solid #0000FF;"></div>

Le résultat n’est pas probant et ceci est normal. Pour que les blocs html div existent pleinement, il faut leur donner des dimensions. Il faut aussi faire en sorte qu’ils s’affichent pleinement sans se limiter à son contenu.

Vous devez donc spécifier certaines caractéristiques de style indispensables:
display:block; -> pour indiquer d’afficher un bloc;
width:200px;height:100px; -> pour le dimensionner.

<div id="left" style="display:block;width:200px;height:100px;border: 1px solid #0000FF;"></div>
<div id="divGame" style="display:block;width:600px;height:100px;border: 1px solid #0000FF;"></div>
<div id="right" style="display:block;width:200px;height:100px;border: 1px solid #0000FF;"></div>

Ce n’est toujours pas probant. Cependant, vous voyez derrière le terrain 2 blocs l’un en dessous de l’autre.

Là nous sommes face à une problématique de positionnement des blocs les uns par rapport aux autres. Changez cette politique de positionnement par une qui placera les éléments les uns derrières les autres sur une même ligne.

Le style float:left placé sur une balise html div indique que cette même balise sera placée à la gauche de la suivante ou plus simplement que la balise suivante sera placée à sa droite.

Tout ceci, bien entendu si les dimensions le permettent. Si vous mettez trois blocs dont la somme des dimensions est supérieure à la dimension de l’écran alors le bloc le plus à droite de l’écran sera placé en dessous du premier bloc (float:left=le plus à gauche possible).

<div id="left" style="float:left;display:block;width:200px;height:100px;border: 1px solid #0000FF;"></div>
<div id="divGame" style="float:left;display:block;width:600px;height:100px;border: 1px solid #0000FF;"></div>
<div id="right" style="float:left;display:block;width:200px;height:100px;border: 1px solid #0000FF;"></div>

Ce qui cloche maintenant, c’est la taille du canvas qui est plus grande que celle du div html. Pour corriger, il suffit que le div html ait la même taille que le canvas html5.

Vous retrouverez la bonne taille dans le fichier conf.js avec les valeurs de GROUNDLAYERWIDTH et GROUNDLAYERHEIGHT.

<div id="left" style="float:left;display:block;width:200px;height:100px;border: 1px solid #0000FF;"></div>
<div id="divGame" style="float:left;display:block;width:700px;height:400px;border: 1px solid #0000FF;"></div>
<div id="right" style="float:left;display:block;width:200px;height:100px;border: 1px solid #0000FF;"></div>

Voilà qui est un peu mieux. Pour parfaire la solution, je vous propose d’aligner la hauteur des deux blocs à celle de celui du milieu.

<div id="left" style="float:left;display:block;width:200px;height:400px;border: 1px solid #0000FF;"></div>
<div id="divGame" style="float:left;display:block;width:700px;height:400px;border: 1px solid #0000FF;"></div>
<div id="right" style="float:left;display:block;width:200px;height:400px;border: 1px solid #0000FF;"></div>

Comme je le disais précédemment:
– le bloc de gauche pourrait être un panneau de commande avec le bouton start auquel vous pourriez ajouter un bouton pause;
– le bloc de droite pourrait accueillir de la publicité (monétisation du jeu ?)

Bref, là c’est à votre inspiration de faire le boulot.

Centrer horizontalement l’écran de jeu

Pour centrer les trois blocs sans travailler sur chacun individuellement nécessite qu’ils forment un tout. Et c’est ce tout que vous allez centrer. Pour former ce tout, il vous suffit d’encapsuler les trois blocs dans un div container.

<div id="blocToCenter">
  <div id="left" style="float:left;display:block;width:200px;height:400px;border: 1px solid #0000FF;"></div>
  <div id="divGame" style="float:left;display:block;width:700px;height:400px;border: 1px solid #0000FF;"></div>
  <div id="right" style="float:left;display:block;width:200px;height:400px;border: 1px solid #0000FF;"></div>
</div>

Cependant, tel qu’indiqué rien ne change: il reste à centrer de bloc container.

La méthode la plus simple pour center en bloc div html sur l’horizontale est:
– de lui donner une taille qui soit supérieure à la somme des tailles des trois blocs encapsulés (via les propriétés de style width et height);
– de lui laisser calculer les marges automatiquement à sa gauche et à sa droite (via les propriétés de style margin).

<div id="blocToCenter" style="width:1010px;height:400px;margin-left:auto;margin-right:auto">
  <div id="left" style="float:left;display:block;width:150px;height:400px;border: 1px solid #0000FF;"></div>
  <div id="divGame" style="float:left;display:block;width:700px;height:400px;border: 1px solid #0000FF;"></div>
  <div id="right" style="float:left;display:block;width:150px;height:400px;border: 1px solid #0000FF;"></div>
</div>

Habillage du bloc gauche

Remarquez que le bouton start en haut à gauche de l’écran fait un peu (voire très) moche. Pourquoi ne pas utiliser le bloc gauche pour y intégrer ce bouton et y ajouter un bouton pause ?

Il y a juste à déplacer la balise img dans le bloc div html nommé left. Prenez soin de réduire un peu la taille de l’image à 100 pixels pour qu’elle soit trop grossière.

Ajoutez un bouton de pause comme celui-ci en le plaçant préalablement dans le dossier img du projet.

<div id="left" style="float:left;display:block;width:150px;height:400px;border: 1px solid #0000FF;text-align:center;">
  <input id="startGame" type="image" style="width:100px" src="./img/startBtn.png">
  <input id="pauseGame" type="image" style="width:100px" src="./img/pauseBtn.png">
</div>

Du coup, le bloc complet remonte et colle quasiment à la partie supérieure de l’écran. Vous pouvez par ailleurs supprimer le bloc menu qui ne sert plus à rien.

Centrer horizontalement et verticalement l’écran de jeu

Esthétiquement parlant, c’est pas top. Un centrage vertical me parait aussi utile et là vous devez changer de méthode. Autant la méthode pour un centrage horizontal tel qu’indiqué est préconisée, si vous voulez les deux c’en est une autre.

Pour centrer le bloc horizontalement et verticalement avec CSS, la méthode va être de placer le bloc div html (son coin supérieur gauche au centre de la page). Puis déplacez ce bloc vers la gauche de la moitié de sa taille horizontale (1010px/2=505px). Et vers le haut de la moitié de sa taille verticale (400px/2=200px) en fixant des marges négatives.

Vous devez d’abord choisir un mode de positionnement absolu (position:absolute;). C’est à dire indépendamment de tout autre élément de la page. Ce mode de positionnement permet de placer le bloc div html où bon vous semble. Vous n’avez qu’à spécifier ses coordonnées via les propriétés left et top.

position:absolute;

Puis placer le bloc (son bord supérieur gauche) au milieu de l’écran.

left:50%;top:50%;

Ensuite fixer ses dimensions (width et height), ce qui est normalement déjà fait.

width:1010px;height:400px;

Ensuite fixer ses dimensions (width et height), ce qui est normalement déjà fait.

margin:-200px 0 0 -505px;

Au final, vous obtenez.

<div id="blocToCenter" style="width:1010px;height:400px;position:absolute;left:50%;top:50%;margin:-200px 0 0 -505px;">

La totale.

<div id="blocToCenter" style="width:1010px;height:400px;position:absolute;left:50%;top:50%;margin:-200px 0 0 -505px;">
  <div id="left" style="float:left;display:block;width:150px;height:400px;border: 1px solid #0000FF;text-align:center;">
    <input id="startGame" type="image" style="width:100px" src="./img/startBtn.png">
    <input id="pauseGame" type="image" style="width:100px" src="./img/pauseBtn.png">
  </div>
  <div id="divGame" style="float:left;display:block;width:700px;height:400px;border: 1px solid #0000FF;"></div>
  <div id="right" style="float:left;display:block;width:150px;height:400px;border: 1px solid #0000FF;"></div>
</div>

Activation des boutons

Rien à changer pour le bouton start puisqu’il est déjà actif. Il reste à activer le bouton pause.
Le mieux serait que lorsqu’on clique sur le bouton pause, il se transforme en bouton continue et vice-versa.

Commencez par ajouter le bouton continue. Rendez le invisible via la propriété de style display.

<div id="left" style="float:left;display:block;width:150px;height:400px;border: 1px solid #0000FF;text-align:center;">
  <input id="startGame" type="image" style="width:100px" src="./img/startBtn.png">
  <i<em>nput id="pauseGame" type="image" style="width:100px" src="./img/pauseBtn.png">
  <input id="continueGame" type="image" style="width:100px;display:none;" src="./img/continueBtn.png">
</div>

Ensuite, créez les fonctions appelées au clic des boutons pause et continue. L’un rendra invisible en plus de mettre en pause ou pas le jeu. Ces deux fonctions prennent la même forme que la fonction onStartGameClickButton du namespace game.control.

game.control = {
  ...
  onPauseGameClickButton : function() {
    if ( game.gameOn ) {
      game.gameOn = false;
      game.pauseGameButton.style.display = 'none';
      game.continueGameButton.style.display = 'inline';
    }
  },
   
  onContinueGameClickButton : function() {
    if ( !game.gameOn ) {
      game.gameOn = true;
      game.pauseGameButton.style.display = 'inline';
      game.continueGameButton.style.display = 'none';
    }
  }
}

Il ne reste plus qu’à appeler ces fonctions sur le clic des boutons dans le namespace game.js. Même forme que pour la fonction initStartGameButton: initPauseGameButton et initContinueGameButton.

const game = {
  ...
  initPauseGameButton : function() {
    this.pauseGameButton.onclick = game.control.onPauseGameClickButton;
  },
 
  initContinueGameButton : function() {
    this.continueGameButton.onclick = game.control.onContinueGameClickButton;
  },
  ....
}

Appelez ces fonctions initPauseGameButton et initContinueGameButton depuis la fonction init.

Au préalable créez et initialisez (toujours depuis la fonction init) les propriétés du namespace game pauseGameButton et continueGameButton. L’initialisation consiste simplement à rattacher les propriétés pauseGameButton et continueGameButton aux objets html correspondant.

const game = {
  ...
  init : function() {
    ...
    this.divGame = document.getElementById("divGame");
    this.startGameButton = document.getElementById("startGame");
    this.pauseGameButton = document.getElementById("pauseGame");
    this.continueGameButton = document.getElementById("continueGame");
    ...
    this.initStartGameButton();
    this.initPauseGameButton(); 
    this.initContinueGameButton();
    ....
  }
}

Ajouter un fond pour le décor dans le jeu Pong

Une simple image de fond ajoutée via la propriété de style background-image à la balise body. L’image à télécharger et intégrer dans le dossier img du projet. Libre à vous d’y mettre une de vos créations.

Le code html.

<html>
  <body style="background-image:url(./img/background.jpg)">
  ...
</html>

Je vous invite à prendre une image suffisamment grande pour éviter l’effet damier.  Lorsqu’une image est trop petite celle-ci se répette autant que besoin pour couvrir la totalité de l’écran.

Le redimensionnement

Tout un tas de truc a été ajouté, mais pas prévu pour être redimensionné  dans l’article précédent. Y a plus qu’à s’y mettre.

Souvenez-vous du principe et de la méthode:
– des valeurs utilisées (et adaptées) de la plateforme le développement énumérées et stockées dans le namespace conf;
– une fonction resizeDisplayData du namespace game prenant des ratios d’adaptation (calculés à partir de la plateforme d’exécution) en paramètres, utilisés pour redimensionner et adapter les valeurs du namespace conf à la plateforme d’exécution.

Le bloc central intégrant de terrain de jeu.

<div id="blocToCenter" style="width:1010px;height:400px;position:absolute;left:50%;top:50%;margin:-200px 0 0 -505px;">
....
</div>

Voyez que le style comporte deux propriétés width et height fixée en dur. Des propriétés dont il faut ajuster la valeur selon les caractéristiques de l’écran d’exécution.

Il y a aussi deux valeurs utiles dans la propriété margin. Ces deux valeurs sont respectivement la moitié des deux valeurs précédentes.

En conséquence, n’ajoutez au namespace conf que les valeurs width et height . Cela suffit pour faire le redimensionnement (les valeurs fixées sont celles utilisées pour la plateforme de développement).

const conf = {
 
  BLOCCENTERWIDTH : 1010,
  BLOCCENTERHEIGHT : 400,
  ...
}

Ces deux valeurs vont être réajustées via la méthode resizeDisplayData, donc rien à faire de ce côté là. Par contre, vous devez réaffecter les valeurs réajustées dans la méthode init.

this.blocToCenter = document.getElementById("blocToCenter");
this.blocToCenter.style.width = conf.BLOCCENTERWIDTH + "px";
this.blocToCenter.style.height = conf.BLOCCENTERHEIGHT + "px";
this.blocToCenter.style.margin = "-" + conf.BLOCCENTERHEIGHT/2 + "px 0 0 -" + conf.BLOCCENTERWIDTH/2 + "px";

Ceci vous oblige aussi à déclarer la propriété blocToCenter au sein du namespace game.

const game = {
    
  blocToCenter : null,
  ....
}

Les blocs et images encapsulés dans la balise div blocToCenter sont aussi à redimensionner . Utilisez la même méthode.

Il reste à traiter donc :
– le bloc de gauche (id=left);
– le bloc de droite (id=right);
– le bloc encapsulant le canvas html5 (id=divGame);
– les trois boutons start (id=startGame), pause (id=pauseGame) et continue (id=continueGame).

Les trois boutons et le bloc div divGame sont déjà définis en tant que propriétés du namespace game:
startGameButton pour le bouton startGame;
pauseGameButton pour le bouton pauseGame;
continueGameButton pour le bouton continueGame;
divGame pour le bloc encapsulant le canvas html5.

S’ajoutent au namespace conf les déclarations suivantes.

const conf = {
  ....
  BLOCLEFTWIDTH : 150,
  BLOCLEFTHEIGHT : 400,
  BLOCRIGHTWIDTH : 150,
  BLOCRIGHTHEIGHT : 400,
  BLOCDIVGAMEWIDTH : 700,
  BLOCDIVGAMEHEIGHT : 400,
 
  BUTTONSTARTGAMEWIDTH : 100,
  BUTTONPAUSEGAMEWIDTH : 100,
  BUTTONCONTINUEGAMEWIDTH : 100,
  ....
}

S’ajoutent au namespace game les réaffectations de valeur après redimensionnement dans le méthode init.

const game = {
  ....
  init : function() {
    ....
    this.blocRight = document.getElementById("right");
    this.blocRight.style.width = conf.BLOCRIGHTWIDTH + "px";
    this.blocRight.style.height = conf.BLOCRIGHTHEIGHT + "px";
     
    this.divGame = document.getElementById("divGame");
    this.divGame.style.width = conf.BLOCDIVGAMEWIDTH + "px";
    this.divGame.style.height = conf.BLOCDIVGAMEHEIGHT + "px";
     
    this.startGameButton = document.getElementById("startGame");
    this.startGameButton.style.width = conf.BUTTONSTARTGAMEWIDTH + "px";
     
    this.pauseGameButton = document.getElementById("pauseGame");
    this.pauseGameButton.style.width = conf.BUTTONPAUSEGAMEWIDTH + "px";
     
    this.continueGameButton = document.getElementById("continueGame");  
    this.continueGameButton.style.width = conf.BUTTONCONTINUEGAMEWIDTH + "px";
    ....
  }
  ....
}

Vous avez vu le décor dans le jeu Pong. Les bases sont désormais installées. A vous de les agrémenter comme bon vous semble. De la pub, un décor plus fouillé, c’est à votre imagination de bosser.

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.