Création d'une classe Sprite
XNA propose un tas de classes et de structures pour nous faciliter la vie dans le développement mais il y a quand même un gros manque : Une classe Sprite. Au fait qu’est ce qu’un Sprite ? C’est une image qui est affichée à l’écran et qui a des propriétés telles qu’une position, une texture, etc.. La classe que nous allons créer va donc reprendre du code que nous avons été obligé d’écrire plusieurs fois dans les 2 premiers tutoriels. Nous avons déclaré 2 structures Vector2 pour gérer la position du laser ET du vaisseau par exemple alors qu’il serait préférable d’avoir une classe qui contient déjà toutes ces informations (vitesse, position, disponible, etc…)
Structure
public class Sprite { // Référence vers la classe du jeu private Game e_game; protected Vector2 _position; protected Texture2D _texture; protected Vector2 _speed; protected bool _active; // Position à l'écran du Sprite public Vector2 Position { get { return _position; } set { _position = value; } } // Texture du Sprite public Texture2D Texture { get { return _texture; } set { _texture = value; } } // Vitesse public Vector2 Speed { get { return _speed; } set { _speed = value; } } // Largeur de l'image public int Width { get { return _texture.Width; } } // Hauteur de l'image public int Height { get { return _texture.Height; } } // Définie si le sprite est actif public bool Active { get { return _active; } set { _active = value; } } // Objet Game public Game Game { get { return e_game; } } // ContentManager pour charger les ressources public ContentManager Content { get { return e_game.Content; } } #region Constructeurs public Sprite (Game game) { } public Sprite (Game game, Vector2 position) : this(game) { } #endregion // --- Schéma classique du pattern GameState public virtual void Initialize() { } public virtual void LoadContent(string textureName) { } public virtual void UnloadContent() { } public virtual void Update(GameTime gameTime) { } public virtual void Draw(SpriteBatch spriteBatch) { } } |
Ce schéma est bien classique est il ressemble comme 2 goûtes d’eau à la classe Game. En fait on peut le voir comme un calque que l’on va déposer sur la classe Game, à chaque instance de cette classe il y aura un élément graphique qui sera affiché.
Cette classe va principalement nous permettre de :
Nous allons commencer les explications par la fin pour une fois et débuter avec la méthode Draw().
Cette classe va principalement nous permettre de :
- positionner un objet
- lui attribuer une vitesse sur les axes X et Y
- activer son affichage ou le désactiver
Nous allons commencer les explications par la fin pour une fois et débuter avec la méthode Draw().
La méthode Draw
public virtual void Draw(SpriteBatch spriteBatch) { if (_active) spriteBatch.Draw (_texture, _position, Color.White); } |
Si la variable _active vaut true alors on affiche le Sprite, cela nous permet de gérer la visibilité des éléments graphiques qui compose le jeu.
La méthode Update
public virtual void Update(GameTime gameTime) { } |
Elle reste vide car nous n’avons de base aucun traitement à faire dans cette méthode. Lorsque nous créerons des types plus spécialisés on surchargera cette méthode.
Les méthodes UnloadContent et LoadContent
UnloadContent
public virtual void UnloadContent() { if (_texture != null) _texture.Dispose(); } |
On fait juste un test pour savoir si la texture est bien initialisée et si c’est le cas la méthode Dispose() est appelée pour libérer la ressource de la mémoire.
LoadContent
LoadContent
public virtual void LoadContent(string textureName) { _texture = Content.Load(textureName); } |
La texture est chargée avec le nom passé en paramètre à cette méthode. A partir de là les propriétés this.Width et this.Height vont renvoyer les dimensions de la texture.
La méthode Initialize
public virtual void Initialize() { _active = true; } |
Même si cela peut paraître redondant (et ça l’est) car on initialise déjà la variable _active à la valeur true dans le constructeur, cela est une bonne idée car la méthode Initialize() est faite pour réinitialiser un objet sans pour autant en créer une nouvelle instance.
Les constructeurs
public Sprite (Game game) { e_game = game; _position = Vector2.Zero; _speed = Vector2.One; _active = true; } public Sprite (Game game, Vector2 position) : this(game) { _position = position; } |
J’ai choisis de créer 2 constructeurs mais au final nous en aurons bien plus. Dans tous les cas un Sprite devra prendre comme paramètre une instance de Game (ou dérivée) afin que nous puissions avoir accès au ContentManager et à d’autres propriétés. Le premier constructeur est chargé d’initialiser les variables de la classe. Le deuxième constructeur appelle le 1er (via l’utilisation de this()) et renseigne une position.
L’implémentation de cette nouvelle classe est terminée. Vous noterez que les méthodes sont toutes publiques car il faut que nous puissions les appeler en dehors de la classe, vous remarquerez aussi qu’elles sont virtuelles, nous pourrons ainsi les surcharger en dérivant cette classe. En effet nous aurons souvent besoin de l’héritage pour créer des Sprites spécialisés, par exemple créer un objet Hero, Enemy, Laser, Asteroid, etc…
L’implémentation de cette nouvelle classe est terminée. Vous noterez que les méthodes sont toutes publiques car il faut que nous puissions les appeler en dehors de la classe, vous remarquerez aussi qu’elles sont virtuelles, nous pourrons ainsi les surcharger en dérivant cette classe. En effet nous aurons souvent besoin de l’héritage pour créer des Sprites spécialisés, par exemple créer un objet Hero, Enemy, Laser, Asteroid, etc…