05 juil. 2007

Exploration de XNA : les décors, permière partie

Et de sept ! Au cours de cette série "Exploration de XNA", nous étudierons plusieurs aspects du développement de jeux vidéo, tant au niveau de l'architecture qu'au niveau de la programmation elle même - avec au final un but : réaliser un petit jeu vidéo.

Nous savons afficher un sprite statique, quelque soit la manière dont il est stocké. Depuis le dernier article de la série, nous savons aussi afficher un sprite animé. Mais pour l'instant, tous ces sprites sont affichés au dessus d'un grand vide : il nous manque de toute évidence quelque chose pour donner là vie à un monde virtuel dans lequel le joueur pourra s'épanouir. Ne cherchez plus, j'ai la solution : il s'agit d'un décors, et c'est ce que se propose d'étudier cet article en plusieurs parties.

Le code correspondant à ce billet est disponible ici.

xna_logo.png [Télécharger Visual C# 2005 Express Edition] [Télécharger XNA Game Studio 1.0 Express Edition] [Télécharger le Service Pack 1 pour VC# 2005 EE] [TorqueX, de GarageGames.com] [XNA Resources] [Forum MSDN XNA Game Studio Express] [GameDev.Net - Plenty of 1s and 0s]

Le fond visuel : le background

Dans la terminologie des jeux vidéos 2D, le background rassemble tous les éléments statiques du décors placés derrière ou sous les personnages. On les considère comme statiques parce que les interractions entre ces éléments et les personnages sont limités - tout au plus, ce background va interdire au joueur l'accès à certaines zones. Les éléments plus dynamiques (avec lesquels les personnages peuvent interragir) seront traités dans un billet ultérieur.

Il existe bien évidemment plusieurs types de background - nous allons donc commencer par voir les cas les plus simples : ceux basés sur l'utilisation d'images pleines.

Le plus simple : une image statique

Le type de background le plus simple est celui qui va être composé d'une unique image statique non animée. Ce type de background convient bien à des jeux de type puzzle - comme Tetris ou un jeu de carte - où l'attention du joueur est centrée sur une partie de l'écran bien précise, et où une animation pourrait parasiter sa concentration. Il est, bien évidemment, extrêmement simple à implémenter : il suffit de charger une texture, de définir un pseudo-sprite qui couvre complètement l'écran et d'effectuer le rendu.

Un peu plus compliqué : le background défilant

Un background défilant est composé d'une ou plusieurs images qui vont défiler soit dans une direction (gauche/droite ou haut/bas), soit dans les deux directions. Deux sous-types sont à différencier

  1. dans le premier cas, l'image (ou la série d'image) n'est affichée qu'une fois pendant toute la séquence de défilement. Toute liberté est donnée à l'artiste pour représenter ce qu'il souhaite. Il n'a pas à se soucier d'un problème de transition (si ce n'est la transition entre les images). Effectuer le rendu de ce type de background n'est guère difficile : il s'agit de calculer à chaque rendu les parties d'image qu'il faut dessiner. Si il n'y a qu'une seule image, c'est encore plus simple : la partie de l'image à dessiner est nécessairement un rectangle dans cette image. Si il y a plusieurs images, il faut découper ce rectangle en plusieurs sous rectangle qui correspondront aux parties visibles de chaque image. Pour simplifier les calculs, on peut coller toutes les images en une seule, ce qui nous ramène dans le premier cas.
  2. dans le second cas, une boucle est effectuée sur la ou les images à afficher. Le calcul des parties d'image à afficher est un peu plus complexe que dans le cas précédent, mais sans toutefois relever des mathématiques de haut niveau. Dans le cas ou le background n'est composé que d'une seule image, et si on autorise le défilement dans les deux directions, on doit calculer les coordonnées de 1 à 4 rectangles maximum.

Exemple: un vaisseau spatial sur un fond défilant composé
d'une seule image (résolution d'écran: 320x200; taille du fond: 640x200)

Vaisseau sur fond défilant

