Présentation de la plateforme XNA

Nicolas Boonaert

XNA est la plateforme de Microsoft qui permet de développer des jeux vidéo en code managé qui pourront être exécutés sous Windows ou sur une console Xbox 360. Elle propose de nombreuses fonctionnalités qui seront abordées à travers cet article.

- Titre : Présentation de la plateforme XNA

- Auteur : Nicolas Boonaert

- Parution : 24 août 2007

- Mise à jour : 26 février 2020

- Licence : Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright ® 2007 Nicolas Boonaert. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- I. Présentation de la plateforme XNA

- I-A. Qu'est-ce que XNA ?

- I-B. Pourquoi XNA ?

- I-B-1. Vers un développement multiplateforme

- I-B-2. Simplifier le développement des jeux vidéo

- II. Description précise de l'architecture

- II-A. Description précise des différents niveaux de l'architecture

- II-A-1. La plateforme d'exécution

- II-A-2. La plateforme .Net

- II-A-3. Le Framework XNA

- II-A-3-a. La plateforme bas niveau

- II-A-3-b. Le cœur du Framework

- II-A-3-c. Le Framework étendu

- II-A-3-d. La couche jeux

- II-A-4. Game Studio Express

- III. Description technique

- III-A. Le Framework étendu

- III-A-1. Le modèle applicatif

- III-B. Prérequis pour le développement avec XNA

- III-C. Création d'un projet de jeu développé avec XNA

- III-D. Le cœur du Framework

- III-D-1. Le namespace « Graphics »

- III-D-1-a. Description

- III-D-1-b. Exemple de code

- III-D-2. Le namespace « Audio »

- III-D-2-a. Description

- III-D-2-b. Exemple de code

- III-D-3. Le namespace « Input »

- III-D-3-a. Description

- III-D-3-b. Exemple de code

- III-D-4. Le namespace « Storage »

- III-D-4-a. Description

- III-D-5. Le namespace « math »

- III-D-5-a. Description

- IV. Conclusion

- V. Références et liens utiles

- V-A. Sources de l'article

- V-B. Liens Internet

- V-B-1. Sites officiels

- V-B-2. Blogs techniques

- V-B-3. Sites de ressources

- V-C. Presse et livres

- V-C-1. Magazine

- V-C-2. Bibliographie

I - Présentation de la plateforme XNA

I-A - Qu'est-ce que XNA ?

XNA est un Framework constitué de plusieurs bibliothèques .Net et qui permet à des développeurs de tout horizon de développer des jeux qui pourront s'exécuter sur différentes plateformes telles que les multiples systèmes Windows, mais aussi sur la console de Microsoft à savoir la XBOX 360.

I-B - Pourquoi XNA ?

I-B-1 - Vers un développement multiplateforme

L'intention de Microsoft sur ce point est claire, l'idée de XNA est de fournir un Framework commun tant au développeur pour Windows que pour plateforme XBOX 360.

C'est dans cette logique que Microsoft a réalisé un ensemble de classes disponibles qui sont communes à ces deux plateformes, de cette manière il est possible de porter un jeu développé pour Windows via XNA, directement sur XBOX 360 sans changer le code ou très peu et même de partager le code d'une plateforme à l'autre.

I-B-2 - Simplifier le développement des jeux vidéo

Le développement de jeux vidéo nécessite des connaissances avancées en développement, ou du moins une maîtrise du langage de développement.

XNA permet de simplifier le développement et de le rendre plus facilement accessible aux personnes qui viennent de débuter.

Là où dans un contexte plus complexe d'utilisation de DirectX ou d'autres API 3d, on passe plusieurs minutes à initialiser le projet, les classes et dépendances diverses, XNA propose de réduire toutes ces tâches toujours dans l'optique de simplification. Ainsi l'établissement de votre projet qui servira de base au jeu vidéo ne prendra que quelques minutes.

Toutes les étapes nécessaires à la création d'une application utilisant DirectX sont automatiquement traitées par le Framework XNA et les outils associés ce qui permet de directement se concentrer sur l'essentiel : le code du jeu.

La simplification peut encore être plus prononcée en utilisant des projets de base appelés « Starter Kit » ce qui permet d'obtenir dans l'assistant de création de projets de Visual Studio, un template de projet de jeu vidéo XNA qui contient une première architecture qui pourra être utilisée pour le jeu vidéo.

Ces kits sont généralement fournis avec une documentation complète et un ensemble de tutoriels qui guident les développeurs en modifiant et en ajoutant de nouvelles fonctionnalités au jeu de base.

II - Description précise de l'architecture

Maintenant que les intentions de Microsoft concernant XNA ont été présentées, il faut s'intéresser à l'architecture de cette plateforme.

II-A - Description précise des différents niveaux de l'architecture

Pour présenter ce schéma, nous allons procéder de la manière la plus simple, à savoir, nous allons commencer de la partie inférieure pour remonter vers les couches de plus haut niveau.

II-A-1 - La plateforme d'exécution

Il s'agit ni plus ni moins du système d'exploitation qui va exécuter notre application, on peut ainsi y retrouver dans notre cas, Windows Vista ou Windows XP, mais également, et parce que c'est le but de XNA, la plateforme exécutive de la Xbox 360.

II-A-2 - La plateforme .Net

Chacune de ces plateformes d'exécution possède son Framework .Net associé. Dans le cas d'un système Windows, le Framework .Net est complet, il ne diffère que dans sa version selon les systèmes.

Pour la Xbox 360, il faut savoir que le Framework .Net utilisé est un dérivé de la version Compact du Framework .Net 2.0.

II-A-3 - Le Framework XNA

II-A-3-a - La plateforme bas niveau

Il s'agit de l'ensemble des composants de bas niveau permettant par exemple, d'accéder aux ressources de la machine comme la carte vidéo (Direct 3D), la carte son (XACT), mais aussi les différentes entrées.

II-A-3-b - Le cœur du Framework

Noyau central du Framework XNA, cette partie importante est celle qui contient les classes .Net du Framework qui permettent de réaliser les opérations souhaitées, ce sont généralement ces classes qui sont utilisées par le développeur.

Nous y reviendrons plus en détail dans la suite du document.

II-A-3-c - Le Framework étendu

