Space shooter : Aron & The Aliens

Chapitre 14 : Ajoutons une ceinture d'astéroïdes

 

Tutoriel présenté par : Robert Gillard (Gondulzak)
Publication : 19 juillet 2014
Dernière mise à jour : 20 juin 2016

 

      Préliminaires

   Dans notre précédent tutoriel nous avons créé une nouvelle classe : la classe « Animation ». Celle-ci va gérer les animations de nos différentes feuilles de sprites et notamment, en ce qui concerne ce chapitre, notre astéroïde : «Asteroides43x32.png».

   A cet effet nous allons écrire une nouvelle classe, la classe «Asteroids». Vous verrez que notre code va très vite s'étoffer mais nous le ferons en douceur, donc pas de panique, cela va très bien se passer. wink

   Nous allons donc faire défiler des astéroïdes dont les positions initiales seront générées aléatoirement sur l'axe X à partir du haut de l'écran de jeu et se dirigeant vers le bas de l'écran avec un aspect flottant en tournant sur eux-mêmes. cool D'ici quelques chapitres, nous allons voir les effets dévastateurs de ces «pierres» flottantes qui n'épargneront ni notre héro ni les aliens mais que nous pourrons quand-même «exploser» à l'aide de super fireballs. Mais je m'avance un peu, là... devil En tout cas vous savez maintenant à quoi vont servir ces «débris» de l'Espace... cheeky


   Remarques sur la « ceinture d'astéroïdes »

   Il faut garder à l'esprit que dans notre jeu, les astéroïdes ayant tous la même direction, ils ne se rencontreront jamais et il n'y aura donc pas de collision astéroïde – astéroïde. Ceci nous laisse entrevoir un premier challenge d'amélioration du jeu dès que celui-ci sera terminé (je vous rappelle que le jeu est pratiquement entièrement programmé et que les améliorations éventuelles ne seront envisageables qu'après cette série de tutoriels wink ).

   Une modification de l'implémentation de la gestion de ces astéroïdes serait de leur donner une origine et des directions aléatoires dans l'écran de jeu afin de permettre une série de collisions supplémentaires astéroïde – astéroïde, ce qui devrait ajouter un «plus» au gameplay et, pourquoi pas, le tutoriel sur le SAT de notre ami Tankerpat pourrait nous aider à ce moment-là (tutoriel à venir au moment de la publication de ce tuto). cool

 

Le projet « AronAndTheAliens04 »

 

   Reprenez votre projet précédent ou créez-en un nouveau que vous nommerez «AronAndTheAliens04» (reportez-vous au chapitre précédent en ce qui concerne les manipulations à réaliser).

 

     1 – Classe Asteroids : Le code

   Ok, vous pouvez maintenant créer une nouvelle classe, la classe «Asteroids». Remplacez le code existant par le code suivant :

#region Description
//MERUVIA XNA TUTORIALS
//AronAndTheAliens04
//Jeu : Aron and the aliens
//Mise en place de la ceinture d'astéroïdes
//Fichier : Asteroids.cs
//Last update : 17/07/2014
#endregion
 
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
 
namespace AronAndTheAliens04
{
    class Asteroids
    {
        #region Déclaration des variables de la classe Asteroids
 
          // L'animation qui représente les asteroïdes
          public Animation AsteroidAnimation;
 
          // Position de l'asteroïde relative au coin supérieur gauche de l'écran
          public Vector2 Position;
 
          // Etat de l'asteroïde
          public bool Active;
 
          // Points de vie de l'astéroïde.  Si ceux-ci sont égal à zero,
          // l'astéroide se désintègre
          public int Health;
 
          // La quantité de dommages infligés à l'astronef ou aux aliens
          // !!! UN SEUL CONTACT AVEC UN ASTEROIDE FAIT EXPLOSER L'ASTRONEF !!!
          public int Damage;
 
          // Le score que donne un astéroïde au joueur
          public int score;
 
          // La quantité de gold reçue par le joueur par astéroïde détruit
          public int gold;
 
          //Vitesse de déplacement des astéroïdes
          float asteroidMoveSpeed;
       
        #endregion Déclaration des variables de la classe Asteroids
 
 
        #region Propriétés
         
