Étude de cas : redimensionnement automatique des jeux HTML5

Derek Detweiler
Derek Detweiler

Introduction

À l'été 2010, nous avons créé Sand Trap, un jeu que nous avons présenté à un concours de jeux HTML5 pour téléphones mobiles. Toutefois, la plupart des téléphones mobiles n'affichaient qu'une partie du jeu ou le rendaient trop petit, ce qui le rendait complètement injouable. Nous nous sommes donc efforcés de faire en sorte que le jeu s'adapte de manière fluide à n'importe quelle résolution. Après avoir reprogrammé le jeu et utilisé les idées décrites dans cet article, nous avons obtenu un jeu qui s'adapte à tous les navigateurs modernes, qu'il s'agisse d'un ordinateur de bureau ou d'un appareil mobile.

Capture d'écran de Thwack en plein écran
capture d'écran de thwack plus petite 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 les résolutions d'écran pour s'adapter aux fenêtres en plein écran et aux fenêtres de taille personnalisée, comme illustré dans les captures d'écran ci-dessous.

Pour ce faire, nous avons dû exploiter à la fois CSS et JavaScript. Il est facile d'utiliser le CSS pour remplir tout l'écran, mais il ne vous permet pas de conserver le même format pour éviter d'étirer le canevas et la zone de jeu. C'est là que JavaScript entre en jeu. Vous pouvez redimensionner les éléments de document avec JavaScript et déclencher le redimensionnement sur les événements de fenêtre.

Préparer la page

La première étape consiste à désigner la zone de la page sur laquelle le jeu se déroulera. Si vous l'incluez en tant que bloc div, vous pouvez y placer d'autres balises ou un élément de canevas. En le configurant correctement, ces éléments enfants hériteront de la mise à l'échelle du bloc div parent.

Si votre zone de jeu se compose de deux parties, une zone de jeu et une zone de notation, elle peut se présenter comme suit:

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

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

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

Le coin supérieur gauche du canevas se trouve alors au centre de l'écran. La fonction de redimensionnement automatique JavaScript 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.

Étant donné que la zone de jeu est automatiquement redimensionnée en fonction des dimensions de la fenêtre, vous ne souhaitez pas que les dimensions soient exprimées en pixels pour les éléments enfants du bloc div gameArea. Vous préférez les définir en pourcentages. Les valeurs en pixels ne permettent pas aux éléments internes de s'adapter à la div parente lorsqu'elle change. Toutefois, il peut être utile de commencer par les pixels, puis de les convertir en pourcentages une fois que vous avez trouvé une mise en page qui vous convient.

Pour cet exemple, commencez par définir la zone de jeu sur 300 x 400 pixels. Le canevas couvre toute la zone de jeu, et un panneau de statistiques semi-transparent s'étend en bas sur 24 pixels de hauteur, comme illustré dans la figure 1.

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

En traduisant ces valeurs en pourcentages, le canevas mesure 100% de largeur et 100% de hauteur (de gameArea, et non de la fenêtre). En divisant 24 par 300, vous obtenez une hauteur de 8 % pour le panneau des statistiques. Comme il couvrira le bas de la zone de jeu, sa largeur sera également de 100%, comme illustré dans la figure 2.

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

Maintenant que vous avez déterminé les dimensions de la zone de jeu et de ses éléments enfants, vous pouvez rassembler 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;
}

Redimensionner le jeu

Vous êtes maintenant prêt à créer une fonction pour gérer le redimensionnement de la fenêtre. Commencez par obtenir une référence à l'élément de document gameArea parent.

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

Étant donné que vous ne vous souciez pas de la largeur ou de la hauteur exactes, la prochaine information que vous devez définir est le ratio entre la largeur et la hauteur. Vous savez que vous souhaitez définir le format sur 4 unités de largeur et 3 unités de hauteur, car vous avez précédemment indiqué que la zone de jeu mesure 400 x 300 pixels.

var widthToHeight = 4 / 3;

Étant donné que 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;

Vous pouvez ainsi choisir de remplir l'écran verticalement ou horizontalement, comme illustré dans la figure 3.

Ajuster l&#39;élément gameArea à la fenêtre tout en conservant les proportions
Figure 3: Ajustement de l'élément gameArea à la fenêtre tout en conservant le format

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

Pour ce faire, testez le format souhaité avec celui 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 la centrer en plaçant une marge négative en haut correspondant à la moitié de la hauteur et à gauche correspondant à la moitié de la largeur. N'oubliez pas que le CSS place déjà l'angle supérieur gauche de la div gameArea au centre exact de la fenêtre. L'aire de jeu est donc centrée dans la fenêtre:

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

Vous devez également ajuster automatiquement la taille de la police. Si tous les éléments enfants utilisent em, vous pouvez simplement 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, vous devez faire en sorte que les dimensions du canevas correspondent à sa nouvelle largeur et hauteur. Notez que le reste du code du jeu doit séparer les dimensions du moteur de jeu des dimensions de dessin du canevas pour permettre une résolution de canevas dynamique.

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

La fonction de redimensionnement terminée peut donc se présenter comme suit:

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 souhaitez 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 resizeGame() 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 est définie sur 100% de la fenêtre. Si la fenêtre est redimensionnée trop large ou si l'orientation de l'écran est horizontale, la hauteur est définie sur 100% de la fenêtre. La dimension restante est dimensionnée en fonction du format prédéterminé de largeur/hauteur.

Résumé

Gopherwood Studios a utilisé des versions de cette structure pour tous ses jeux HTML5. Elle 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 en plein écran, nos jeux Web offrent une expérience immersive plus proche des jeux sur ordinateur traditionnels que de nombreux jeux basés sur un navigateur. Nous avons hâte de voir de nouvelles innovations dans les jeux Web à mesure que le HTML5 et les technologies Web continueront d'évoluer.