L'objectif principal de cette couche du Framework XNA est véritablement de rendre le développement de jeux vidéo plus aisé. Dans la version actuelle, ce Framework étendu est composé de deux sous-éléments : le modèle applicatif et le content pipeline. Cette partie du Framework devrait être encore étendue dans les prochaines versions de XNA toujours dans l'optique de simplifier le développement.

II-A-3-d - La couche jeux

Cette couche est celle de plus haut niveau, elle correspond au code de votre jeu et à son contenu. C'est également dans cette couche qu'on retrouve les éléments tels que les modèles, les composants de jeux ainsi que les starter-kits.

II-A-4 - Game Studio Express

Cette partie de l'architecture de XNA correspond à l'outil permettant d'utiliser et de développer avec le Framework XNA. Cet IDE basé sur Visual C# Express se voit pourvu de type de projet dédié à XNA, et est enrichi au besoin, de différents starter-kits qui peuvent être utiles pour débuter.

III - Description technique

À travers cette partie, nous allons véritablement entrer dans la description des différents éléments des couches présentées dans la partie de description de l'architecture. Pour cela nous allons partir de la couche de plus haut niveau (couche jeu) pour terminer par les couches de plus bas niveau du Framework XNA.

III-A - Le Framework étendu

III-A-1 - Le modèle applicatif

L'intention de ce modèle applicatif présent dans cette partie du Framework XNA est de faire abstraction de tous traitements habituels des jeux vidéo, à savoir le suivi de son cycle de vie.

Avec XNA, pas besoin de s'occuper de créer la fenêtre, de gérer les messages, de créer les différents timers et horloge d'exécution, la seule chose sur laquelle le développeur se concentre, c'est le code de son jeu.

Les jeux vidéo en général respectent un schéma de base simple dans leur exécution :

Après avoir été initialisé, le cœur du jeu s'exécute en boucle (la boucle de jeu) en effectuant les opérations suivantes.

Mise à jour du modèle : prise en compte des actions du jeu, d’actions utilisateur, du moteur physique, etc.

Affichage du modèle à l'écran

Dans certains cas, cette boucle peut se voir ajouter une troisième étape qui correspond à une étape de posttraitement pour des effets après rendu.

Ce fonctionnement logique du jeu vidéo doit en général être traité par le développeur, grâce à XNA, toute cette architecture logicielle est prise en charge.

Lors de la création d'un jeu vidéo à travers l'IDE dédié, on remarque que la génération du code respecte un schéma particulier et base le projet sur un squelette de base. Une classe principale, dérivée de la classe Game permet d'utiliser de nombreux éléments conteneurs et autres services, mais propose également cinq méthodes qui décrivent le cycle de vie du jeu et qui sont très utiles dans la simplification du développement :

Initialize

Exemple de code issu du code de projet nouvellement créé

protected override void Initialize()
{
// TODO: Add your initialization logic here

base.Initialize();
}

Cette méthode permet de créer les composants non graphiques, d'initialiser les paramètres du jeu, de créer les différentes instances nécessaires et de récupérer des informations sur la plateforme d'exécution.

LoadGraphicsContent

Exemple de code issu du code de projet nouvellement créé

protected override void LoadGraphicsContent(bool loadAllContent)
{
if (loadAllContent)
{
// TODO: Load any ResourceManagementMode.Automatic content
}

// TODO: Load any ResourceManagementMode.Manual content
}

Cette méthode est appelée automatiquement à travers la méthode Initialize(). C'est à travers cette dernière que l'on charge les éléments et ressources nécessaires au jeu, par exemple les modèles 3d, les textures et autres éléments utiles.

UnloadGraphicsContent

Exemple de code issu du code de projet nouvellement créé

protected override void UnloadGraphicsContent(bool unloadAllContent)
{
if (unloadAllContent)
{
// TODO: Unload any ResourceManagementMode.Automatic content
content.Unload();
}

// TODO: Unload any ResourceManagementMode.Manual content
}

C'est à travers cette méthode que nous procédons à la libération des ressources, on décharge ainsi les éléments de la mémoire, on « dispose » les différents éléments graphiques utilisés.

Update

Exemple de code issu du code de projet nouvellement créé

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);
}

Cette méthode correspond à l'étape de mise à jour du modèle, de prise en compte des actions du jeu. C'est clairement une méthode présente dans la boucle de jeu qui prend en compte les actions et entrées de l'utilisateur, du moteur physique, etc.

Draw

Exemple de code issu du code de projet nouvellement créé

protected override void Draw(GameTime gameTime)
{
graphics.GraphicsDevice.Clear(Color.CornflowerBlue);

// TODO: Add your drawing code here

base.Draw(gameTime);
}

Cette méthode correspond à l'étape d'affichage du modèle, il s'agit réellement de celle qui effectue le rendu à l'écran à travers le GraphicsDevice géré par XNA.

Plus de détails sur la boucle de jeu : la boucle de jeu peut être gérée par le développeur pour correspondre à un besoin précis. L'appel successif des méthodes Update() et Draw() peut alors être modifié par le développeur.

Variable step game

Cette première possibilité de gestion de la boucle de jeu présente le fonctionnement suivant : lorsque la frame précédente est affichée à l'écran, l'appel de la méthode Update() est directement réalisé. On attend ainsi l'affichage complet pour appeler la méthode de mise à jour du modèle.

Fixed step game

Cette seconde possibilité impose un intervalle fixe entre les appels de la méthode Update.

Cette seconde possibilité peut s'avérer plus utile et plus simple d'utilisation, car on peut alors effectuer des traitements à intervalles réguliers tels que des déplacements linéaires.

Dans les deux cas, l'animation linéaire d'un objet ou l'évolution linéaire d'un élément peut être assurée, car si dans le cas d'une utilisation d'intervalle régulier il est aisé de traiter cette évolution, dans le cas d'une utilisation d'un intervalle variable on peut utiliser le temps du jeu passé en paramètre de la méthode Update().

Le content pipeline

Les contenus multimédias graphiques et sonores occupent une place plus qu'importante dans les jeux actuels et l'incorporation de ces éléments dans le projet n'est pas chose aisée. La plupart du temps, l'accent est mis sur la recherche de l'exporter approprié, de l'outil nécessaire pour effectuer une tâche particulière. Dans un environnement de travail en équipe, plusieurs personnes travaillent en ce sens pour réussir à inclure ces éléments dans le projet et cela nécessite des moyens importants et réduit la flexibilité de travail.