          // Renvoie la largeur d'un astéroïde
          public int frameWidth
          {
              get { return AsteroidAnimation.FrameWidth; }
          }
 
          // Renvoie la hauteur d'un astéroïde
          public int frameHeight
          {
              get { return AsteroidAnimation.FrameHeight; }
          }
       
        #endregion Propriétés
 
 
        #region Fonction d'initialisation
       
          public void Initialize(Animation animation, Vector2 position)
          {
 
              // Charge la texture d'un astéroïde
              this.AsteroidAnimation = animation;
 
              // Initialise la position d'un astéroïde
              this.Position = position;
 
              // Initialise un astéroïde "actif" au démarrage du jeu
              Active = true;
 
              // Points de vie d'un astéroïde
              Health = 750;
 
              // Dommages occasionnés par un astéroïde
              Damage = 5000;
 
              // Vitesse de déplacement d'un astéroïde
              asteroidMoveSpeed = 0.5f;
 
              // Score obtenu si astéroïde détruit
              score = 100;
 
              // Gold obtenu si astéroïde détruit
              gold = 50;
 
          }
        
        #endregion Fonction d'initialisation
 
 
        #region Fonction de mise à jour
       
          public void Update(GameTime gameTime)
          {
              // La direction d'un astéroïde va du haut vers le bas et la droite.
              Position.Y += asteroidMoveSpeed;
              Position.X += asteroidMoveSpeed;
 
              // Mise à jour de la position de l'animation
              AsteroidAnimation.Position = Position;
 
              // Mise à jour de l'animation
              AsteroidAnimation.Update(gameTime);
 
              // Si un astéroïde dépasse le bas ou la droite de l'écran, ou si ses
              //points de vie sont <= 0, on le désactive.
              if ((Position.Y >= 480 + frameHeight / 2 || Health <= 0)
                            || ((Position.X >= 800 + frameWidth / 2 || Health <= 0)))
              {
                //Si on met le "drapeau" Active à false, on enlève l'objet de la liste
                  Active = false;
              }
          }
        
        #endregion Fonction de mise à jour
 
 
        #region Fonction de dessin
       
          public void Draw(SpriteBatch spriteBatch)
          {
              // Dessine l'animation
              AsteroidAnimation.Draw(spriteBatch);
          }
       
