Étude de cas : redimensionnement automatique des jeux HTML5

Derek Detweiler
Derek Detweiler

Présentation

Au cours de l'été 2010, nous avons créé Sand Trap, un jeu auquel nous avons participé à un concours sur les jeux HTML5 pour téléphones mobiles. Cependant, la plupart des téléphones mobiles n'affichaient qu'une partie du jeu ou rendaient le jeu trop petit, ce qui le rendait complètement injouable. Nous avons donc décidé de faire en sorte que le jeu s'adapte facilement à n'importe quelle résolution. Après un peu de reprogrammation et d'utilisation des idées décrites dans cet article, nous avons créé un jeu qui s'adapte à tous les navigateurs modernes, que ce soit sur ordinateur de bureau ou sur appareil mobile.

Capture d'écran du plein écran
capture d'écran d'un indicateur plus petit dans la fenêtre du navigateur

Cette approche a bien fonctionné pour Sand trap. Nous avons donc utilisé la même méthode pour notre dernier jeu, Thwack!. Le jeu ajuste automatiquement la résolution de l'écran pour s'adapter aux fenêtres de taille personnalisée et plein écran, comme illustré dans les captures d'écran ci-dessous.

Pour cela, il fallait utiliser à la fois CSS et JavaScript. L'utilisation de CSS pour remplir l'intégralité de l'écran est simple, mais CSS ne vous permet pas de conserver le même rapport largeur/hauteur pour éviter que le canevas et la zone de jeu ne soient étirés. C'est là que JavaScript entre en jeu. Vous pouvez redimensionner les éléments du document avec JavaScript et déclencher le redimensionnement lors des événements de fenêtre.

Préparer la page

La première étape consiste à désigner la zone de la page où le jeu se déroulera. Si vous l'incluez en tant que bloc div, vous pouvez y placer d'autres tags ou un élément canevas. Si la configuration est correcte, ces éléments enfants hériteront de la mise à l'échelle du bloc div parent.

Si votre zone de jeu comporte deux parties, une aire de jeu et une zone de suivi des scores, elle pourrait se présenter comme suit:

<div id="gameArea">
  <canvas id="gameCanvas"></canvas>
  <div id="statsPanel"></div>
</div>

Une fois que vous disposez d'une structure de document de base, vous pouvez attribuer à ces éléments quelques propriétés CSS afin de les préparer au redimensionnement. La plupart des propriétés CSS de "gameArea" sont manipulées directement par JavaScript, mais pour qu'elles fonctionnent, vous devez d'abord configurer quelques autres propriétés CSS en commençant par le bloc div gameArea parent:

#gameArea {
  position: absolute;
  left:     50%;
  top:      50%;
}

Cela place le coin supérieur gauche du canevas au centre de l'écran. La fonction JavaScript de redimensionnement automatique décrite dans la section suivante manipule des propriétés CSS supplémentaires pour redimensionner la zone de jeu et la centrer dans la fenêtre.

La zone de jeu étant automatiquement redimensionnée en fonction des dimensions de la fenêtre, les dimensions en pixels des éléments enfants du bloc div gameArea doivent être exprimées en pourcentages. Les valeurs de pixel ne permettent pas aux éléments internes de s'adapter au div parent lorsqu'il est modifié. Cependant, il peut être utile de commencer par les pixels, puis de les convertir en pourcentages une fois que vous avez une mise en page qui vous convient.

Dans cet exemple, la zone de jeu mesure 300 pixels de hauteur et 400 pixels de largeur. Le canevas couvre l'ensemble de la zone du jeu, et un panneau de statistiques semi-transparent d'une hauteur de 24 pixels s'affiche en bas, comme illustré dans la figure 1.

Dimensions des éléments enfants gameArea en pixels
Figure 1: Dimensions des éléments enfants gameArea en pixels

Si vous convertissez ces valeurs en pourcentages, le canevas a une largeur de 100% et une hauteur de 100 % (pour gameArea, et non pour la fenêtre). La division de 24 par 300 donne une hauteur de 8 % au panneau des statistiques. Comme il couvre le bas de la zone de jeu, sa largeur est également de 100%, comme illustré dans la figure 2.

Dimensions des éléments enfants gameArea en pourcentages
Figure 2: Dimensions des éléments enfants gameArea en pourcentages

Maintenant que vous avez déterminé les dimensions de la zone de jeu et de ses éléments enfants, vous pouvez assembler les propriétés CSS des deux éléments internes comme suit:

#gameCanvas {
  width: 100%;
  height: 100%;
}
#statsPanel {
  position: absolute;
  width: 100%;
  height: 8%;
  bottom: 0;
  opacity: 0.8;
}

Redimensionnement du jeu

Vous êtes maintenant prêt à créer une fonction permettant de gérer le redimensionnement de la fenêtre. Tout d'abord, récupérez une référence à l'élément parent gameArea du document.

var gameArea = document.getElementById('gameArea');

Puisque vous n'êtes pas préoccupé par la largeur ou la hauteur exactes, l'information suivante que vous devez définir est le rapport entre la largeur et la hauteur. Comme nous l'avons vu précédemment, pour une zone de jeu de 400 pixels de large et de 300 pixels de haut, vous savez que vous souhaitez définir le format sur 4 unités de largeur et 3 unités de hauteur.

var widthToHeight = 4 / 3;

