Retourner au sommaire des cours
Nous arrivons maintenant à la seconde étape de notre apprentissage de la programmation de jeu avec le Framework XNA. Nous avons vu précédemment comment configurer notre système et nous avons testé un premier programme "clé en main".
Il est désormais temps de passer aux choses concrêtes... de manière humble toutefois. Pour ce second tutorial, nous allons créer maintenant un premier projet, tenter de comprendre son fonctionnement et le modifier.
Création d'un projet
Ouvrez Visual Studio. Dans le menu "Fichier" selectionnez "Nouveau Projet". Une fenêtre s'ouvre alors vous donnant la possibilité de choisir le type de projet à créer et de spécifier un nom (entre autres).
Dans le type de projet "Xna Game Studio", choisissez Windows Game et donnez pour nom "PremierProjet".

Visual Studio créé alors un projet qui contient deux fichiers cs.

Avant de modifier le contenu de ces fichiers, il convient de comprendre leur contenu.
Etude du projet
Nous n'étudierons pas le fichier Program.cs qui est simplement un "startup file" qui va créer un objet de type Game1 et appeller sa méthode Run().
Le répertoire "Content" est destiné à recevoir toutes les assets (ressources graphiques, sonores, 3D, etc) de votre jeu. Nous n'en sommes pas encore là. Cette partie sera étudiée plus tard. Vous pouvez toujours vous reporter à l'article portant sur le Content Pipeline et la gestion des assets ici.
Game.ico et GameThumnail.png sont tout simplement deux ressources graphiques utilisées pour représenter le jeu sous Windows (icone de la fenêtre et de l'application dans la barre des tâches).
Le fichier Game1.cs contient la classe principale du jeu. Celle-ci se compose de 6 méthodes pour l'instant vides mais qui ne demandent qu'à êtres implémentées. Elle contient en outre deux membres sur lesquels nous reviendrons.
Le constructeur se contente d'initialiser deux de ses membres :
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}
GraphicsDeviceManager est une classe qui donne accès aux fonctionnalités de la carte graphique. La seconde instruction spécifie où se trouve les assets dans le projet. Par défaut ceux-ci se trouvent dans le répertoire nommé Content. D'une manière générale on évitera de placer ici le code d'initialisation. On utilisera plutot la méthode Initialize :
/// <summary>
/// Allows the game to perform any initialization it needs to before starting to run.
/// This is where it can query for any required services and load any non-graphic
/// related content. Calling base.Initialize will enumerate through any components
/// and initialize them as well.
/// </summary>
protected override void Initialize()
{
// TODO: Add your initialization logic here
base.Initialize();
}
C'est ici que le développeur initialisera toutes les données de son jeu. Initialize est appellée juste après la méthode Load.
Vient ensuite deux méthodes qui vont gérer le chargement et le déchargement des assets du jeu (son, images, objets 3D, fonts ...).
/// <summary>
/// LoadContent will be called once per game and is the place to load
/// all of your content.
/// </summary>
protected override void LoadContent()
{
// Create a new SpriteBatch, which can be used to draw textures.
spriteBatch = new SpriteBatch(GraphicsDevice);
// TODO: use this.Content to load your game content here
}
/// <summary>
/// UnloadContent will be called once per game and is the place to unload
/// all content.
/// </summary>
protected override void UnloadContent()
{
// TODO: Unload any non ContentManager content here
}
Nous reviendrons dans un prochain tutorial sur l'utilité du paramètre booléen qu'elles prennent en entrée.
Les deux dernières méthodes gèrent la vie du jeu.
/// <summary>
/// Allows the game to run logic such as updating the world,
/// checking for collisions, gathering input, and playing audio.
/// </summary>
/// <param name="gameTime">Provides a snapshot of timing values.</param>
protected override void Update(GameTime gameTime)
{
// Allows the game to exit
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
// TODO: Add your update logic here
base.Update(gameTime);
}
/// <summary>
/// This is called when the game should draw itself.
/// </summary>
/// <param name="gameTime">Provides a snapshot of timing values.</param>
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
// TODO: Add your drawing code here
base.Draw(gameTime);
}
Update s'occupe de mettre à jour toutes les données du jeu et n'effectue aucun traitement d'affichage. Elle reçoit en entrée un objet de type GameTime. Cette classe permet de synchroniser les affichages dans le jeu. Elle contient un ensemble d'informations temporelles comme le temps passé depuis l'affichage de la dernière frame (écran de jeu), le temps passé depuis le début du jeu, etc. Grâce à cela, le développeur peut créer un jeu dont la "vitesse" sera indépendante de la plateforme sur laquelle tourne le jeu. On evite ainsi un jeu qui tourne au ralenti sur les vieille machine et en "acceléré" sur les machines surpuissantes. Problème souvent rencontré lorsqu'on execute de vieux jeux sur son pc.
Update vérifie ici, si l'utilisateur a pressé la touche Back du GamePad 1 auquel cas elle arrête l'application.
Draw s'occupe exclusivement de l'affichage des données. On évitera de placer dans cette méthode des traitements autres que ceux demandés pour rendre une scène à l'écran. Pour l'heure, Draw efface le contenu de la fenêtre à l'aide d'une couleur bleue.
En outre il est important de noter que chacune de ces deux méthodes appelle leur jumelle parente via le mot clé base. Ceci est important pour permettre à la classe mère Microsoft.Xna.Framework.Game d'effectuer ses traitements internes.
Revenons pour finir sur les deux membre de la classe Game1.
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
GraphicsDeviceManager est une classe qui encapsule le device graphique (la carte graphique) afin de pouvoir communiquer avec elle et lui envoyer des instructions. Le développeur est donc libéré de cette tâche fastidieuse. Elle possède un membre nommé Device qui correspond au Device de DirectX. Un device peut être vu comme un lien directe vers les fonctionnlités d'un matériel (ici la carte graphique). C'est la méthode Clear de cet objet qui est appellée pour effacer le contenu de la fenêtre. SpriteBatch est une classe qui est utilisé pour l'affichage de texture en 2D à l'écran. Pratique pour les jeux 2D ou pour l'affichage d'interface utilisateurs en deux dimensions dans un jeu 3D.
Modification du code source
Maintenant que le code source est compris, nous pouvons le modifier. Faisons simple au départ. Nous spécifierons une taille de 800 par 600 pour la fenêtre de jeu, indiquerons qu'elle est redimentionnable et que le jeu ne tourne pas en plein écran. Nous donnerons enfin un titre à cette dernière. Modifiez la méthode Initialize de cette manière :
protected override void Initialize()
{
// TODO: Add your initialization logic here
this.graphics.IsFullScreen = false;
this.graphics.PreferredBackBufferWidth = 800;
this.graphics.PreferredBackBufferHeight = 600;
this.graphics.ApplyChanges();
this.Window.Title = "Notre premier programme !";
this.Window.AllowUserResizing = true;
base.Initialize();
}
Rien de compliqué en sommes. Notons juste que la classe possède un membre nommé Window qui correspond à la fenêtre de jeu. La méthode ApplyChanges permet de valider les modifications appliquées à l'objet graphics.
Si vous lancez l'application vous obtenez :

C'est déjà un bon début !
Conclusion
Nous avons vu simple pour un premier cours mais c'était important. Nous sommes en train d'aborder les notions fondamentales du développement XNA, il est important de les comprendre de manière claire, car c'est sur elles que repose le bon fonctionnement de nos applications.
Nous verrons dans le prochain article les effects et l'affichage d'une première forme.
Vous pouvez télécharger le sample ici.
A bientôt sur ce Blog !
Valentin Billotte
Retourner au sommaire des cours