Le content pipeline faisant partie du Framework XNA propose une approche différente et améliorée.

Il ne vous propose pas les outils de création de contenu (récemment l'apparition de l'outil de Softimage XSI Mod Tools gratuit et dédié à la création pour le jeu), mais cependant, une fois de plus, il facilite les actions du développeur en prenant en charge les étapes nécessaires à l'exploitation du contenu.

Il se veut également ouvert et personnalisable pour combler au mieux le besoin et enfin il vous laisse le choix des outils de création de contenu que ce soit au niveau des graphismes 2D, 3D ou sonore.

Pour comprendre comment fonctionne cette partie importante du Framework, il peut être utile de comprendre comment il fonctionne à plus bas niveau et de découvrir les différentes parties de celui-ci.

Les importers

Lorsque vous ajoutez du contenu à votre jeu vidéo pour la première fois, vous avez besoin de choisir un importer (même si ce choix peut être assisté). Cet importer est responsable de récupérer les données, de les traiter et de les normaliser pour la suite du traitement, il vérifie également leur cohérence. Il n'est donc plus nécessaire de s'occuper de l'importation et des soucis liés, l'importer s'occupe de tout à condition d'être rigoureux dans la création de contenu (fichiers respectueux du format).

Il existe de nombreux importers parmi ceux-ci bien sûr nombre d'importers habituels, mais également quelques-uns très intéressants tels que ceux liés au format Autodesk FBX. Ce format présente la possibilité de sauvegarder des scènes 3D complètes à travers la plupart des outils de création graphiques tant open source que commerciaux, s'avérant ainsi une bonne solution en attendant un réel standard dans les formats de fichier 3D.

Les différents formats de fichiers et types de fichiers supportés sont les suivants, les exporteurs de fichiers dans ce format sont nombreux :

Les fichiers audio de format XAP sont issus de l'outil XACT (Microsoft Cross-Platform Audio Creation Tool) qui sait traiter les fichiers sonores dans des formats standards.

Le content DOM

Une fois que les importers ont réalisé leur tâche d'importation, les données sont présentes dans le content DOM. Le terme DOM est ici simplement utilisé pour représenter une collection de classes et de schémas (de la même manière qu'un fichier XML).

Les données présentes dans le content DOM sont des données fortement typées ce qui signifie qu'elles sont stockées sous un format bien connu par exemple, une collection de sommets ou des données de textures auront le même format dans ce content DOM.

Ce point est important pour la suite du traitement de ces données, ce résultat peut d'ailleurs être inscrit sur le disque au format XML pour le débogage uniquement, il permet un traitement homogène dans les autres étapes d'exploitation des contenus.

Les processors

Un processor est chargé de récupérer les données présentes dans le content DOM et de créer un objet qui pourra être utilisé en exécution. Cet objet peut alors être simple comme un processor model (sur lequel nous reviendrons juste en dessous) ou complexe en combinant plusieurs de ces processors.

Par défaut, le Framework XNA propose plusieurs processors de base tels :

le processor model : utile pour les objets simples avec textures ;

le processor Texture2D : utile pour les sprites ou pour combiner avec les models ;

le processor Effect : utile pour manipuler les matériaux des models ;

il en existe bien d'autres…

La plupart du temps donc, ces processors sont utilisés en combinaison et sont très utiles pour effectuer des tâches importantes de traitement des données en plus du fait qu'ils sont très permissifs et facilement personnalisables pour exploiter n'importe quel contenu, car en utilisant le content DOM qui normalise les données, ces processors peuvent traiter tout type de fichiers de contenu.

Il est possible depuis ces processors et le content DOM, d'effectuer des opérations d'optimisation qui peuvent améliorer le rendement de votre jeu vidéo.

Le content building

Cette partie du content pipeline est également importante et il est géré par le coordinateur de construction du projet. Ainsi lorsque le projet est compilé, le contenu est construit et enregistré sur le disque de la même façon que votre code.

Le content manager

Le content manager est véritablement l'élément qui vous permet d'utiliser vos contenus dans votre jeu, il s'occupe de charger rapidement ces éléments en mémoire.

Son utilisation se veut très simple et voici un exemple de code qui vous permettra de récupérer un élément que vous avez ajouté à votre projet.

Exemple de code issu du code de projet nouvellement créé :

ContentManager contentManager = new ContentManager(Services);

Model model = contentManager.Load("element");

Il est donc très aisé d'utiliser du contenu à votre jeu vidéo en utilisant cette technologie qu'est le content pipeline intégré à XNA et ceci devrait encore s'améliorer au fil des versions.

Voici un schéma qui résume le fonctionnement global du content pipeline :

Pour aller plus loin avec cette pièce importante du Framework XNA, vous pouvez consulter le Livre Blanc rédigé par Valentin Billotte - MVP C#/DirectX technologies. Cet article est très complet et bien plus juste que cette introduction du content pipeline.

III-B - Prérequis pour le développement avec XNA

Visual C# Express Edition 2005 - http://msdn2.microsoft.com/en-us/express/aa700756.aspx

Il faut tout d'abord installer cet IDE gratuit de Microsoft. Seule cette version permet de développer officiellement avec XNA. Par la suite, le développement sera supporté sur toutes les éditions de Visual Studio, mais cela arrivera avec la sortie de XNA 2.0.

XNA Game Studio Express - http://msdn2.microsoft.com/en-us/xna/aa937795.aspx

Extension qui vient s'ajouter à C# Express Edition 2005, on peut alors retrouver des templates de projets correspondant à des jeux Windows ou Xbox, des bibliothèques, mais aussi les « starter kits ».

Service Pack 1 - C# Express Edition 2005 http://www.microsoft.com/downloads/details.aspx?familyid=7b0b0339-613a-46e6-ab4d-080d4d4a8c4e&displaylang=en

III-C - Création d'un projet de jeu développé avec XNA

Une fois ces éléments installés, il est possible de créer un projet XNA. Pour cela, à travers Visual C# Express Edition 2005, on crée un nouveau projet : File>New>Project…

