A tutorial I did for my school in 2008/2009 about XNA (Framework 3). It's in french only.
------------------------------------------------------------
Un tutorial que j'ai fait pour mon école en 2008/2009 sur XNA (Framework 3). C'est en français seulement.
1. XNA – Aide scolaire<br />Par Sonny Brabez, pour les étudiants de SUPINFO.<br />Pour mieux comprendre comment mettre en place l’audio avec XNA, il y a un très bon tutorial en vidéo sur le site suivant : http://creators.xna.com/fr-FR/education/gettingstarted/bg3d/chapter8<br />Points étudiés dans ce document :<br />Mettre en place un projet Windows Game.<br />Comprendre la classe Game1 et les 5 méthodes utilisées par XNA : Initialize, LoadContent, UnloadContent, Update et Draw.<br />Mettre en place des textures 2D : mettre l’image souhaitée dans la solution, l’appeler et l’instancier dans LoadContent().<br />Savoir dessiner une texture 2D : utiliser un SpriteBatch dans la méthode Draw() et comprendre comment placer vos textures sur votre écran.<br />Mettre plusieurs textures et savoir gérer leurs superpositions : le premier sera celui le plus au fond, le dernier sera le plus proche.<br />Savoir mettre des valeurs de rectangles, de vecteurs par défaut dépendantes des textures : dans la méthode LoadContent().<br />Connaître la notion de sprite et comprendre comment gérer les Sprite Sheet : utilisation d’un rectangle source prenant la taille d’un sprite du sprite sheet, sachant que chaque sprite est séparé par une même largeur et hauteur.<br />Savoir utiliser la rotation (vecteur d’origine + angle de rotation), le scaling (zoom), les SpriteEffect (effet miroir) via le SpriteBatch.<br />Mettre en place des classes DrawableGameComponent et savoir les ajouter dans la classe Game1.<br />Permettre la gestion utilisateur (utilisation des manettes, du clavier, de la souris) : classes Keyboard, Mouse et GamePad.<br />Savoir gérer les collisions entre deux rectangles (méthode Intersects).<br />Utiliser XACT, l’outil de mise en place de musiques avec XNA.<br />Mettre en place la musique dans la solution en reprenant le .xap créé par XACT.<br />Mettre en place un projet Windows Game.<br />Il suffit de faire : File > New Project > Windows Game (2.0) OU (3.0).<br />Comprendre la classe Game1 et les 5 méthodes utilisées par XNA : Initialize, LoadContent, UnloadContent, Update et Draw.<br />A l’ouverture de votre projet, vous avez une classe nommée Game1 qui hérite de Game : celle-ci sera votre classe principale.<br />A vous de juger ce que vous mettez dedans. Néanmoins, vous y verrez 5 méthodes obligatoires :<br />Initialize() : permet d’initialiser des objets (hors texture graphismes).<br />LoadContent() : permet d’initialiser tous les objets graphiques (textures).<br />UnloadContent() : permet de détruire les objets graphiques (méthode Dispose() sur les textures).<br />Update(GameTime gameTime) : permet de lancer en boucle les actions répétitives (genre le déplacement des personnages, ennemis etc). Prend en paramètre un GameTime : celui-ci permettant de gérer le temps.<br />Draw(GameTime gameTime) : permet de dessiner de manière répétitives chaque élément.<br />Mettre en place des textures 2D : mettre l’image souhaitée dans la solution, l’appeler et l’instancier dans LoadContent().<br />Pour mettre en place des images sur XNA, il faut tout d’abord les importer dans la solution. Pour cela, il suffit d’aller sur l’explorateur de solution (raccourci clavier : Ctrl+W puis S) et faire du glisser-déposer de vos images dans le dossier « Content ».<br />Remarquer « Content » avec un logo particulier.<br />Pour appeler une image, il faut d’abord la placer dans un objet. Le type d’objet utilisable pour ceci est Texture2D.<br />Pour instancier une texture 2D, il faut d’abord penser à la mettre dans la méthode LoadContent().<br />Ensuite il suffit de prépare sa texture 2D à accueilir le Content Pipeline ainsi :<br />Content.Load<Texture2D>(« nomDeVotreImage »)<br />ATTENTION : si vous aviez une image appelée alpha.png, il faudra marquer : Content.Load<Texture2D>(«alpha »). Il ne faut donc pas mettre le format de l’image à la fin !<br />Exemple :<br />Je prend une image nommée « backgrounds » qui est dans le dossier « Contentackground ».<br />Savoir dessiner une texture 2D : utiliser un SpriteBatch dans la méthode Draw().<br />Nous avons dorénavant mis en place une texture. Cependant celle-ci doit être dessinée. Pour cela, il faut utiliser un SpriteBatch, créé par défaut dans le LoadContent() en tant que spriteBatch.<br />S’il vous faut créer un SpriteBatch, penser que celui-ci prend en paramètre un GraphicDevice, disponible grâce au GraphicsDeviceManager. Par défaut, il s’agit de la variable graphics.<br />Le SpriteBatch doit être utilisé dans Draw() pour mettre en place un dessin.<br />Penser d’abord à démarrer le SpriteBatch dans Draw() avec : spriteBatch.Begin().<br />Penser ensuite à lui dire tout ce que vous voulez dessiner.<br />Et enfin pensez à l’arrêter : spriteBatch.End().<br />Supposons que nous voulons dessiner dans notre SpriteBatch, il faudra utiliser : spriteBatch.Draw(paramètres).<br />Il faut savoir qu’il existe plusieurs surcharges de la méthode faisant qu’elle utilise plusieurs paramètres. Voici une définition des paramètres possibles :<br />Texture2D : prend une texture.<br />Rectangle : prend un rectangle définissant un dessin de votre texture. Permet de dimensionner votre texture (et donc au préalable de l’aggrandir grâce à Width et Height) et de la placer sur votre écran. On va également préciser la position sur votre écran de la texture (via X et Y).<br />Vector2 : permet de mettre en place un vecteur (donc de gérer la position X/Y d’une texture). Il peut y en avoir deux dont 1 sert également à gérer la rotation (ce sera le vecteur d’origine).<br />Rectangle? : prend un rectangle source. Ceci est utilisé dans le cas des Sprite Sheet, pour séparer chaque sprite qui est à l’intérieur d’un Sprite Sheet.<br />Color : permet de définir une couleur à votre texture (Color.White permet de ne pas mettre de couleur particulière à votre texture).<br />float : Ici on peut en avoir 3 différents. Un sera pour l’angle de rotation en radian. Le second sera pour le zoom de votre texture (ATTENTION à bien toujours le mettre à 1 sinon votre texture ne sera jamais présente !). Le troisième sera pour la profondeur.<br />SpriteEffect : le SpriteEffect permet de faire un effet miroir de votre texture. FlipHorizontally fait l’effet miroir de gauche à droite.<br />Exemple avec mise en place d’une texture, d’un rectangle de dimension et d’une couleur :<br />Exemple avec mise en place d’une texture, d’un rectangle de base, d’un rectangle source (pour couper le sprite sheet) et d’une couleur :<br />Exemple avec mise en place d’une texture, d’un vecteur, d’un rectangle source, d’une couleur, d’une rotation, d’un vecteur d’origine, d’un zoom, d’un SpriteEffect et d’une profondeur :<br />A savoir : En XNA, penser que votre écran de jeu a un axe abscisses (X)/ordonnées (Y) tel que le point d’origine (0,0) est en haut, à gauche.<br />Exemple :<br />Mettre plusieurs textures et savoir gérer leurs superpositions : le premier sera celui le plus au fond, le dernier sera le plus proche.<br />Dans le SpriteBatch, l’ordre est simple : le premier élément dessiné sera celui placé le plus au fond. C’est comme dans une peinture !<br />Ainsi le dernier élément placé sera donc le dernier à être dessiné.<br />Exemple :<br />Ici, si on prend le code dans le switch, case 1, le premier « hill » est placé dans notre écran PUIS le deuxième « hill2 » est placé faisant que « hill2 » sera AU DESSUS de « hill ».<br />A savoir : penser que quand vous ajoutez des composants DrawableGameComponent, ils se placeront selon leur ordre d’ajout donc le premier ajouté sera donc celui le plus au fond de votre écran !<br />Savoir mettre des valeurs de rectangles, de vecteurs par défaut dépendantes des textures : dans la méthode LoadContent().<br />Vous aurez remarqué que pour nos Draw dans le SpriteBatch, nous avons souvent besoin de vecteurs ou de rectangles.<br />Si on veut que ces vecteurs ou rectangles prennent des valeurs reprises de la texture, il est nécessaire de les placer là où on initialise la texture c'est-à-dire le LoadContent().<br />En effet, les placer dans Update() ou Draw() serait un très mauvais choix car ceux-ci sont systématiquement relancés (contrairement à LoadContent()).<br />Voici un exemple :<br />Ici on voit que je donne à mon vecteur marioMovements une hauteur qui DEPEND de ma texture, d’où la nécessité de faire mon instance de vecteur dans le LoadContent().<br />Connaître la notion de sprite et comprendre comment gérer les Sprite Sheet : utilisation d’un rectangle source prenant la taille d’un sprite du sprite sheet, sachant que chaque sprite est séparé par une même largeur et hauteur.<br />Le sprite est en fait un simple personnage qui possède un unique mouvement.<br />Un sprite sheet est simplement composé de plusieurs sprites permettant de donner une dynamique de mouvements (car un sprite = un mouvement) et donc par exemple de faire qu’un personnage puisse courir, sauter, tomber etc.<br />Pour mettre en place un sprite sheet, il est essentiel d’avoir une largeur et hauteur égales entre chaque sprite de ce sprite sheet.<br />Exemple de Sprite Sheet :<br />Ici Mario a 4 sprites dont chaque sprite a une largeur de 16 et une hauteur de 27. Le total de sa largeur (c'est-à-dire les 4 sprites réunis) est également à noter : 64.<br />Pour mettre en place une solution avec Sprite Sheet, il est essentiel d’instancier un Rectangle qui commencera au début du sprite sheet (ici le début du sprite sheet est à X = 0 et Y = 0) et qui aura pour largeur celle d’UN SPRITE (16 ici) et la longueur d’UN SPRITE.<br />Ensuite, il faudra penser à glisser entre chaque sprite en ajoutant à chaque fois à l’abscisse du rectangle (X), la largeur d’un sprite. <br />Pour revenir à la case départ, penser à faire un modulo sur l’abscisse du rectangle (X) en utilisant la largeur totale de notre sprite sheet (ici 64).<br />Exemple d’instance :<br />Le rectangle nommé marioSheet est mon instance, contenant uniquement une largeur de 16 et une hauteur de 27, c'est-à-dire : un sprite de notre sprite sheet. La texture « Characters/mariobrosdroite » est un sprite sheet. Le vecteur va permettre de bouger la texture par rapport à l’écran alors que le rectangle va permettre de glisser la texture vers un autre sprite.<br />Exemple de glissage :<br />Ici dans Update(), j’ai décidé d’avancer Mario en gérant à la fois son vecteur (qui avance sa texture) et son rectangle (qui avance son sprite sheet). La partie du sprite sheet est à l’intérieur du compteur : j’ajoute 16 à l’abscisse de mon rectangle et je module à 64, la totalité de l’image<br />Savoir utiliser la rotation (vecteur d’origine + angle de rotation), le scaling (zoom), les SpriteEffect (effet miroir) via le SpriteBatch.<br />Pour pouvoir utiliser rotation, zoom, SpriteEffect, il faut d’abord les utiliser dans les Draw() du SpriteBatch.<br />Une rotation va permettre de changer d’angle votre texture mais pour cela il est nécessaire de prévoir un vecteur d’origine puis un angle.<br />L’angle peut se faire via l’aide de la classe MathHelper (et ses propriétés Pi).<br />Un zoom s’utilise simplement avec des nombres flottants ( ne pas oublier le f après le chiffre quand on gère des nombres flottants). Attention à ne pas l’avoir à zéro, sinon plus rien ne s’affiche.<br />Un SpriteEffect est une énumération permettant de tourner votre texture dans le sens d’un miroir (donc une symétrie par rapport à un axe). Attention à ne pas confondre avec la rotation.<br />Mettre en place des classes DrawableGameComponent et savoir les ajouter dans la classe Game1.<br />Une classe DrawableGameComponent permet de créer des classes entières pour un élément au lieu de tout faire au niveau de Game1.<br />Pour la créer, il faut d’abord mettre en place un GameComponent puis changer l’héritage par DrawableGameComponent.<br />Exemple :<br />Avant, j’avais juste GameComponent et je l’ai remplacé par DrawableGameComponent.<br />Penser à bien remettre toutes les méthodes en écrivant « override » et vous aurez une petite bulle où vous pouvez choisir les méthodes à redéfinir. Logiquement il faut remettre : LoadContent(), UnloadContent() et Draw(GameTime gameTime).<br />Il suffit ensuite de faire comme dans la classe Game1.<br />Pour associer à Game1 nos DrawableGameComponent, vous aurez remarqué que dans le constructeur du DrawableGameComponent j’ai un constructeur prenant un Game. C’est par cela qu’on pourra gérer la liaison entre les deux classes.<br />Dans Game1, il faudra juste ajouter : Components.Add(DrawableGameComponent).<br />Exemple :<br />J’ai ajouté un Drawable Mario, que j’ai instancié en fonction de la classe Game1 (via this) puis je l’ai ajouté en tant que composant.<br />Dans DrawableGameComponent, pour reprendre les éléments de notre Game1 (attention à penser à mettre quelques éléments en public : en autre le GraphicsDeviceManager), il suffit de faire un cast : ((Game1)Game)<br />Autre méthode possible en exemple :<br />Ici, ma classe Game1 (que j’ai renommé MarioGame), j’en crée un objet que j’instancie avec le Game game présent dans le constructeur de mon DrawableGameComponent.<br />Permettre la gestion utilisateur (utilisation des manettes, du clavier, de la souris) : classes Keyboard, Mouse et GamePad.<br />Pour qu’un utilisateur puisse jouer, il doit pouvoir contrôler au moins 1 texture. Pour cela, il y a présence de classes telles que Keyboard, Mouse et GamePad.<br />ATTENTION : il est inutile de les instancier… leurs méthodes sont statiques et donc disponible à partir de la classe.<br />Il faut penser à gérer ces événements dans Update().<br />Exemple :<br />Ici si j’appuie sur Haut (IsKeyDown(Keys.Up)), ma texture va perdre 30 en ordonnée (elle va donc monter sur mon écran ).<br />Penser qu’on peut gérer quand aucune touche n’est appuyée de la manière suivante :<br />Savoir gérer les collisions entre deux rectangles (méthode Intersects).<br />Pour la gestion des collisions, il faut penser à mettre en place au moins deux rectangles.<br />Pour gérer la collision il suffit de faire : rectangleA.Intersects(rectangleB).<br />Ce résultat envoie un booléen précisant s’il y a collision.<br />A savoir : je vous recommande de créer des méthodes dans vos Drawable et ensuite de les appeler dans la classe Game1.<br />Exemple :<br />Dans mon Drawable, je renvois un rectangle de mon Mario auquel je mets à jour son mouvement (très important !).<br />Même chose pour mon Goomba (un ennemi).<br />Ici dans mon Update de Game1, je dis que si Mario est en collision avec Goomba alors selon si Mario saute ou non, je dispose soit Goomba soit Mario.<br />Utiliser XACT, l’outil de mise en place de musiques avec XNA.<br />Pour pouvoir gérer les sons/musiques sur XNA, il faut lancer XACT. Pour cela, il faut aller chercher ici (si vous avez la version 3 de XNA, logiquement c’est pareil pour la version 2) : C:rogram Filesicrosoft XNANA Game Studio3.0ools <br />Ouvrer : Xact.exe (et AudConsole.exe si vous voulez pouvoir écouter les sons ajoutés).<br />Dedans, il est nécessaire de créer un nouvel élément en allant sur File > New Project.<br />Ensuite, penser à renommer votre projet AVANT enregistrement, sinon ce sera trop tard ! (Le nom est important)<br />Ajouter une Wave Bank et faites clique droit « Insert Wave File(s) » et prenez toutes vos musiques en .WAV ou .AIFF. (nommer bien votre Wave Bank). A savoir : le choix multiple est possible.<br />Ajouter ensuite une Sound Bank. Faites glisser déposer les éléments de votre Wave Bank dans la partie Cue de votre Sound Bank. Nommer bien votre Sound Bank.<br />Enregistrer tout et c’est fini avec XACT.<br />Résultat possible :<br />Mettre en place la musique dans la solution en reprenant le .xap créé par XACT.<br />Pour mettre la musique dans votre jeu, n’oubliez pas les étapes suivantes :<br />Dans le dossier « Content » de notre solution (via Solution Explorer), insérer le fichier .xap créé par XACT.<br />Via Windows, aller dans le dossier de votre solution, dans le dossier « Content » et ajouter TOUT les Wav pour qu’ils soient retrouvés. JE VOUS PREVIENS QUE JE NE SUIS PAS SUR DE CELA… MAIS JE N’ARRIVE PAS A FAIRE FONCTIONNER AUTREMENT…<br />Dans votre solution, instancier trois éléments :<br />AudioEngine, WaveBank et SoundBank.<br />Finir par jouer une musique grâce au SoundBank et la méthode PlayCue attendant le nom d’une musique (Cue Name).<br />Ne pas oublier de mettre à jour le AudioEngine via sa méthode Update.<br />Exemple :<br />ATTENTION : L’AudioEngine prend un .xgs dont le nom sera celui du .xap. Le WaveBank prend le nom du wave bank créé dans XACT et a pour extension .xwb. De même niveau SoundBank sauf que c’est une extension .xsb.<br />