        #endregion Fonction de dessin
    }
}
 

 

  Je pense que les commentaires ajoutés tout au long du code la de la classe «Asteroids» sont relativement explicites, je vais simplement ajouter quelques remarques. wink

   Déclarations

   Notre première déclaration est AsteroidAnimation, de type Animation. Il faut savoir que si Animation est une classe que nous avons créée dans le chapitre précédent, elle est aussi ici considérée comme un type.

   Certaines déclarations de notre classe se rapportent bien sûr à tout ce qui est en rapport avec la classe ( position des astéroïdes, points de santé, état), mais d'autres déclarations vont également agir sur d'autres classes (Enemy et Hero) en modifiant certaines de leurs valeurs en fonction des collisions (dommages causés, score et gold obtenus wink


   Propriétés

   Nous avons également besoin de deux Propriétés que nous avons dénommées frameWidth et frameHeight, et qui (petit rappel) nous permettront d'accéder à la largeur et à la hauteur des frames de nos astéroïdes en dehors de la classe.

 

    Fonction Initialize()

   Celle-ci prend en paramètres deux variables représentant l'animation d'un astéroïde ainsi que sa position sur l'écran.

   Nous initialisons ensuite les valeurs des variables représentant l'état d'un astéroïde, ses points de santé, les dommages causés, sa vitesse, le score et la quantité de gold obtenus par le joueur lors de la destruction d'un astéroïde.

   Les points de santé sont initialisés à 750. Nous verrons lors de la gestion des collisions super fireball – astéroide qu'il faudra 10 tirs pour «exploser» un astéroïde, les dommages causés par une super fireball étant de 75 PV / tir.

   De même, un score de 100 unités et un gain de 50 gold seront portés au crédit du joueur pour la destruction d'un astéroïde. cool

   Et c'est tout ce qu'il faut savoir au sujet de la fonction Initialize(), celle-ci ne présente aucune difficulté.


   Fonction Update()

   Ici nous voyons que la variable Position de type Vector2 donne la direction du déplacement de l'astéroïde. En effet, comme chaque déplacement modifie la position en Y et en X de la même valeur «asteroidMoveSpeed» nous voyons que la direction que prend l'astéroïde va du haut vers le bas et de la gauche vers la droite. wink

   Suivent ensuite les mises à jour des déplacements et de l'animation des astéroïdes. Et pour terminer, nous devons enlever un astéroïde de la liste des astéroïdes dès que celui-ci disparaît de l'écran ou que ses points de santé descendent à zéro lors de tirs de l'astronef. Pour ce faire, nous faisons un test sur ses points de santé et 2 autres pour voir s'il sort par le bas ou par le côté droit de l'écran. Dans ce cas, nous mettons le drapeau Active à false pour qu'il soit enlevé de la liste (nous allons le voir bientôt wink) dans la fonction UpdateAsteroid() du fichier AronAndTheAliens04.cs.

 

   Fonction Draw()

   Dans la fonction Draw(), nous dessinons simplement l'animation à l'aide de l'instruction

AsteroidAnimation.Draw(spriteBatch);


  Et c'est tout pour la classe «Asteroids», nous pouvons maintenant compléter le code de notre fichier AronAndTheAliens04.cs.


   2 – Fichier «AronAndTheAliens04.cs»

   On retourne donc maintenant dans notre fichier AronAndTheAliens04.cs. Avant toute chose, n'oubliez pas de mettre le fichier Asteroides43x32.png dans le dossier Textures de votre projet (je vous rappelle que vous trouverez toutes les images nécessaires a la réalisation de ce projet dans le fichier AronAndTheAliens04Content qui se trouve dans le fichier .zip qui accompagne ce chapitre et que vous pouvez bien entendu télécharger ci-dessus wink).

   Ceci étant fait, en dessous de la déclaration des polices de caractères, ajoutez les lignes suivantes :

 

        #region ASTEROIDS DECLARATIONS DATA'S
        
          Texture2D asteroidTexture;     //Texture asteroids
          Vector2 location;              //Position aléatoire d'un astéroïde à l'écran
 
 
          private Rectangle initialAsteroidFrame;  //Le rectangle qui contiendra une 
                                                   //frame de l'astéroïde
 
          Random rand = new Random();              //Variable d'élément aléatoire
 
 
          List<Asteroids> asteroids;               //Les astéroïdes seront gérés dans 
                                                   //une liste
 
 
          // La fréquence à laquelle apparaît un astéroïde
          TimeSpan asteroidSpawnTime;
          TimeSpan previousAsteroidSpawnTime;
       
        #endregion ASTEROIDS DECLARATIONS DATA'S

 

   Ces lignes représentent une région qui concerne des déclarations de données se rapportant aux astéroïdes, c'est pourquoi je l'ai dénommée «Asteroids declarations data's». Et comme je vous l'ai signalé dans le chapitre précédent, une région commence par un #region et se termine obligatoirement par un #endregionwink

   Les données sont commentées et ne présentent aucune difficulté de compréhension. Je vous dirai simplement que le type TimeSpan représente le temps écoulé et sera utilisé comme timer (Je vous rappelle que vous pouvez utiliser le forum pour poser l'une où l'autre question concernant un ou plusieurs points concernant les différents chapitres).

   Nous passons à une autre région, maintenant ajoutez les lignes suivantes :

 
    #region KEYBOARD / GAMEPAD
        
          // Les états du clavier qui détermineront les touches pressées
          KeyboardState currentKeyboardState;
          KeyboardState previousKeyboardState;
 
          // Les états du gamepad qui détermineront les boutons pressés
          GamePadState currentGamePadState;
          GamePadState previousGamePadState;
       
    #endregion KEYBOARD / GAMEPAD

 

   Dans cette portion de code, nous initialisons simplement les états «courant» et «précédent» du clavier et du gamepad.

   Et dans la fonction Initialize(), au-dessus de l'instruction base.Initialize(); , ajoutez le code suivant :
 

#region INITIALIZE ASTEROIDS DATA'S            
            
     //Dimensionne une frame
     initialAsteroidFrame.Width = 43;
     initialAsteroidFrame.Height = 32;
 
     Vector2 location = Vector2.Zero;  //Initialisation de la position aléatoire
                                       //d'un astéroïde à l'écran.
            
     //Instanciation de la liste asteroids
     asteroids = new List<Asteroids>();
 
     // Initialise les différents timers à zero
     previousAsteroidSpawnTime = TimeSpan.Zero;
 
     // Détermine à quelle fréquence un astéroïde réapparait
     asteroidSpawnTime = TimeSpan.FromSeconds(3.0f);
           
#endregion INITIALIZE ASTEROIDS DATA'S

 

   Code dans lequel nous initialisons les variables déclarées plus haut avec en premier lieu les dimensions de la variable de type Rectangle «initialAsteroidFrame», soit une largeur de 43 pixels et une hauteur de 32 pixels.

   La variable location, définissant la position d'apparition aléatoire d'un astéroïde est initialisée en (0, 0), soit Vector2.Zero. Nous créons ensuite une instance de la classe représentant la liste des astéroïdes puis nous initialisons notre timer à zéro.

   Pour terminer, nous donnons une valeur égale à 3 secondes à la variable asteroidSpawnTime, ce qui représente la fréquence d'apparition des astéroïdes à l'écran.

   Et c'est tout en ce qui concerne la fonction Initialize()wink


   Dans la fonction LoadContent(), en dessous de planets = new Planets(Content); , ajoutez le code suivant :

 
#region TEXTURES
            
     //Textures sprites
     asteroidTexture = Content.Load<Texture2D>("Textures/Asteroides43x32");
           
#endregion TEXTURES

 

   Dans lequel nous chargeons notre nouvelle texture Asteroides43x32.png.

   Et c'est tout en ce qui concerne la fonction LoadContent(). Nous allons maintenant écrire le code de la fonction de génération aléatiore d'un astéroïde qui nous servira également plus tard pour générer des «bonus» à l'écran.


   Et voici le code de cette fonction que vous entrerez à la suite de la fonction UnloadContent() :

 
#region RANDOM HORIZONTAL DATA'S LOCATIONS FUNCTION
        
  // Fonction de génération aléatoire de la position d'un astéroide ou d'un bonus
  // sur la longueur de l'écran.
  // InitialAsteroidInitialFrame.Width est ici considérée comme la valeur ajoutée
  // au début et retirée à la fin de l'aire de jeu et dans laquelle il ne pourra y
  // avoir d'apparition aléatoire.
 
 
  private Vector2 randomHorizontalLocation()
  {
      location.X = rand.Next(0 + initialAsteroidFrame.Width, 800 -
                                         (2 * initialAsteroidFrame.Width));         
      location.Y = 0;
 
      return location;
  }
       
#endregion RANDOM HORIZONTAL DATA'S LOCATIONS FUNCTION

 

   Un astéroïde aura toujours sa position initiale en Y = 0. Sa position sur l'axe X sera générée aléatoirement à partir d'une position X = 0 + 43 (43 étant la largeur d'une frame de l'astéroïde wink, pour qu'il apparaisse en entier) et jusqu'à une position X = 800 – 2*43 (soit la largeur de l'écran moins deux fois une largeur de frame).

   Et ceci a pour but de voir la génération de TOUS les astéroïdes à l'écran. En effet, si un astéroïde était généré en X=800, son déplacement vers la droite ferait qu'il ne pourrait être aperçu à l'écran et serait automatiquement retiré de la liste.

   C'est tout en ce qui concerne notre fonction de génération aléatoire. Maintenant nous allons écrire la fonction AddAsteroid(), qui ajoute un astéroïde à la liste des astéroïdes. A la suite de ce que vous venez d'écrire, entrez le code suivant :

 
#region ADD ASTEROID TO LIST
        
          //Ajoute un astéroïde à la liste
          private void AddAsteroid()
          {
              // Creation d'une animation d'un astéroïde
              Animation asteroidAnimation = new Animation();
 
              // On initialise l'animation par rapport aux données de la feuille de 
              // sprites et le temps que nous désirons appliquer entre chaque frame
              asteroidAnimation.Initialize(asteroidTexture,
                                           location,
                                           initialAsteroidFrame.Width,
                                           initialAsteroidFrame.Height,
                                           7,
                                           175,
                                           Color.White,
                                           1.0f,
                                           true);
 
              //Appel à la fonction randomHorizontalLocation pour la génération 
              //aléatoire d'un astéroïde à un endroit quelconque sur l'axe des X
              location = randomHorizontalLocation();
 
 
              // Creation d'un astéroïde
              Asteroids asteroid = new Asteroids();
 
              // Initialise l'astéroïde
              asteroid.Initialize(asteroidAnimation, location);
 
 
              // Ajout de l'astéroïde à la liste active des astéroïdes
              asteroids.Add(asteroid);
          }
       
#endregion ADD ASTEROID TO LIST

 

   Dans la fonction AddAsteroid(), nous commençons par créer l'animation d'un astéroïde et ensuite nous initialisons l'animation créee en passant à la fonction Initialize() les paramètres texture, location, largeur, hauteur, nb de frames / feuille, nb de millisecondes/frame, la couleur, l'échelle, et l'état de l'animation.

   La valeur 175 qui représente le nombre (nb) de secondes / frame n'est pas une constante dans les paramètres passés à la fonction Initialize(). Notre animation ne possédant que 7 frames, j'ai cherché une valeur acceptable afin de ne pas avoir une animation saccadée ou trop rapide et la valeur 175 me semble représenter au mieux celle-ci. wink

   Nous faisons ensuite appel à la fonction randomHorizontalLocation() pour déterminer une position aléatoire d'un astéroïde sur l'axe X et nous retournons la valeur générée dans la variable location. Ok, nous avons l'animation et la position de l'astéroïde à afficher à l'écran, nous n'avons plus qu'à créer l'objet lui-même en créant une instance de la classe Asteroids et initialiser l'objet en passant son animation ainsi que sa position à la fonction Initialize().

   Et pour terminer, nous ajoutons l'astéroïde à la liste des astéroïdes à l'aide de l'instruction asteroids.Add(asteroid);

   Nous devons maintenant mettre à jour la liste des astéroïdes à l'aide de la fonction UpdateAsteroids(), donc à la suite de la fonction AddAsteroid() entrez le code suivant :

 
   #region ASTEROIDS UPDATE LIST FUNCTION
        
          //Mise à jour de la liste des astéroïdes
          private void UpdateAsteroids(GameTime gameTime)
          {
              // Génère un nouvel astéroïde toutes les 3.0 secondes
              if (gameTime.TotalGameTime - previousAsteroidSpawnTime > asteroidSpawnTime)
              {
                  previousAsteroidSpawnTime = gameTime.TotalGameTime;
 
                  // Ajout d'un astéroïde
                  AddAsteroid();
              }
 
              // Mise à jour des astéroïdes
              for (int i = asteroids.Count - 1; i >= 0; i--)
              {
                  asteroids[i].Update(gameTime);
 
                  if (asteroids[i].Active == false)
                      asteroids.RemoveAt(i);
 
              }
          }
       
 
  #endregion ASTEROIDS UPDATE LIST FUNCTION

 

   Cette fonction va dans un premier temps générer un nouvel astéroïde toutes les 3 secondes et l'ajouter à la liste des astéroïdes par l'appel à la fonction AddAstéroid() que nous venons de voir plus haut.

   Nous parcourons ensuite toute la liste des astéroïdes afin de permettre leur mise à jour et voir si leur état est toujours actif. Si le booléen Active est false pour un objet d'un indice quelconque de la liste, celui-ci est immédiatement enlevé de cette liste à l'aide de l'instruction asteroids.RemoveAt(i); .

  Et c'est tout en ce qui concerne la fonction UpdateAsteroids()wink

 

   Nous pouvons maintenant passer à la modification de la fonction Update() du fichier AronAndTheAlien04.cs. Je me permets de vous rappeler que si vous faites un nouveau projet par chapitre, que vous devez y intégrer les codes et dossiers du chapitre précédent avant d'écrire tous les codes que je vous livre ici..

   Notre fonction Update() du chapitre précédent, étant relativement courte, je vous propose de la supprimer entièrement et de la remplacer par celle-ci :

 
 #region FUNCTION UPDATE
        
          protected override void Update(GameTime gameTime)
          {
              // Permet la sortie du jeu
              if ((currentKeyboardState.IsKeyDown(Keys.Escape) ||
                     (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)))
                 this.Exit();
 
              /* Sauve le précédent état du clavier et du gamepad afin que l'on puisse
                 déterminer quelle touche/bouton sera pressé(e) */
              previousGamePadState = currentGamePadState;
              previousKeyboardState = currentKeyboardState;
 
              // Lit l'état courant du clavier ou du gamepad et l'enregistre
              currentKeyboardState = Keyboard.GetState();
              currentGamePadState = GamePad.GetState(PlayerIndex.One);
 
              //Mise à jour du background et des images défilantes
              background.UpdateBackground();
              planets.UpdatePlanets();
 
              //Mise à jour des astéroîdes
              UpdateAsteroids(gameTime);
 
              //base.Update(gameTime);
          }
       
 #endregion FUNCTION UPDATE

 

   Dans la fonction Update(), nous permettons premièrement la possibilité de sortir du programme soit en pressant la touche «Escape» du clavier numérique soit en pressant le bouton «Retour» du gamepad.

   Nous désignons ensuite les états précédents du clavier et du gamepad comme étant les états actuels et ce, afin de déterminer le bouton ou la touche pressé(e). Les états courants du clavier ou du gamepad sont ensuite enrégistrés dans les variables currentKeyboardState et currentGamePadState.

   Et à la suite de la mise à jour du background et des images défilantes nous faisons une mise à jour de la liste des astéroïdes par l'instruction UpdateAsteroids(gameTime); .

   C'est tout pour notre fonction Update(), il nous reste à compléter la fonction Draw(), sans toucher à la fonction DrawHud() pour l'instant.

 

   Donc, dans la fonction Draw(), nous allons dessiner nos astéroïdes. Juste en dessous de l'appel à la fonction Drawhud(), ajoutez les lignes suivantes :

 
             // Dessine les astéroïdes
             for (int i = 0; i < asteroids.Count; i++)
             {
                 asteroids[i].Draw(spriteBatch);
             }

 

   Et c'est tout pour ce chapitre ! cool

   Pour la suite, j'ai quelque peu modifié l'ordre des chapitres à présenter. En effet, dans le chapitre 15, nous mettrons en oeuvre la classe «Enemy» dans laquelle nous allons générer la horde d'aliens que notre héros devra bientôt combattre. wink

   Mais en attendant, compilez ce projet et admirez la progression des astéroïdes dont je vous donne deux screenshots ici :

 

 

   A bientôt pour la suite. smiley

         Gondulzak.

 


 

Abonnez-vous et devenez Premium pour lire la fin de ce tuto ainsi que tous les autres tutos du site !

 

 

   Et voici maintenant la liste des chapitres suivants, de ce tuto, auxquels vous aurez accès :

- Big tuto XNA : Chapitre 15 : Space shooter - Les ennemis
- Big tuto XNA : Chapitre 16 : Space shooter - Les Ovnis
- Big tuto XNA : Chapitre 17 : Space shooter - La MSF
- Big tuto XNA : Chapitre 18 : Space shooter - Le Héros
- Big tuto XNA : Chapitre 19 : Space shooter - Les Power-ups
- Big tuto XNA : Chapitre 20 : Space shooter - Le script
- Big tuto XNA : Chapitre 21 : Space shooter - Les collisions (1)
- Big tuto XNA : Chapitre 22 : Space shooter - Générateur de particules
- Big tuto XNA : Chapitre 23 : Space shooter - Les collisions (3)
- Big tuto XNA : Chapitre 24 : Space shooter - Les collisions (4)
- Big tuto XNA : Chapitre 25 : Space shooter - Les collisions (5)
- Big tuto XNA : Chapitre 26 : Space shooter - Musique et sons 

 

Et voilà le résultat final auquel vous parviendrez à la fin de ce Tuto !

 

   @ bientôt ! wink

                Jay

 

 

Connexion

CoalaWeb Traffic

Today201
Yesterday282
This week995
This month3288
Total1742495

19/04/24