Plusieurs modèles de projets s'offrent alors à nous :

Windows Game : jeu basé sur le Framework XNA destiné à être utilisé sous plateforme Windows (PC).

Xbox 360 Game : jeu destiné à être utilisé pour la console Xbox 360.

Windows Game Library : bibliothèque de jeu basé sur XNA destiné à être utilisé à travers un jeu Windows.

Xbox 360 Game Library : la même chose, mais pour la console Xbox 360.

Et enfin, des starters kits : par défaut en installant les éléments indiqués on peut utiliser le starter kit « Spacewar » proposant ainsi les modèles : Spacewar Windows Starter kit et Spacewar Xbox 360 Starter Kit.

Il est ensuite possible d'utiliser nos propres modèles ou d'autres « starter kits ».

Le choix d'un de ces modèles permet d'obtenir une première architecture de base pour le jeu ou la bibliothèque à développer.

Nommez directement votre projet et situez le répertoire au moment de la création pour vous éviter quelques éventuels soucis.

III-D - Le cœur du Framework

À travers cette partie, nous allons aborder les différents namespaces du cœur du Framework et les classes importantes qui les composent.

III-D-1 - Le namespace « Graphics »

III-D-1-a - Description

Ce namespace présente des classes et interfaces disponibles en code managé qui permettent la programmation graphique en s'appuyant sur les API issues de Direct3D 9.

À l'origine basée sur Managed DirectX (qui devrait d'ailleurs progressivement disparaître au profit de XNA), la partie graphique de XNA a été revue en profondeur pour offrir une solution plus simple et plus propre à utiliser en développement, ainsi les fonctions ne sont plus si proches du langage de bas niveau et une nouvelle fois, l'expérience du développeur est améliorée.

La principale amélioration de XNA sur le plan graphique, par rapport aux autres produits de versions précédentes est de favoriser le portage des jeux vidéo sur la plateforme Xbox 360 en imposant un pipeline basé totalement sur les shaders (les shaders sont des jeux d'instruction utilisés au moment du rendu).

Voici une série de méthodes pour réaliser diverses opérations graphiques.

III-D-1-b - Exemple de code

Affichage d'élément 2D

Afin d'afficher un élément 2D, on peut utiliser un objet de type SpriteBatch, ce dernier proposant la possibilité d'encadrer les opérations de tracés des textures 2D.

Après avoir déclaré dans la classe principale dérivée de Game mon objet de type SpriteBatch ainsi qu'un objet de type Texture2D qui correspond à la texture à afficher à partir d'un fichier, de cette façon :

SpriteBatch _spriteBatch;
Texture2D _texture2D;

On crée le batch en question dans la méthode d'initialisation (Initialize()) et on place en paramètre les périphériques graphiques gérés par XNA. On peut en profiter pour personnaliser notre fenêtre en modifiant les dimensions ou les titres.

_spriteBatch = new SpriteBatch(_graphics.GraphicsDevice);

//properties of the game window
_graphics.PreferredBackBufferWidth = 800;
_graphics.PreferredBackBufferHeight = 600;
_graphics.IsFullScreen = false;
_graphics.ApplyChanges();

Window.Title = "Microsoft XNA - Boonaert Nicolas";

On ajoute un fichier dans le content pipeline de la même manière que l'on ajoute un fichier au projet (dans le Solution Explorer>Clic droit>Add>Existing Item puis sélectionner content pipeline option puis sélectionner le fichier en question).

Il faut ensuite initialiser la texture2D que l'on va utiliser, ce qui est fait dans la méthode LoadGraphicsContent() :

_texture2D = content.Load<Texture2D>("textures/bill_gates_box");

Dans la méthode Draw() du la classe principale, on procède à l'affichage de l'élément :

_spriteBatch.Begin(SpriteBlendMode.AlphaBlend);
_spriteBatch.Draw(_texture2D,
new Rectangle(10, 10,565,210),
Color.White);
_spriteBatch.End();

Voici le résultat observé en exécution :

Voici le code de la classe principale résumant cette explication :

Game1.cs

#region Using Statements
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Storage;
#endregion

namespace WindowsGame
{
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager _graphics;
ContentManager content;

SpriteBatch _spriteBatch;
Texture2D _texture2D;

public Game1()
{
_graphics = new GraphicsDeviceManager(this);
content = new ContentManager(Services);
}

protected override void Initialize()
{
base.Initialize();

_spriteBatch = new SpriteBatch(_graphics.GraphicsDevice);

//properties of the game window
_graphics.PreferredBackBufferWidth = 800;
_graphics.PreferredBackBufferHeight = 600;
_graphics.IsFullScreen = false;
_graphics.ApplyChanges();

Window.Title = "Microsoft XNA - Boonaert Nicolas";
}

protected override void LoadGraphicsContent(bool loadAllContent)
{
if (loadAllContent)
{
_texture2D = content.Load<Texture2D>("textures/vs2008");
}
}

protected override void UnloadGraphicsContent(bool unloadAllContent)
{
if (unloadAllContent)
{
content.Unload();
}
}

protected override void Update(GameTime gameTime)
{
// Allows the game to exit
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();

base.Update(gameTime);
}

protected override void Draw(GameTime gameTime)
{
_graphics.GraphicsDevice.Clear(Color.CornflowerBlue);

_spriteBatch.Begin(SpriteBlendMode.AlphaBlend);
_spriteBatch.Draw(_texture2D,
new Rectangle(10, 10,565,210),
Color.White);
_spriteBatch.End();

base.Draw(gameTime);
}
}
}

Affichage d'élément 3D

Pour afficher un modèle 3D, la mise en œuvre est relativement proche de la précédente en 2D.

On ajoute la déclaration d'un objet de type Model à la classe principale :

Model _model;

On charge le modèle depuis le content pipeline après avoir ajouté le modèle et la texture associée.

_model = content.Load<Model>("models/p1_wedge");

Enfin dans la méthode Draw(), on récupère les sommets de l'objet 3D, on initialise les propriétés du modèle, puis la caméra et ses propriétés.

// Copy any parent transforms.
Matrix[] transforms = new Matrix[_model.Bones.Count];
_model.CopyAbsoluteBoneTransformsTo(transforms);

