1. Introduction

Avant de commencer à programmer pour la XBox, il est important d'utiliser les bons outils. Voici les outils qui seront rapidement nécessaires :

Pour le dernier élément de la liste, son installation n'est pas obligatoire mais il permet d'utiliser certains outils dédiés pour DirectX comme nous le montrons plus loin dans cet article. Par contre, il n'y a pas de lien direct, vous allez donc devoir utiliser votre moteur de recherche préféré pour obtenir la dernière version.

Pour l'ordre d'installation, commencez par Visual C# Express et ensuite installez le module XNA.

Pour l'instant, une version française n'existe pas encore, donc les menus, et l'aide, seront en anglais. Il faut le prendre comme un exercice de langue en même temps que l'apprentissage de l'informatique !

Dernière remarque, pour toutes les installations, la suite de ce tutoriel suppose que vous avez effectué une installation complète des composants. En principe, cela installera donc aussi l'aide MSDN.

2. Premier lancement

Une fois que tout est installé correctement vous allez pouvoir lancé le lien XNA Game Studio Express qui se trouve dans le menu Démarrer. Celui-ci lance en fait Visual C# Express.

Image non disponible
Une première vue de XNA Game Studio utilisant Visual C#

Vous pouvez maintenant créer un nouveau projet et obtenir une fenêtre proposant Windows Game (XNA). Dans le nom du projet, vous pouvez mettre le titre du jeu ou comme le montre l'exemple, simplement Essai.

Image non disponible
La création du projet

Ceci ouvre une nouvelle fenêtre, dans lequel vous avez les composants à gauche (un seul composant graphique pour le moment) et à droite les fichiers liés au projet, à droite. Avant toute chose, il faut penser à sauvegarder le projet : allez dans le menu et choisissez l'option Save all (pensez à cliquer sur la création de répertoire pour le projet).

Image non disponible
La sauvegarde du projet

3. Le code

En cliquant sur la partie gauche de la fenêtre, vous allez avoir l'option View Code. Ceci vous permet de voir le code de base d'un programme XNA. Normalement vous devriez avoir ceci :

Image non disponible
Le code du premier projet

Pour faciliter la lecture et voir tout le code, voici une copie du code :

Le code de départ
Sélectionnez

using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Components;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Storage;

namespace Essai
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    partial class Game1 : Microsoft.Xna.Framework.Game
    {
        public Game1()
        {
            InitializeComponent();
        }

        protected override void Update()
        {
            // The time since Update was called last
            float elapsed = (float)ElapsedTime.TotalSeconds;

            // TODO: Add your game logic here

            // Let the GameComponents update
            UpdateComponents();
        }

        protected override void Draw()
        {
            // Make sure we have a valid device
            if (!graphics.EnsureDevice())
                return;

            graphics.GraphicsDevice.Clear(Color.CornflowerBlue);
            graphics.GraphicsDevice.BeginScene();

            // TODO: Add your drawing code here

            // Let the GameComponents draw
            DrawComponents();

            graphics.GraphicsDevice.EndScene();
            graphics.GraphicsDevice.Present();
        }
    }
}

Sans faire un cours sur les différentes parties de ce code, le début commence avec les traditionnelles inclusions nécessaires pour le programme. Ensuite vient la déclaration d'un espace de nom et enfin la classe pour le jeu.

Le constructeur initialise les composants pour le jeu. Et cette classe contient deux autres fonctions membres :

  • Update : fonction qui permet de mettre à jour les informations concernant le jeu, gérer la logique de jeu, l'intelligence artificielle, le réseau, le son, l'entrée utilisateur, les collisions entre les objets;
  • Draw : fonction qui permet de gérer le rendu du programme, c'est ici que vous mettrez ce qui doit être dessiner, comment et où.

Comme vous le voyez, la fonction Update commence par donner le temps écoulé depuis la dernière mise à jour. Cette information est très importante dans la programmation d'un jeu. Elle permet de calculer la distance que doit parcourir un objet, décider de l'image à dessiner pour l'animation d'un objet...

4. Création et ajout d'une balle

4.1. Création

Si vous compilez les codes (F6 pour compiler et Ctrl-F5 pour lancer le programme), vous devriez obtenir une fenêtre vide. Bien sûr, nous voulons faire plus ! Le premier endroit pour chercher des informations se trouve dans l'aide associée avec l'EDI. En appuyant sur F1, vous allez obtenir quelque chose de similaire à ceci :

Image non disponible
L'aide MSDN avec la partie XNA

Dans la partie de gauche vous avez une partie XNA, la suite (y compris le code) de ce tutoriel puise ses informations de cette aide très bien faite. Pour avoir plus de détails, je vous invite à étudier cette aide (bien qu'elle soit en anglais, c'est abordable). Je ne peux que vous encourager d'y faire un tour !

En suivant donc cette première aide de la MSDN, nous allons ajouter une texture de balle pour le jeu et la faire rebondir sur les bords de la fenêtre. Il va donc falloir commencer par créer l'image de balle.

En utilisant votre programme de dessin préféré, vous pouvez créer une image qui ressemblera à ceci :