Le fait de faire défiler le background donne l'impression que le vaisseau avance alors que sa position réelle n'est pas modifiée. Ce n'est toutefois qu'une astuce graphique, qui ne peut en aucun cas se substituer à la mise à jour du modèle du jeu (où l'on est bien obligé de considérer que le vaisseau avance). Cette astuce est néanmoins très pratique dans de nombreux cas, par exemple lorsqu'on veut faire en sorte que l'avatar du joueur reste toujours au centre de l'écran.

Dans ce cas simple, les calculs effectués sont - bien évidemment - simples. Le code est le suivant:

// xScroll is the topleft position of the visible part
//of our background. It is incremented in Update()
Rectangle destRectangle = new Rectangle(0, 0, 
  ScreenWidth, ScreenHeight);
Rectangle sourceRectangle = new Rectangle(xScroll, 0, ScreenWidth, ScreenHeight);
if (xScroll + ScreenWidth > scrollingBackground.Width) { // the first part of the rectangle is its left part. It maps // to the remaining part of the scrolling background // ie the part that covers (xScroll, background.Width) sourceRectangle.X = xScroll; sourceRectangle.Width = scrollingBackground.Width - xScroll;
destRectangle.Width = sourceRectangle.Width;
spriteBatch.Draw(scrollingBackground, destRectangle, sourceRectangle, Color.White);
// once this has been drawn, we must update the dest // and the source so that the next draw call will draw // the right part of the rectangle (which it at the // beginning of the background texture, in the range // (0, ScreenWidth - part that was drawn before) destRectangle.X = destRectangle.Width; destRectangle.Width = ScreenWidth - destRectangle.X;
sourceRectangle.X = 0; sourceRectangle.Width = ScreenWidth - sourceRectangle.Width; }
spriteBatch.Draw(scrollingBackground, destRectangle, sourceRectangle, Color.White);

Vous pouvez tester cet exemple en lançant le projet ScrollingBackground situé dans le code associé à ce billet. Vous pouvez voir en temps réel le dessin des deux rectangles en pressant la touche "+" de votre clavier numérique ("-" permet de revenir au mode normal) : la première partie du rectangle est dessinée en rouge, et la seconde partie en bleu. Notez que la plupart du temps, seule la seconde partie est dessinée - une fois que xScroll dépasse scrollingBackground.Width, on le réinitialise à 0. Vous pouvez aussi en profiter pour jeter un coup d'oeil à l'image background.jpg.

Une peu de sucre : plusieurs background défilants

Le principe de calcul est le même, mais au lieu de dessiner un seul background, on va en superposer plusieurs qui sont animés à des vitesses différentes, dans le but de créer une illusion de profondeur. C'est ce qu'on appelle le parallax scrolling. Les calculs à effectuer sont les mêmes, le seul point supplémentaire auquel il faut penser est l'ordre de dessin - il faut dessiner les couches les plus profondes d'abord, pour terminer par celles qui sont le plus proche du plan de l'écran.

Le programme ParallaxScrolling dans l'archive du jour démontre cette technique à l'aide du fichier background.jpg de l'exemple précédent et du fichier background2.png, qui est dessiné par dessus le premier (la couche de transparence du fichier PNG permet de voir ce qui est en dessous).

Exemple: parallax scrolling

Vaisseau et parallax scrolling

Le programme est quasiment le même - j'ai juste chargé une texture supplémentaire, et j'ai transformé le code ci-dessus en une méthode plus générique me permettant d'afficher un background à partir de n'importe quelle position xScroll.

Le code

Le code correspondant à ce billet ne contient que les deux exemples mentionnés ci-dessus (ScrollingBackground et ParallaxScrolling). Chaque projet a été simplifié à l'extrême - c'est à dire pas d'utilisation de la librairie SpriteLib ; celle ci sera de retour très prochainement - afin de vous permettre de vous concentrer sur le principe du code. Je vous conseille de vous amuser à créer vos propres fonds (n'importe quelle image fera l'affaire) et de tenter de gérer

  1. le scrolling vertical
  2. le scrolling vertical et le scrolling horizontal ensemble

Les effets obtenus sont souvent saisissants.

Sur ce, à la prochaine fois !

Commentaires

1. Le mardi, août 28 2007, 11:34 par Stéphane

Excellent tutoriaux en Français (je crois bien que ce sont les seuls de cette qualité) !!!
Dans l'attente de la suite avec impatience...
J'aimerais bien (si possible) un didactitiel spécifique à la gestion de l'affichage des textes sous XNA pour les faire bouger dans tous les sens (Scrolling), disparaître ou apparaître progressivement (fading) mais aussi une interaction avec l'utilisateur (clic de la souris, passage du curseur au dessus etc...).
En te remerciant d'avance

Stéphane

2. Le jeudi, août 30 2007, 10:27 par Emmanuel Deloget

Et bien, que dois-je dire à part "merci"? :)

En ce qui concerne la suite, elle viendra courant septembre (pas de date précise), et se concentrera pour un temps sur les autres types de background et sur la gestion de ceux-ci dans un jeu. Ensuite nous aborderont les effets spéciaux réalisables avec l'interface sprite. Et si tout va bien nous aborderons ensuite des sujets plus... mieux.

Ajouter un commentaire

Les commentaires peuvent être formatés en utilisant une syntaxe wiki simplifiée.

Fil des commentaires de ce billet