// Draw the model. A model can have multiple meshes, so loop.
foreach (ModelMesh mesh in _model.Meshes)
{
// This is where the mesh orientation is set, as well as our camera and projection.
foreach (BasicEffect effect in mesh.Effects)
{
effect.EnableDefaultLighting();
effect.World = transforms[mesh.ParentBone.Index]
* Matrix.CreateRotationX(modelRotation/10)
* Matrix.CreateRotationY(modelRotation)
* Matrix.CreateTranslation(modelPosition);
effect.View = Matrix.CreateLookAt(cameraPosition,
Vector3.Zero,
Vector3.Up);
effect.Projection = Matrix.CreatePerspectiveFieldOfView(
MathHelper.ToRadians(45.0f),
1.33f,
1.0f,
10000.0f);
}
// Draw the mesh, using the effects set above.
mesh.Draw();
}

Voici le résultat en exécution, on observe l'objet 3D en rotation sur ses axes x et y :

Ce modèle est issu du starter kit SpaceWar, de même que sa texture.

Voici alors le code de la classe principale :

Game1.cs

#region Using Statements
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Storage;
#endregion

namespace WindowsGame
{
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager _graphics;
ContentManager content;

SpriteBatch _spriteBatch;
Texture2D _texture2D;
Model _model;

public Game1()
{
_graphics = new GraphicsDeviceManager(this);
content = new ContentManager(Services);
}

protected override void Initialize()
{
base.Initialize();

_spriteBatch = new SpriteBatch(_graphics.GraphicsDevice);

//properties of the game window
_graphics.PreferredBackBufferWidth = 800;
_graphics.PreferredBackBufferHeight = 600;
_graphics.IsFullScreen = false;
_graphics.ApplyChanges();

Window.Title = "Microsoft XNA - Boonaert Nicolas";
}

protected override void LoadGraphicsContent(bool loadAllContent)
{
if (loadAllContent)
{
_texture2D = content.Load<Texture2D>("textures/bill_gates_box");
_model = content.Load<Model>("models/p1_wedge");
}
}

protected override void UnloadGraphicsContent(bool unloadAllContent)
{
if (unloadAllContent)
{
content.Unload();
}

}

protected override void Update(GameTime gameTime)
{
// Allows the game to exit
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();

modelRotation += (float)gameTime.ElapsedGameTime.TotalMilliseconds
* MathHelper.ToRadians( 0.1f );

base.Update(gameTime);
}

// Set the position of the model in world space, and set the rotation.
Vector3 modelPosition = Vector3.Zero;
float modelRotation = 0.0f;

// Set the position of the camera in world space, for our view matrix.
Vector3 cameraPosition = new Vector3(0.0f, 80.0f, 5000.0f);

protected override void Draw(GameTime gameTime)
{
_graphics.GraphicsDevice.Clear(Color.CornflowerBlue);

// Copy any parent transforms.
Matrix[] transforms = new Matrix[_model.Bones.Count];
_model.CopyAbsoluteBoneTransformsTo(transforms);

// Draw the model. A model can have multiple meshes, so loop.
foreach (ModelMesh mesh in _model.Meshes)
{
// This is where the mesh orientation is set
// as well as our camera and projection.
foreach (BasicEffect effect in mesh.Effects)
{
effect.EnableDefaultLighting();
effect.World = transforms[mesh.ParentBone.Index]
* Matrix.CreateRotationY(modelRotation)
* Matrix.CreateRotationX(modelRotation/10)
* Matrix.CreateTranslation(modelPosition);
effect.View = Matrix.CreateLookAt(cameraPosition,
Vector3.Zero,
Vector3.Up);
effect.Projection = Matrix.CreatePerspectiveFieldOfView(
MathHelper.ToRadians(45.0f),
1.33f,
1.0f,
10000.0f);
}
// Draw the mesh, using the effects set above.
mesh.Draw();
}
}
}
}

III-D-2 - Le namespace « Audio »

III-D-2-a - Description

Ce namespace propose un ensemble d'API qui repose sur XACT (Microsoft Cross-Platform Audio Creation Tool) et plus précisément sur les API qui le composent aussi bien pour Windows que pour Xbox 360.

Le principe est le même que pour le contenu graphique, on retrouve la même idée que les shaders de Direct3D. Les créateurs des sons utilisent l'outil XACT pour créer des ensembles (packages) de sons et configurent les propriétés telles que le volume, le canal (dans le cas du 5.1) à travers l'outil dédié.

Les développeurs n'ont alors qu'à importer ces ensembles (packages) de sons, les charger et peuvent ainsi jouer ces sons sans se préoccuper des pénibles étapes d'antan telles que l'initialisation des buffers de sortie ou d'autres opérations de gestion.

Pour exemple, le créateur d'un son d'explosion importe et monte en quelque sorte ses éléments sonores en paramétrant les propriétés, il package l'ensemble des sons wave le constituant ainsi que les informations liées, dans un package XAP généré depuis XACT. Le développeur importe ce package est n'a qu'à le jouer.

III-D-2-b - Exemple de code

Pour jouer un son, ici on utilise le fichier XAP issu du starter kit Spacewar.

Il suffit d'ajouter le fichier XAP à votre projet via le Solution Explorer, puis dans le dossier où est situé le fichier XAP dans votre projet, déposer le dossier des fichiers WAV associés.

On déclare les objets des composants nécessaires à l'exploitation de sons dans XNA.

//Audio API components
AudioEngine _audioEngine;
WaveBank _waveBank;
SoundBank _soundBank;

L'objet de type AudioEngine correspond au moteur de rendu sonore, il est utilisé en paramètre des autres objets.

L'objet de type WaveBand correspond à l'ensemble des sons ajoutés au projet par l'intermédiaire du fichier XAP.

Enfin l'objet de type SoundBank représente une collection de sons qu'on va pouvoir jouer dans notre jeu.

Dans la méthode Initialize(), on prend soin d'initialiser les objets utilisés comme suit :

//initialize audio components
_audioEngine = new AudioEngine(@"audio\SpaceWar.xgs");
_waveBank = new WaveBank(_audioEngine, @"audio\SpaceWar.xwb");
_soundBank = new SoundBank(_audioEngine, @"audio\SpaceWar.xsb");