Image non disponible
La balle

C'est une image blanche ! Bien sûr, nous voulons voir une balle, mais nous voulons que, lors du rendu, seul un rond apparaisse. Ceci se fait facilement en ajoutant un canal supplémentaire nommé Alpha. En effet, toute image possède des pixels de 3 couleurs (rouge, vert et bleu) et on ajoute généralement un dernier canal alpha pour la transparence. Puisque nous voulons que la balle soit opaque mais que le reste soit transparent, il suffira de dessiner un cercle noir sur fond noir :

Image non disponible
Le canal Alpha de l'image (le blanc représente la partie opaque et le noire la partie transparente)

En utilisant un outil de la SDK DirectX nommé Texture Tool, nous allons créer une texture DirectX. Cet outil possède une simple fenêtre et lorsque nous voulons créer une texture (option New Texture), nous obtenons cette sous-fenêtre :

Image non disponible
Création d'une texture DirectX

La seule chose à changer ici est la taille de l'image si vous souhaitez une image plus petite. Mais vous pouvez aussi le laisser tel quel en appuyant directement sur Ok.

Enfin, il vous suffit d'ajouter l'image de la balle en utilisant Open Onto this Surface, et en utilisant Open Onto Alpha Channel Of This Surface pour l'image du canal alpha.

Remarquons que Texture Tool redimensionne les images pour qu'elles soient entièrement dans la texture. Bien sûr, il vaut mieux avoir la même taille que les images créées précédemment mais cela n'est pas nécessaire.

Image non disponible
La texture est créée

