Coder le jeu video html5 pong – adaptation de la taille de l’écran




 

Jusqu’à présent, le jeu Pong html5 que vous avez développé fonctionne sur PC. Toutefois, un problème de dimensionnement se pose puisque les dimensions des objets du jeu tel que la taille des boutons, de l’écran sont spécifiés de manière absolue. Je vous propose donc de gérer la taille des objets du jeu en les adaptant à l’écran du PC sur lequel le jeu vidéo est exécuté.

Prérequis

Avoir lu les tutoriaux suivants :
– 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;
– le 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 html5 pong – Renvoi de la balle;
– l’ajout du son lorsque la balle cogne un mur ou une raquette Coder le jeu vidéo Pong – Ajout du son.
– l’intelligence artificielle Coder le jeu video html5 pong – Intelligence Artificielle;
– la Coder le jeu video html5 pong – Gestion du score et engagement;
– l’ajout d’un début et d’une fin à une partie Coder le jeu video html5 pong – début et fin de partie;
– la vitesse et la trajectoire de la balle Coder le jeu video html5 pong – vitesse et trajectoire de la balle;
– le look plus moderne Coder le jeu video html5 pong – Changement de look.

 

Introduction

Je ne parlerais pas des Media Queries CSS3. L’idée ici est d’adapter proportionnellement l’écran de jeu à la taille du PC sur lequel le jeu est exécuté : pas de changement de disposition, et une seule feuille de style quelque soit le média utilisé. Il va donc falloir pondérer toutes les positions et mesures des objets graphiques en fonction de la taille de l’écran.

 

Qu’est ce qui change par rapport à la version originelle ?

D’un point de vue graphique, seules les dimensions changent. En passant d’une taille d’écran à une autre ou d’une résolution à une autre, rien ne change. Hormis le fait que les éléments du jeu ont une taille adaptée à l’écran.

 

Les dimensions et les positions s’adaptent au média

L’idée est de créer un ratio qui servira depuis une résolution de développement à passer à une résolution cible.

Le calcul de ce ratio se fait à partir de la taille de l’écran cible et la taille de l’écran qui a servi au développement du jeu vidéo.

Cette méthode, facile à comprendre et à implémenter, a le privilège de fonctionner partout et tout le temps.

Veillez bien à retenir que les objets et les positions seront redimensionnés. La difficulté ici est de n’oublier personne sans quoi l’affichage du jeu et son comportement risque fortement d’être chaotique.

 

Enumération des valeurs à repositionner

Oui, énumérer il faut. Non, appliquer manuellement une opération de redimensionnement sur chaque élément énuméré il ne faut pas.

Le jeu, si c’en est un, consiste à relever tous les éléments graphiques du jeu avec leur valeur de taille et de positionnement. De cette liste va naitre un namespace javascript de configuration game.conf.

Vous avez entre autres la taille du terrain (les 3 layers), la taille et la position des joueurs, de la balle, du filet, du score.

Vient ensuite la création d’une méthode dédiée qui appliquera aux propriétés du namespace javascript game.conf le redimensionnement voulu.

C’est parti:

var conf = {
   GROUNDLAYERWIDTH : 700,
   GROUNDLAYERHEIGHT : 400,
   
   SCORELAYERWIDTH : 700,
   SCORELAYERHEIGHT: 400,

   PLAYERSBALLLAYERWIDTH : 700,
   PLAYERSBALLLAYERHEIGHT: 400,
   
   NETWIDTH : 6,
   
   SCOREPOSXPLAYER1 : 300,
   SCOREPOSYPLAYER1 : 55,
   SCOREPOSXPLAYER2 : 365,
   SCOREPOSYPLAYER2 : 55,
   SCOREFONTSIZE : 50,
   
   BALLWIDTH : 10,
   BALLHEIGHT : 10,
   BALLPOSX : 200,
   BALLPOSY : 200,

   PLAYERONEWIDTH : 10,
   PLAYERONEHEIGHT : 70,
   PLAYERONEPOSX : 30,
   PLAYERONEPOSY : 200,

   PLAYERTWOWIDTH : 10,
   PLAYERTWOHEIGHT : 70,
   PLAYERTWOPOSX : 650,
   PLAYERTWOPOSY : 200
   
}

Ceci réalisé, il vous faut substituer toutes ces constantes aux valeurs correspondantes dans le code. Principalement dans le namespace javascript game, là où toutes les initialisations se font.