Enfin dans cette même fonction, on peut choisir de jouer le son :

_soundBank.PlayCue("title_music");

Le nom du fichier à placer en paramètre est celui fixé lors de la création du fichier XAP dans le XACT, il peut être retrouvé en ouvrant le fichier XAP dans visual studio.

Le résultat en exécution est une fenêtre de base qui au lancement, joue la musique du jeu Spacewar que nous avons récupérée.

Voici le code de la classe principale permettant de réaliser ce traitement :

Game1.cs

#region Using Statements
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Storage;
#endregion

namespace WindowsGame
{
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager _graphics;
ContentManager content;

//Audio API components
AudioEngine _audioEngine;
WaveBank _waveBank;
SoundBank _soundBank;

public Game1()
{
_graphics = new GraphicsDeviceManager(this);
content = new ContentManager(Services);
}
protected override void Initialize()
{
base.Initialize();
//initialize audio components
_audioEngine = new AudioEngine(@"audio\SpaceWar.xgs");
_waveBank = new WaveBank(_audioEngine, @"audio\SpaceWar.xwb");
_soundBank = new SoundBank(_audioEngine, @"audio\SpaceWar.xsb");

_soundBank.PlayCue("title_music");

Window.Title = "Microsoft XNA - Boonaert Nicolas";
}

protected override void LoadGraphicsContent(bool loadAllContent)
{
}
protected override void UnloadGraphicsContent(bool unloadAllContent)
{
if (unloadAllContent)
{
content.Unload();
}
}
protected override void Update(GameTime gameTime)
{
// Allows the game to exit
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
_graphics.GraphicsDevice.Clear(Color.CornflowerBlue);
base.Draw(gameTime);
}
}
}

III-D-3 - Le namespace « Input »

III-D-3-a - Description

L'API de gestion des entrées de l'utilisateur (inputs) repose sur XInput qui est l'API multiplateforme qui permet d'exploiter la manette classique (manette de la Xbox 360), mais aussi le clavier et la souris.

Parmi ces trois types de périphériques d'entrées supportés, les possibilités du contrôleur de la Xbox 360 sont plus étendues, car il est possible d'aller plus loin dans les possibilités du jeu vidéo.

On y retrouve par exemple, la possibilité d'exploiter les sticks présents sur le contrôleur qui ne renvoient pas de valeurs booléennes comme un clavier, mais des valeurs flottantes, on peut aussi utiliser les vibrations du contrôleur tout cela pour renforcer la prise en main et l'immersion de l'utilisateur final.

Bien entendu l'idée de multiplateforme n'est jamais très loin et la possibilité de « mapper » directement les contrôles entre les périphériques sont d'ores et déjà présentes.

III-D-3-b - Exemple de code

Pour exploiter les périphériques d'entrées, on utilise une fonction UpdateInput() que l'on crée dans la classe principale pour alléger le code de la méthode Update(), cette méthode appellera à son tour trois autres fonctions respectivement pour la manette Xbox 360, le clavier et la souris :

UpdateInputGamePad()

protected void UpdateInputGamePad()
{
// Get the game pad state.
GamePadState currentState = GamePad.GetState(PlayerIndex.One);

if (currentState.IsConnected)
{
// Rotate the model using the left thumbstick, and scale it down.
modelRotationY -= currentState.ThumbSticks.Left.X * 0.10f;
modelRotationX -= currentState.ThumbSticks.Left.Y * 0.10f;

// Create some velocity if the right trigger is down.
Vector3 modelVelocityAdd = Vector3.Zero;

// Find out what direction we should be thrusting, using rotation.
modelVelocityAdd.X = -(float)Math.Sin(modelRotationY);
modelVelocityAdd.Z = -(float)Math.Cos(modelRotationY);

// Now scale our direction by how hard the trigger is down.
modelVelocityAdd *= currentState.Triggers.Right;

// Finally, add this vector to our velocity.
modelVelocity += modelVelocityAdd;

GamePad.SetVibration(PlayerIndex.One,
currentState.Triggers.Right,
currentState.Triggers.Right);

// In case you get lost, press A to warp back to the center.
if (currentState.Buttons.A == ButtonState.Pressed)
{
modelPosition = Vector3.Zero;
modelVelocity = Vector3.Zero;
modelRotationY = 0.0f;
modelRotationX = 0.0f;
}
}
}

Cette fonction met à jour des variables de la classe principale depuis des valeurs lues sur le périphérique d'entrée qui ici correspond au contrôleur de la Xbox 360 connecté au PC.

On remarque ainsi l'utilisation d'un objet de type GamePadState qui récupère l'état du contrôleur souhaité en utilisant la classe GamePad.

GamePadState currentState = GamePad.GetState(PlayerIndex.One);

Après avoir vérifié la connexion du contrôleur, on récupère la valeur sur le stick de gauche qui servira à effectuer la rotation du modèle 3D sur les axes X et Y :

modelRotationY -= currentState.ThumbSticks.Left.X * 0.10f;
modelRotationX -= currentState.ThumbSticks.Left.Y * 0.10f;

On remarque que les sticks principaux sont appelés Thumbsticks dans cette classe, on doit sélectionner celui qu'on souhaite sur le contrôleur (Droite ou Gauche).

Il existe plusieurs catégories d'éléments du contrôleur qui peuvent être lus via cet objet d'état tels que les thumbsticks, les triggers (gâchettes du dessus du contrôleur), les buttons (boutons du contrôleur).

Cette fonction UpdateInput initialise ensuite les variables permettant d'effectuer la rotation, enfin on peut remarquer une ligne de code intéressante ici :

GamePad.SetVibration(PlayerIndex.One,
currentState.Triggers.Right,
currentState.Triggers.Right);

Ici, on propose que la vibration du contrôleur s'effectue sur l'appui de la gâchette de droite, on peut changer cette valeur par une autre valeur flottante issue par exemple des sticks principaux.

Cette fonction SetVibration() prend en paramètres l'index du contrôleur sur lequel il faut appliquer l'effet, puis les deux valeurs flottantes qui suivent sont les valeurs de vibration des moteurs du contrôleur (moteur gauche et droit) allant de 0.0 à 1.0.