Une fois terminée, nous pouvons sauvegarder la texture (l'extension du fichier sera .dds) dans le répertoire du projet, la suite de l'article supposera que le fichier de la texture est balle.dds.

4.2. Ajout

Pour ajouter un fichier image à un projet, il suffit de demander d'inclure un objet existant au projet, comme le montre l'image suivant :

Image non disponible
Ajout d'un objet

Cela permettra lors de la création du programme de copier le fichier de la balle en même temps que le programme. Pour dire à Visual C# Express de copier la texture lors de la compilation du projet, il faut aller dans les propriétés de la texture :

Image non disponible
Regardez les propriétés de la texture

Ceci ouvre une fenêtre dans laquelle on peut spécifier la copie du fichier lors de la compilation (mettre l'option à Copy always) :

Image non disponible
Fenêtre des propriétés de la texture

On termine donc la partie sur la création d'une texture et son ajout dans le projet. Nous allons maintenant modifier le code pour qu'il prenne en compte l'objet et qu'il le dessine à l'écran.

5. Retour sur le code

Remarque : encore une fois, le code présenté ici est une copie (à part pour les commentaires) du code trouvé dans l'aide MSDN. Je ne fais que le présenter d'une autre manière et en français !

5.1. Les nouveaux membres et fonctions

Pour terminer ce premier petit programme nous devons tout d'abord compléter la classe principale du programme. En effet, nous avons besoin d'un objet pour contenir la texture de la balle, deux champs pour sa position et un objet qui s'occupera du rendu de la balle.

Il faut donc ajouter dans la classe ceci :

Les nouveaux membres de la classe
Sélectionnez

	        //Ceci contient la texture de la balle
    	    Texture2D m_textureBalle;
    	    
	       	//Position de la balle
    	    int m_balleX = 0;
        	int m_balleY = 0;
	        //La vitesse de la balle
    	    int m_vx = 3;
	        int m_vy = 3;
	        
    	    //L'objet qui dessinera la balle
        	SpriteBatch m_spriteBatch;
			

La seule chose différente de ce qu'on a l'habitude de voir est l'objet de type SpriteBatch. Cette classe permet de gérer le rendu des objets de votre jeu. Sinon nous avons un objet pour contenir la texture de la balle et 4 entiers pour la position et la vitesse courante de la balle.

Nous devons maintenant charger la texture en mémoire et ceci peut se faire au démarrage du programme. Comme beaucoup d'API graphique, il est possible qu'à un moment de la vie du programme, il faille recharger cette texture (par exemple, lors d'un changement de résolution). Nous allons donc créer une fonction LoadRessources qui sera appelée lors de la création du programme et lorsque le composant graphique doit être réinitialisé. Ceci se fait en écrivant deux fonctions supplémentaires : OnStarting et GraphicsDevice_DeviceReset.

Les nouvelles fonctions
Sélectionnez

protected override void OnStarting()
        {
            base.OnStarting();
            graphics.GraphicsDevice.DeviceReset += new EventHandler(GraphicsDevice_DeviceReset);
            LoadResources();

        }

        void GraphicsDevice_DeviceReset(object sender, EventArgs e)
        {
            LoadResources();
        }

        void LoadResources()
        {
            myTexture = Texture2D.FromFile(graphics.GraphicsDevice, "balle.dds");
            spriteBatch = new SpriteBatch(graphics.GraphicsDevice);
        }

La fonction OnStarting démarre la base du programme et met en place la gestion d'une réinitialisation du composant graphique en demandant qu'on appelle la fonction GraphicsDevice_DeviceReset, puis la fonction LoadRessources

La fonction GraphicsDevice_DeviceReset demande simplement le chargement des ressources graphique. Enfin, la fonction LoadRessources charge la texture balle.dds. Ensuite on crée une instance de la classe SpriteBatch qui je le rappelle gérera le rendu de la balle.

La dernière nouvelle fonction est appelée BougeBalle. Elle permet de déplacer la balle et de vérifier si on sort de la fenêtre. Si c'est le cas, on la repositionne et on inverse sa direction. Son code ressemble donc à :

La fonction BougeBalle
Sélectionnez

        void BougeBalle()
        {
            //Bouger la balle par rapport a la vitesse
            m_balleX += m_vx;
            m_balleY += m_vy;

            int MaxX = Window.ClientWidth - m_textureBalle.Width;
            int MinX = 0;
            int MaxY = Window.ClientHeight - m_textureBalle.Height;
            int MinY = 0;

            //On regarde si on sort de la fenetre
            if (m_balleX > MaxX)
            {
                m_vx *= -1;
                m_balleX = MaxX;
            }
            else if (m_balleX < MinX)
            {
                m_vx *= -1;
                m_balleX = MinX;
            }

            if (m_balleY > MaxY)
            {
                m_vy *= -1;
                m_balleY = MaxY;
            }
            else if (m_balleY < MinY)
            {
                m_vy *= -1;
                m_balleY = MinY;
            }
         }

Si on regarde ce code attentivement, on remarque que l'objet Window permet d'avoir la taille de la fenêtre et l'objet m_textureBalle permet d'avoir les dimensions de l'objet. Avec la position et la vitesse de la balle, la fonction est donc capable de mettre à jour la position de l'objet et de vérifier si la balle sort de la fenêtre.

5.2. Modifications des autres fonctions

Cette petite partie présente les modifications de code pour gérer et afficher la balle dans la fenêtre. La fonction Update appelle la fonction BougeBalle pour mettre à jour la position de la balle.

La fonction Update
Sélectionnez

        protected override void Update()
        {
            // The time since Update was called last
            float elapsed = (float)ElapsedTime.TotalSeconds;

            //Bouger la balle
            BougeBalle();

            // Let the GameComponents update
            UpdateComponents();
        }

La fonction Draw a un peu plus de modification. Nous avons déjà dit que c'est l'objet m_spriteBatch qui gère l'affichage des objets. Comme pour le rendu de beaucoup d'API graphique, nous englobons le code de rendu par une fonction Begin et une fonction End.

La fonction Begin de la classe SpriteBatch prend le style de rendu que nous voulons faire. Dans le cas présent, nous voulons avoir un affichage qui tient en compte le canal Alpha de la texture. Ceci implique donc que nous allons passer SpriteBlendMode.AlphaBlend à la fonction Begin

Ensuite, pour dessiner la balle, nous utilisons la fonction Draw de l'objet m_spriteBatch en lui passant la texture à dessiner, un rectangle contenant la position de la balle, une taille et une couleur qui sera multiplié sur chaque pixel. En mettant Red, nous allons donc obtenir une image dont tous les pixels sont multiplié par une couleur rouge.

Le code de rendu
Sélectionnez

        protected override void Draw()
        {
            if (!graphics.EnsureDevice())
            {
                return;
            }

            graphics.GraphicsDevice.Clear(Color.CornflowerBlue);
            graphics.GraphicsDevice.BeginScene();

            //Dessiner la balle
            m_spriteBatch.Begin(SpriteBlendMode.AlphaBlend);
            m_spriteBatch.Draw(m_textureBalle, 
                    new Rectangle(m_balleX, m_balleY, m_textureBalle.Width, m_textureBalle.Height), 
                    Color.Red);
            m_spriteBatch.End();

            // Let the GameComponents draw
            DrawComponents();

            graphics.GraphicsDevice.EndScene();
            graphics.GraphicsDevice.Present();
        }

Enfin, voici une image du petit programme que nous venons de créer :

Image non disponible
Une image du premier petit programme XNA

6. Conclusion

Voilà, l'introduction de la programmation XNA est terminée ! Vous avez en principe tous les outils pour créer des jeux qui pourront être porté vers la XBox. Bien sûr, il faudra faire plus qu'une balle qui rebondit sur les bords de l'écran mais c'est un début.

L'aide MSDN est complète et présente de nombreux exemples pour savoir comment créer divers éléments d'un jeu !

Jc

Liens

7. Téléchargements

Voici le code source pour ce premier tutoriel: (10 Ko).

Voici la version pdf de cet article: (494 Ko).

Enfin, sur la page http://jeux.developpez.tv/tutoriel/xna, vous pourrez trouver une video montrant le déroulement de cet article et qui constitue une présentation visuelle de Visual C#/XNA et de l'aide MSDN.

Si vous avez des suggestions, remarques, critiques, si vous avez remarqué une erreur, ou bien si vous souhaitez des informations complémentaires, n'hésitez pas à me contacter !

8. Remerciements

Je remercie matrix788 pour sa relecture et ses remarques.