Du fait du basculement de certaines variables dans le namespace javascript conf, celles-ci disparaissent du namespace javascript game.

Supprimer le code suivant du namespace game:

scorePosPlayer1 : 300,
scorePosPlayer2 : 365,

Ce sont les variables qui portent la position des scores sur l’axe X de l’écran de jeu et qui sont remplacées par les valeurs du namespace javascript conf:

   SCOREPOSXPLAYER1 : 300,
   SCOREPOSYPLAYER1 : 55,
   SCOREPOSXPLAYER2 : 365,
   SCOREPOSYPLAYER2 : 55,

Hé oui, il n’y a pas deux mais quatre valeurs: les positions sur la verticale ont été rajoutées car étaient en dur dans le code (mauvais pratique) SCOREPOSYPLAYER1, SCOREPOSYPLAYER2.

A aussi été rajoutée la taille de la font du score SCOREFONTSIZE.

Enfin les valeurs game.groundWidth, game.groundHeight, game.netWidth étant initialisées dans le namespace conf et redimensionnées dans ce même namespace javascript, elle sont de fait déportées.

Il n’y a donc aucun intérêt à les conserver dans le namespace game.

S’en suivent les changements suivant au sein du namespace game:

var game = {
  ....   
  ball : {
    ....   
    bounce : function(soundToPlay) {
      if ( this.sprite.posX > conf.GROUNDLAYERWIDTH || this.sprite.posX < 0 ) {
        this.directionX = -this.directionX;
		soundToPlay.play();
	  }
      if ( this.sprite.posY > conf.GROUNDLAYERHEIGHT || this.sprite.posY < 0  ) {
        this.directionY = -this.directionY;
        soundToPlay.play();
      }		
    },
	....
  },
  .... 
  init : function() {
    ....	
    this.groundLayer= game.display.createLayer("terrain", conf.GROUNDLAYERWIDTH, conf.GROUNDLAYERHEIGHT, this.divGame, 0, "#000000", 10, 50); 
    game.display.drawRectangleInLayer(this.groundLayer, conf.NETWIDTH, conf.GROUNDLAYERHEIGHT, this.netColor, conf.GROUNDLAYERWIDTH/2 - conf.NETWIDTH/2, 0);
    
    this.scoreLayer = game.display.createLayer("score", conf.GROUNDLAYERWIDTH, conf.GROUNDLAYERHEIGHT, this.divGame, 1, undefined, 10, 50);
    game.display.drawTextInLayer(this.scoreLayer , "SCORE", "10px Arial", "#FF0000", 10, 10);
    
    this.playersBallLayer = game.display.createLayer("joueursetballe", conf.GROUNDLAYERWIDTH, conf.GROUNDLAYERHEIGHT, this.divGame, 2, undefined, 10, 50);  
    game.display.drawTextInLayer(this.playersBallLayer, "JOUEURSETBALLE", "10px Arial", "#FF0000", 100, 100);
    
    this.displayScore(0,0);
	
    this.ball.sprite = game.display.createSprite(conf.BALLWIDTH,conf.BALLHEIGHT,conf.BALLPOSX,conf.BALLPOSY,"./img/ball.png");
    this.displayBall();
	
    this.playerOne.sprite = game.display.createSprite(conf.PLAYERONEWIDTH,conf.PLAYERONEHEIGHT,conf.PLAYERONEPOSX,conf.PLAYERONEPOSY,"./img/playerOne.png");
    this.playerTwo.sprite = game.display.createSprite(conf.PLAYERTWOWIDTH,conf.PLAYERTWOHEIGHT,conf.PLAYERTWOPOSX,conf.PLAYERTWOPOSY,"./img/playerTwo.png");	
    this.displayPlayers();
    ....   
  },
    
  displayScore : function(scorePlayer1, scorePlayer2) {
    game.display.drawTextInLayer(this.scoreLayer, scorePlayer1, conf.SCOREFONTSIZE + "pt DS-DIGIB", "#FFFFFF", conf.SCOREPOSXPLAYER1, conf.SCOREPOSYPLAYER1);
    game.display.drawTextInLayer(this.scoreLayer, scorePlayer2, conf.SCOREFONTSIZE + "pt DS-DIGIB", "#FFFFFF", conf.SCOREPOSXPLAYER2, conf.SCOREPOSYPLAYER2);
  },
 
  ....   
};

 

Ce dont vous avez besoin pour redimensionner