Cette méthode UpdateInputGamePad() est appelée au sein de la méthode UpdateInput(). Cette dernière appelle également deux autres méthodes :

UpdateInpuKeyboard()

protected void UpdateInputKeyboard()
{
if (Keyboard.GetState().IsKeyDown(Keys.Up))
{
modelRotationX += 0.2f * 0.10f;
}
if (Keyboard.GetState().IsKeyDown(Keys.Down))
{
modelRotationX -= 0.2f * 0.10f;
}
if (Keyboard.GetState().IsKeyDown(Keys.Left))
{
modelRotationY -= 0.2f * 0.10f;
}
if (Keyboard.GetState().IsKeyDown(Keys.Right))
{
modelRotationY += 0.2f * 0.10f;
}

if (Keyboard.GetState().IsKeyDown(Keys.Space))
isLocked = !isLocked;
}

Cette fonction permet d'obtenir l'état (pressée ou non) des touches directionnelles du clavier.

Keyboard.GetState().IsKeyDown(Keys.Up))

Ici on récupère l'état du clavier et on teste si la touche “Up” (flèche du haut) est appuyée.

On peut remarquer le traitement particulier pour la touche espace qui permet de verrouiller ou non la vue en activant ou non la prise en charge de la souris pour la rotation.

UpdateInputMouse()

protected void UpdateInputMouse()
{
MouseState mState = Mouse.GetState();
if (!isLocked)
{
modelRotationY -= (mState.X - 400) * 0.0002f;
modelRotationX -= (mState.Y - 300) * 0.0002f;
}
}

Cette fonction permet de récupérer la position de la souris par rapport au centre de la fenêtre et d'effectuer la rotation en fonction de la position X et Y de la souris par rapport au centre. On utilise une variable « isLocked » qui nous permet de verrouiller ou non la prise en charge de la souris sur l'appui de la touche espace du clavier.

Voici le code de la classe principale :

Game1.cs

#region Using Statements
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Storage;
#endregion

namespace WindowsGame
{
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager _graphics;
ContentManager content;

Model _model;

// Set the velocity of the model, applied each frame to the model's position.
Vector3 modelVelocity = Vector3.Zero;

// Set the position of the model in world space, and set the rotation.
Vector3 modelPosition = Vector3.Zero;
float modelRotationY = 0.0f;
float modelRotationX = 0.0f;

// Set the position of the Camera in world space, for our view matrix.
Vector3 cameraPosition = new Vector3(0.0f, 50.0f, -5000.0f);

//Game information
bool isLocked = true;  // vision locked (mouse inactive)

public Game1()
{
_graphics = new GraphicsDeviceManager(this);
content = new ContentManager(Services);
}

protected override void Initialize()
{
base.Initialize();

//properties of the game window
_graphics.PreferredBackBufferWidth = 800;
_graphics.PreferredBackBufferHeight = 600;
_graphics.IsFullScreen = false;
_graphics.ApplyChanges();

Window.Title = "Microsoft XNA - Boonaert Nicolas";
}

protected override void LoadGraphicsContent(bool loadAllContent)
{
if (loadAllContent)
{
_model = content.Load<Model>("models/p1_wedge");
}
}

protected override void UnloadGraphicsContent(bool unloadAllContent)
{
if (unloadAllContent)
{
content.Unload();
}
}

protected override void Update(GameTime gameTime)
{
// Allows the game to exit
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();

// Get some input.
UpdateInput();

// Add velocity to the current position.
modelPosition += modelVelocity;

// Bleed off velocity over time.
modelVelocity *= 0.95f;

base.Update(gameTime);
}

#region inputs

protected void UpdateInput()
{
UpdateInputGamePad();
UpdateInputKeyboard();
UpdateInputMouse();
}

protected void UpdateInputGamePad()
{
// Get the game pad state.
GamePadState currentState = GamePad.GetState(PlayerIndex.One);

if (currentState.IsConnected)
{
// Rotate the model using the left thumbstick, and scale it down.
modelRotationY -= currentState.ThumbSticks.Left.X * 0.10f;
modelRotationX -= currentState.ThumbSticks.Left.Y * 0.10f;

// Create some velocity if the right trigger is down.
Vector3 modelVelocityAdd = Vector3.Zero;

// Find out what direction we should be thrusting, using rotation.
modelVelocityAdd.X = -(float)Math.Sin(modelRotationY);
modelVelocityAdd.Z = -(float)Math.Cos(modelRotationY);

// Now scale our direction by how hard the trigger is down.
modelVelocityAdd *= currentState.Triggers.Right;

// Finally, add this vector to our velocity.
modelVelocity += modelVelocityAdd;

GamePad.SetVibration(PlayerIndex.One,
currentState.Triggers.Right,
currentState.Triggers.Right);

// In case you get lost, press A to warp back to the center.
if (currentState.Buttons.A == ButtonState.Pressed)
{
modelPosition = Vector3.Zero;
modelVelocity = Vector3.Zero;
modelRotationY = 0.0f;
modelRotationX = 0.0f;
}
}
}

protected void UpdateInputKeyboard()
{
if (Keyboard.GetState().IsKeyDown(Keys.Up))
{
modelRotationX += 0.2f * 0.10f;
}
if (Keyboard.GetState().IsKeyDown(Keys.Down))
{
modelRotationX -= 0.2f * 0.10f;
}
if (Keyboard.GetState().IsKeyDown(Keys.Left))
{
modelRotationY -= 0.2f * 0.10f;
}
if (Keyboard.GetState().IsKeyDown(Keys.Right))
{
modelRotationY += 0.2f * 0.10f;
}

if (Keyboard.GetState().IsKeyDown(Keys.Space))
isLocked = !isLocked;
}

protected void UpdateInputMouse()
{
MouseState mState = Mouse.GetState();
if (!isLocked)
{
modelRotationY -= (mState.X - 400) * 0.0002f;
modelRotationX -= (mState.Y - 300) * 0.0002f;
}
}

#endregion

protected override void Draw(GameTime gameTime)
{
_graphics.GraphicsDevice.Clear(Color.CornflowerBlue);

// Copy any parent transforms.
Matrix[] transforms = new Matrix[_model.Bones.Count];
_model.CopyAbsoluteBoneTransformsTo(transforms);

// Draw the model. A model can have multiple meshes, so loop.
foreach (ModelMesh mesh in _model.Meshes)
{
// This is where the mesh orientation is set
// as well as our camera and projection.
foreach (BasicEffect effect in mesh.Effects)
{
effect.EnableDefaultLighting();
effect.World = transforms[mesh.ParentBone.Index]
* Matrix.CreateRotationY(modelRotationY)
* Matrix.CreateRotationX(modelRotationX)
* Matrix.CreateTranslation(modelPosition);
effect.View = Matrix.CreateLookAt(
cameraPosition,
Vector3.Zero,
Vector3.Up);
effect.Projection = Matrix.CreatePerspectiveFieldOfView(
MathHelper.ToRadians(45.0f),
1.33f,
1.0f,
10000.0f);
}
// Draw the mesh, using the effects set above.
mesh.Draw();
}
base.Draw(gameTime);
}
}
}