Comme cette fonction est appelée chaque fois que la fenêtre est redimensionnée, vous devez également récupérer les nouvelles dimensions de la fenêtre afin de pouvoir ajuster les dimensions de votre jeu en conséquence. Pour ce faire, utilisez les propriétés innerWidth et innerHeight de la fenêtre.

var newWidth = window.innerWidth;
var newHeight = window.innerHeight;

Tout comme vous avez déterminé le rapport largeur/hauteur souhaité, vous pouvez maintenant déterminer le rapport largeur/hauteur actuel de la fenêtre:

var newWidthToHeight = newWidth / newHeight;

Cela vous permet de décider si le jeu doit remplir l'écran verticalement ou horizontalement, comme illustré dans la figure 3.

Adapter l&#39;élément gameArea à la fenêtre tout en conservant le format
Figure 3: Adapter l'élément gameArea à la fenêtre tout en conservant le format

Si la forme souhaitée de la zone de jeu est plus large que la forme de la fenêtre (et que la hauteur est plus courte), vous devez remplir la fenêtre horizontalement et laisser les marges en haut et en bas. De même, si la forme souhaitée de la zone de jeu est plus haute que la forme de la fenêtre (et que la largeur est plus étroite), vous devez remplir la fenêtre verticalement et conserver des marges à gauche et à droite.

Pour ce faire, testez le rapport largeur/hauteur souhaité avec le rapport largeur/hauteur de la fenêtre actuelle, puis effectuez les ajustements appropriés comme suit:

if (newWidthToHeight > widthToHeight) {
  // window width is too wide relative to desired game width
  newWidth = newHeight * widthToHeight;
  gameArea.style.height = newHeight + 'px';
  gameArea.style.width = newWidth + 'px';
} else { // window height is too high relative to desired game height
  newHeight = newWidth / widthToHeight;
  gameArea.style.width = newWidth + 'px';
  gameArea.style.height = newHeight + 'px';
}

Maintenant que vous avez ajusté la largeur et la hauteur de la zone de jeu, vous devez centrer les éléments en plaçant en haut une marge négative qui équivaut à la moitié de la hauteur et sur la gauche qui correspond à la moitié de la largeur. N'oubliez pas que CSS place déjà l'angle supérieur gauche du tag "gameArea" exactement au centre de la fenêtre, de façon à centrer la zone de jeu dans la fenêtre:

gameArea.style.marginTop = (-newHeight / 2) + 'px';
gameArea.style.marginLeft = (-newWidth / 2) + 'px';

Vous pouvez également ajuster automatiquement la taille de la police. Si tous les éléments enfants utilisent em, il vous suffit de définir la propriété CSS fontSize du bloc div gameArea sur une valeur déterminée par sa taille.

gameArea.style.fontSize = (newWidth / 400) + 'em';

Enfin, faites en sorte que les dimensions du dessin de la toile correspondent à ses nouvelles largeurs et hauteurs. Notez que les dimensions du moteur de jeu et du dessin du canevas doivent être séparées dans le reste du code du jeu afin de s'adapter à une résolution de canevas dynamique.

var gameCanvas = document.getElementById('gameCanvas');
gameCanvas.width = newWidth;
gameCanvas.height = newHeight;

Ainsi, la fonction de redimensionnement terminée peut ressembler à ceci:

function resizeGame() {
    var gameArea = document.getElementById('gameArea');
    var widthToHeight = 4 / 3;
    var newWidth = window.innerWidth;
    var newHeight = window.innerHeight;
    var newWidthToHeight = newWidth / newHeight;
    
    if (newWidthToHeight > widthToHeight) {
        newWidth = newHeight * widthToHeight;
        gameArea.style.height = newHeight + 'px';
        gameArea.style.width = newWidth + 'px';
    } else {
        newHeight = newWidth / widthToHeight;
        gameArea.style.width = newWidth + 'px';
        gameArea.style.height = newHeight + 'px';
    }
    
    gameArea.style.marginTop = (-newHeight / 2) + 'px';
    gameArea.style.marginLeft = (-newWidth / 2) + 'px';
    
    var gameCanvas = document.getElementById('gameCanvas');
    gameCanvas.width = newWidth;
    gameCanvas.height = newHeight;
}

Vous voulez maintenant que ces ajustements soient effectués automatiquement chaque fois que la fenêtre est redimensionnée ou, dans le cas des appareils mobiles, que l'orientation de l'écran est modifiée. Gérez ces événements en les faisant appeler votre fonction renameGame() comme suit:

window.addEventListener('resize', resizeGame, false);
window.addEventListener('orientationchange', resizeGame, false);

Si la fenêtre est redimensionnée trop haut ou si l'orientation de l'écran est verticale, la largeur de la fenêtre est de 100 %. De plus, si la fenêtre est redimensionnée trop large ou si l'orientation de l'écran est horizontale, sa hauteur correspondra à 100% de la fenêtre. La dimension restante est dimensionnée en fonction du rapport largeur/hauteur prédéterminé.

Résumé

Gopherwood Studios a utilisé des versions de cette structure pour tous nos jeux HTML5. Cette structure s'est avérée très utile pour s'adapter à plusieurs résolutions d'écran et à divers appareils mobiles. De plus, grâce à un navigateur plein écran, nos jeux Web offrent une expérience immersive plus proche des jeux sur ordinateur traditionnels que de nombreux jeux sur navigateur. À mesure que le HTML5 et les technologies Web ne cessent d'évoluer, nous attendons avec impatience davantage d'innovations dans le domaine des jeux en ligne.