D’un point de vue plus opérationnelle, vous avez besoin de 5 nouvelles propriétés à rattacher au namespace javascript game:
– les deux premières pour stocker la résolution de l’écran qui a servi au développement;
– les deux suivantes pour stocker la résolution de l’écran cible qui servira à jouer;
– les deux dernières pour stocker le ration qui permettra de passer de la résolution de développement à la résolution cible sur chacun des axes.

Pour les puristes, l’usage d’une structure de données pour chaque couple de valeurs peut aussi être un usage.

var game = {
  ....
  devResX : null,
  devResY : null,
  targeResX : null,
  targetResY : null,
  ratioResX : null,
  ratioResY : null,
  ....
}

Il faut ensuite fixer ces valeurs: les deux premières sont fixées par le développeur et sont relatives à son environnement. Les quatre dernières sont calculées.

var game = {
  ....
  devResX : 1366,
  devResY : 738,
  ....
}

Pour le calcul des quatre dernières valeurs, une fonction dédiée qui, à partir de la résolution du joueur, calculera un ration de transformation.

var game = {
  ....
  initScreenRes : function() {
    this.targetResX = window.screen.availWidth;
    this.targetResY = window.screen.availHeight;
    this.ratioResX = this.targetResX/this.devResX;
    this.ratioResY = this.targetResY/this.devResY;
  },
  ....
}

 

La fonction de redimensionnement

Une seule fonction qui balaie toutes les données du namespace conf pour leur appliquer les ratios.

Il y a un ratio à appliquer sur les données relatives à l’horizontale X et un ratio à appliquer sur les données relatives à la verticale Y.

Pour appliquer avec discernement ces ratios, la fonction scrute le nom de la propriété et:
– regarde si elle contient X ou WIDTH (les majuscules sont importantes) pour appliquer ratioX;
– regarde si elle contient Y ou HEIGHT(les majuscules sont importantes) pour appliquer ratioX.

Cette règle impose donc une contrainte sur le nommage des propriétés relatives à l’affichage et intégrées au namespace conf.

var game = {
  ....
  resizeDisplayData : function(object, ratioX, ratioY) {
    var property;
    for ( property in object ) { 
      if ( property.match(/^.*X.*$/i) || property.match(/^.*WIDTH.*$/i) ) {
        object[property] = Math.round(object[property] * ratioX);
      } else {
        object[property] = Math.round(object[property] * ratioY);
      }
    }
  },
  ....
}

 

Mise en opération du redimensionnement

Ici les choses ont simples, puisqu’il suffit de référencer le namespace conf dans le fichier pong.html.

<html>
 <body>
 </body>
<style>
@font-face { 
  font-family: 'DS-DIGIB'; 
  src: url('./font/ds_digital/DS-DIGIB.TTF'); 
}
</style>
<script src="conf.js"></script>
<script src="game.js"></script>
....
</html>

Puis depuis la fonction init namespace game:
– d’appeler la fonction d’initialisation des ratios;
– et d’appeler la fonction d’application des ratios.

var game = {
  ....
  init : function() {
    this.initScreenRes();
    this.resizeDisplayData(conf,this.ratioResX,this.ratioResY);
    ....
  },
  ....
}

Mais ce n’est pas tout. En l’état, balle et raquettes garderont leurs tailles originelles.

Du fait de l’implémentation de la fonction drawImageInLayer du namespace game.display qui ne prend pas en compte une taille cible pour les images affichées:

game.display = {
  ....
  drawImageInLayer : function(targetLayer, image, x, y) {
    targetLayer.context2D.drawImage(image, x, y);
  },
  ....
}

Il suffit de la modifier en changeant la signature de la fonction (deux paramètres supplémentaires) et en appelant la fonction drawImage avec la signature comportant une taille cible et le tour est joué:

game.display = {
  ....
  drawImageInLayer : function(targetLayer, image, x, y, width, height) {
    targetLayer.context2D.drawImage(image, x, y, width, height);
  },
  ....
}

 
Pour voir en live le code, cliquez sur Pong

 

Si vous avez aimé cet article, partagez le.

 

Si vous constatez des coquilles, ou avez des remarques, une autre solution ou encore souhaitez manifester votre satisfaction de ce tuto, commentez.

 

Posté dans html5, pongTaggé canvas html5, canvas image, jeu video html5, tuto html5  |  3 commentaires

3 réponses à "Coder le jeu video html5 pong – adaptation de la taille de l’écran"

Répondre

*