III-D-4 - Le namespace « Storage »

III-D-4-a - Description

L'API de gestion du stockage permet au développeur de lire et écrire des données telles que la progression du joueur, les meilleurs scores, etc.

Le système de fichiers de la Xbox 360 étant très différent de celui d'un PC fonctionnant sous Windows, il était alors nécessaire d'avoir une API qui uniformalise ces opérations ce qui est chose faite à travers cette API.

Il est en effet possible d'effectuer des opérations de stockage sur les cartes mémoire ou le disque dur de la Xbox 360 en fonction du profil du joueur, tout comme sur le disque dur dans un système Windows.

On peut bien sûr, dans le cadre d'un jeu Windows, utiliser System.IO, mais cela n'est pas possible sur la Xbox 360 pour des raisons de sécurité, et est donc à éviter pour conserver la possibilité multiplateforme du jeu.

III-D-5 - Le namespace « math »

III-D-5-a - Description

L'API math propose des types souvent utiliser dans la programmation de jeu vidéo, ces types sont par exemple les Vector2, Vector3, Vector4, Matrix, Plan et Ray.

Tandis que les premiers types sont utilisés pour des calculs, les deux derniers correspondent à des types principalement utilisés dans les traitements physiques :

Plan : plan de collision déterminé par ses dimensions et son orientation décrite par son vecteur normal (perpendiculaire à la face) ;

Ray : vecteur dans l'espace, décrit par une direction, il permet de vérifier simplement s'il existe une collision avec un élément sur cette trajectoire.

On retrouve également les « bounding volumes » qui sont conteneurs utiles pour la détection de collision entre éléments du jeu vidéo, parmi ceux-ci figurent :

les « Bounding Boxes » : boites englobant les objets ;

les « Bounding Spheres » : sphères englobant les objets ;

les « Bounding Frustum » : la caméra détermine une limite englobante par l'espace imposé par son champ de vision, les objets entrent en collision avec les bords du champ de vision.

IV - Conclusion

Les possibilités de la plateforme XNA sont énormes et ouvrent la voie à des développements amateurs et à une démocratisation du développement de jeux vidéo multiplateformes.

Microsoft essaie de s'installer comme un carrefour du jeu vidéo PC et console en proposant la possibilité de partager ses créations via le Xbox Live et plus particulièrement le XNA Creators Club qui permet de diffuser ses créations sur ce réseau et qui sait, peut être de se faire un nom dans le domaine. Certaines limites sont imposées en termes de taille de jeu (en raison des supports de sauvegardes présents pour la console) et pour diffuser vos jeux sur la plateforme Live et exécuter votre jeu sur la Xbox 360, il est obligatoire d'avoir l'abonnement au XNA Creators Club (49 $ pour 4 mois, 99 $ pour un an d'abonnement) permettant au passage d'accéder à des ressources dédiées (livres blancs, tutoriels, ressources 2d et 3d…).

On peut voir que cette plateforme simplifie le développement de jeux vidéo avec un code managé et des fonctions dignes de ce langage ce qui permet de rendre encore plus accessible ce domaine parfois considéré comme trop complexe ou du moins d'un niveau avancé.

XNA n'en est qu'à ses débuts et suscite l'intérêt de beaucoup, un domaine très en vogue et qui est très plaisant d'étudier, alors peut-être que les prochains grands titres seront réalisés par un groupe d'amateurs passionnés et utilisant cette plateforme d'autant plus qu'une v2 a été annoncée au Gamefest07 organisé par Microsoft…

Nous ne manquerons pas de réaliser d'autres articles sur cette plateforme et comptons sur votre avis et votre participation.

V - Références et liens utiles

V-A - Sources de l'article

Les sources des miniprojets de cet article sont disponibles en téléchargement via ce lien.

V-B - Liens Internet

V-B-1 - Sites officiels

Voici la liste des sites officiels traitant de XNA

Site officiel de XNA

Page MSDN officielle sur XNA

Forum officiel Microsoft de développement de jeu vidéo

Blog officiel de l'équipe XNA

V-B-2 - Blogs techniques

Voici plusieurs blogs techniques

Blog technique de Benjamin Nitschke - Auteur du starter kit racing

Blog technique de Mykre - Membre de l'équipe XNA, de nombreuses ressources et astuces

Blog technique de Shawn Hargreaves - Membre de l'équipe XNA

Blog technique de David Weller - Membre de l'équipe XNA

Blog technique d'Emmanuel Deloget - Contenant d'excellents articles sur XNA notamment concernant la 2D.

Blog technique de Valentin Billotte - MVP C#/DirectX Technologies - Propose d'excellents articles très innovants.

V-B-3 - Sites de ressources

XNAtutorial.com - Site de ressources pour apprendre XNA

Ziggyware - Véritable portail des projets de jeux vidéo amateurs et de ressources, articles…

Zbuffer

XBox360homebrew

V-C - Presse et livres

V-C-1 - Magazine

Programmez ! - N°93 - Janvier 2007 : Article de Alain Zanchetta - Consultant architecte chez Microsoft France / Services

V-C-2 - Bibliographie

XNA Game Studio Express: Developing Games for Windows and the Xbox 360 par Joseph B Hall

Professional XNA Game Programming: For Xbox 360 and Windows par Benjamin Nitschke