De XNA à MonoGame

Dean Ellis

Traducteur

Alexandre Laurent

Cet article est une republication du magazine Game Developer de mai 2013 expliquant comment vous pouvez passer de XNA à MonoGame.

Commentez

- Titre : De XNA à MonoGame

- Auteur : Dean Ellis

- Traducteur : Alexandre Laurent

- Parution : 16 juillet 2013

- Mise à jour : 16 juillet 2013

- 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 ® 2013 Dean Ellis. 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. Introduction

- II. Qu'est-ce que MonoGame ?

- III. Démarrer avec MonoGame

- IV. Récupérer le code

- V. Contenu et ressources

- VI. Utiliser des effets personnalisés

- VII. MonoGame pour mobiles

- VII-A. Résolution d'écran

- VII-B. Gestion des commandes

- VII-C. Pousser les performances

- VII-D. Éditeur de liens Android et iOS

- VIII. Aidez-nous !

- IX. Remerciements

I - Introduction

Pendant un long moment, l'idée de créer un « vrai » jeu en utilisant des langages managés comme C# était considérée comme de la folie. Mais les choses ont changé et les langages managés prouvent maintenant qu'ils sont tout à fait viables pour créer des jeux, grâce en grande partie à XNA et Unity 3D qui utilisent C# en tant que langage principal ou langage de script. Beaucoup de nouveaux développeurs de jeux ont appris à utiliser XNA afin d'avoir leurs jeux sur Xbox 360 et sur PC sous Windows. Bien que Microsoft ait récemment annoncé que XNA n'évoluera plus et ne sera pas supporté dans l'interface Metro de Microsoft, ces développeurs n'ont pas à tout recommencer à partir de zéro. C'est là qu'arrive MonoGame, une implémentation Open Source de l'API XNA 4.

II - Qu'est-ce que MonoGame ?

Le but de MonoGame était à l'origine de permettre aux développeurs XNA de publier leurs jeux sur iPhone, mais le projet a énormément grandi depuis ses humbles débuts. Il supporte maintenant un certain nombre de plateformes, incluant Mac OS X, Linux, Windows 8, Windows Phone 8, Android et iOS. Pour la plupart, l'utilisation est libre (bien que vous deviez payer la licence pour les frameworks Xamarin iOS et Android) et modifiable, car tout le code est couvert par la licence MS-PL (Microsoft Permissive License).

Maintenant, le but premier de MonoGame est de produire une API compatible XNA et multiplateforme, qui peut être étendue à de nouvelles plateformes au fur et à mesure de leur création. Par exemple, comme MonoGame supporte déjà Android, nous avons été capables d'ajouter le support de la Ouya en quelques jours.

Une fois l'API XNA stable, nous envisageons d'étendre l'API avec de nouvelles fonctionnalités que les gens auraient aimé voir dans XNA et l'étendre pour rendre certaines choses plus simples. Pour la plupart des membres de l'équipe qui travaillent sur MonoGame depuis déjà quelques années maintenant, c'est un projet à long terme.

III - Démarrer avec MonoGame

Premièrement, allez sur la page http://www.monogame.net/downloads et récupérez la dernière version stable. Actuellement, MonoGame supporte Visual Studio et Monodevelop/Xamarin Studio.

Si vous voulez utiliser Visual Studio : l'installateur Windows va installer les modèles de projet pour toutes les éditions de Visual Studio 2010 et 2012. Des conditions particulières peuvent exister pour votre plateforme cible :

- pour les Windows bureau, vous pouvez utiliser VS 2010 Express ou une édition supérieure ou VS 2012 Express pour bureau ou une édition supérieure sur Windows 7 ou 8 ;

- pour Windows Store, vous avez besoin de VS 2012 Express pour Windows 8 ou une édition supérieure sur Windows 8 ;

- pour Windows Phone 8, vous avez besoin de Windows 8 64-bits et du SDK Windows Phone 8. Celui-ci installera VS 2012 Express pour Windows Phone et pourra aussi fonctionner avec VS 2012 Professionnel ou une édition supérieure. Pour utiliser l'émulateur Windows Phone 8, votre PC doit correspondre à des exigences matérielles spécifiques. Visitez http://www.microsoft.com/en-GB/download/details.aspx?id=35471 pour plus de détails ;

- pour Android et/ou iOS, vous avez besoin de VS 2010 ou 2012 Professionnel ou une édition supérieure ainsi que de Xamarin Business ou une édition supérieure sur Windows 7 ou 8.

Pour compiler du contenu au format XNB, vous avez besoin de XNA Game Studio 4.0 ou du SDK Windows Phone 7.11 sur votre machine. C'est une solution temporaire tant que notre remplacement du pipeline de contenu n'est pas complet. Pour installer ces SDK sur Windows 8, vous devez d'abord avoir le client Windows Games Live.

Une liste complète des conditions et des liens de téléchargement peut être trouvée ici.

Si vous souhaitez utiliser MonoDevelop/Xamarin Studio : MonoDevelop est un EDI gratuit et Open Source disponible pour Windows, Linux et Mac OS X (http://www.monodevelop.com/). MonoGame est disponible sous la forme d'un paquet, qui inclut les routines pour chaque plateforme. Vous pouvez le télécharger sur CodePlex sous la forme d'un fichier .mpack et l'installer à l'aide du « AddIn Manager » (gestionnaire de modules) dans MonoDevelop. Récemment, Xamarin a publié Xamarin Studio, une version améliorée de MonoDevelop pour les gens voulant utiliser cet EDI. Il y a aussi un fichier .mpack disponible pour cette version.

Une fois que vous avez installé le paquet requis dans votre EDI, vous êtes prêt à créer un nouveau projet MonoGame. Il y a plusieurs choix possibles, mais pour démarrer, prenez celui conçu pour votre plateforme native : pour Windows, créez une nouvelle application « MonoGame for Window GL » (MonoGame pour Window GL) ; pour Mac OS X, créez une application « MonoGame for MacOS » (MonoGame pour MacOS) et ainsi de suite. Une fois que vous avez créé un nouveau projet, vous allez voir la classe habituelle « Game » qui effectue le rendu de l'écran bleu bleuet.

Skulls of the Shogun développé par 17-Bit avec MonoGame pour produire une version Windows 8 de leur jeu.

Avant que vous ne commenciez à coder, il y a quelques éléments à savoir. Pour Windows, tous les modèles de projet vont fonctionner directement, mais si vous voulez travailler sur un projet Android, vous aurez besoin de Xamarin.Android provenant de Xamarin. MonoDevelop/Xamarin Studio inclut les modèles de projet pour Max OS X et iOS, mais ceux-ci ne fonctionneront que sur un Apple Mac à cause des conditions de développement requises. Pour iOS, vous devrez installer Xamarin.iOS et pour Mac vous devrez récupérer MonoMac. De plus, à cause de quelques problèmes avec le module AddIn pour MonoDevelop et Xamarin Studio, vous allez devoir télécharger le code source de MonoGame et ajouter les références dans les projets pour MacOS, iOS et Android. (L'équipe de développement travaille sur la correction de ce point.)

IV - Récupérer le code

Si vous voulez récupérer le code de MonoGame, vous devez installer git. Il existe de jolies interfaces utilisateur pour git, mais la plupart des membres de l'équipe utilisent la ligne de commande. Donc voici la liste des commandes que vous devez utiliser pour récupérer le code :

git clone git://github.com/mono/MonoGame.git MonoGame

cd MonoGame

git submodule update -init ThirdParty

Ces commandes récupéreront une copie en lecture seule de MonoGame et des bibliothèques tierces dont vous avez besoin. Si vous souhaitez faire des modifications et contribuer au projet, vous devez créer un fork du projet. Vous pouvez trouver les détails ici.

V - Contenu et ressources

MonoGame, tout comme XNA, peut utiliser les fichiers de contenu compilé .xnb. Ces fichiers .xnb sont actuellement créés avec le pipeline de contenu XNA. Au moment de l'écriture de cet article, l'équipe de MonoGame travaille sur une implémentation multiplateforme qui fonctionnera sur Windows, Mac OS X et Linux, mais pour le moment, vous aurez besoin d'utiliser le pipeline de contenu de XNA. Il est aussi possible de charger des ressources natives grâce au ContentManager, donc si vous souhaitez charger directement un fichier .png, vous pouvez utiliser le code que vous utilisez habituellement :

texture = Content.Load<Texture2D>("character");

MonoGame essaiera de charger un fichier .xnb en premier, mais si le fichier n'existe pas, il tentera les types natifs connus pour ce type d'objet. Cette fonctionnalité a été ajoutée à l'origine pour aider les personnes développant pour iOS et Mac et n'ayant pas accès à une machine Windows pour préparer leurs contenus. (Voir la Figure 1 pour une table des types de fichiers disponibles pour chaque classe.)

Figure 1 : formats disponibles pour chaque classe. * - fichier PVRTC compressé seulement, ** - doit être généré par le « Content Pipeline » de MonoGame.

Classe

Windows

Linux

Mac OS

IOS

Android

Windows 8

Texture2D

.xnb .png .jpg .tiff

.xnb .png .jpg .tiff

.xnb .png .jpg .tiff

.xnb* .png .jpg .tiff

.xnb .png .jpg .tiff

.xnb .png .jpg

SoundEffect

.xnb .wav

.xnb .wav

.xnb

.xnb

.wav .mp3 .ogg

.xnb

Song

.xnb .wav

.xnb .wav

.xnb

.xnb

.mp3

.xnb

Model

.xnb

.xnb

.xnb

.xnb

.xnb

.xnb

Effect

.xnb**

.xnb**

.xnb**

.xnb**

.xnb**

.xnb**

SpriteFont

.xnb

.xnb

.xnb

.xnb**

.xnb

.xnb

Comme vous pouvez le voir dans la Figure 1, sur Android vous ne pouvez pas utiliser les fichiers .xnb pour les SoundEffet et Song. Vous devez utiliser les types natifs pour cette plateforme. Cela est dû aux limitations des classes SoundPool et MediaPlayer sur Android. (Certaines de ces restrictions seront retirées au fil du temps et de la maturation du framework.) De plus, certaines plateformes ne supportent que les fichiers .xnb pour certains types. Cela est dû au fait qu'il est plus efficace d'utiliser les fichiers de contenu compilé et optimisé pour ces types. Par exemple, il est plus performant de prétraiter un Model au moment de la compilation que de charger un fichier .fbx pendant l'exécution et de le décoder sur un périphérique mobile.

Heureusement, le framework MonoGame est fourni avec des outils que nous utilisons pour étendre le pipeline de contenu de XNA afin de produire ce dont nous avons besoin. Toutefois, comme il repose sur le framework XNA, cela ne fonctionnera que sous Windows. Vous pouvez créer un « MonoGame Content Project » (Projet de contenu MonoGame) dans Visual Studio 2010, qui créera un projet au contenu XNA classique et un projet XNA qui va, à son tour, construire le contenu du projet. Ces deux projets ont toutes les références nécessaires et les importations de cibles MSBuild pour permettre d'utiliser les processeurs de MonoGame.

Maintenant, lorsque vous ajoutez une nouvelle ressource au contenu du projet et que vous sélectionnez le type de processeur que vous souhaitez utiliser, vous allez voir des processeurs liés à MonoGame : « MonoGame - Effect », « MonoGame - Texture » et ainsi de suite. Ces processeurs effectueront des tâches spécifiques sur les ressources pour les optimiser pour la plateforme cible (voir Figure 2).

Figure 2 : exemple de formats internes .xnb optimisés.

Type

Windows

Linux

Mac OS

IOS

Android

Windows 8

Texture2D

DXT

DXT

DXT

PVRTC

DXT

DXT

SpriteFont

DXT

DXT

DXT

PVRTC

DXT

DXT

Song

MP3

MP3

MP3

MP3

N/A

MP3

SoundEffect

PCM

PCM

PCM

PCM

N/A

PCM

Le nouveau projet « Builder » possède plusieurs configurations de construction pour chaque plateforme, donc si vous ciblez l'iPhone, vous pouvez choisir la configuration iOS. Si vous ciblez le Windows Store, choisissez la configuration Windows 8. Les fichiers produits seront placés dans bin\<Configuration>\Release, de sorte que si vous construisez les fichiers pour plusieurs plateformes, vous aurez un répertoire pour chaque plateforme cible. La dernière étape est d'ajouter ces fichiers au répertoire Content de votre projet. Vous pouvez le faire facilement en utilisant la fonctionnalité « Add as Link » (Ajouter comme lien) dans Visual Studio et MonoDevelop. De cette façon, vous pouvez lier un fichier sans avoir à le copier dans le répertoire du projet, ce qui est pratique lorsque vous modifiez le contenu et que vous le compilez avec le « Builder » de contenu, le fichier sera automatiquement récupéré la prochaine fois que vous compilez votre application. Notez que selon la plateforme cible vous devez définir la BuildAction (action de construction) correctement pour vos fichiers ressources afin de les inclure dans le paquet final de l'application.

VI - Utiliser des effets personnalisés

Si vous souhaitez utiliser des fichiers Effect d'un projet XNA précédent ou d'un échantillon XNA, vous devez les traiter avec le processeur d'effets de MonoGame afin de les compiler pour la plateforme cible. Certaines plateformes utilisent OpenGL au lieu de DirectX comme bibliothèque graphique, donc le fichier Effect de XNA devra être converti dans le langage de shaders d'OpenGL pour fonctionner.

Plutôt que de demander aux développeurs de réécrire leurs shaders en GLSL, MonoGame installe quelques outils pour convertir automatiquement le HLSL du fichier Effect vers le langage de shaders approprié pour la plateforme cible. Pour les plateformes utilisant DirectX, MonoGame utilise la suite d'outils de DirectX 11 pour compiler vos effets en shaders optimisés. Pour les plateformes OpenGL, le fichier Effect est traité par un outil appelé MojoShader, qui effectue une conversion bas niveau du HLSL vers GLSL permettant à votre effet de fonctionner pour cette plateforme.

Bien sûr, le processus de conversion peut occasionnellement introduire des erreurs ou des fonctionnalités non supportées par la plateforme cible. Par exemple, avec OpenGL Shader Model 3.0, vous ne pouvez pas accéder à la texture dans le vertex shader, donc si votre effet utilise cette fonctionnalité, il ne fonctionnera probablement pas. Prenons un échantillon d'un effet provenant des exemples de XNA disponibles sur le site Xbox Creator Club : l'effet d'extraction de bloom est un bon exemple. Bien que ce ne soit qu'un pixel shader, cela vous donnera une bonne idée du genre de choses dont nous devons nous soucier.

Listing 1 : Extraction de bloom

// Le Pixel shader extrait les zones claires de l'image.
// C'est la première étape pour appliquer l'effet de bloom.
sampler TextureSampler : register(s0);
float BloomThreshold;
float4 PixelShaderFunction(float2 texCoord : TEXCOORD0) : COLOR0
{
// Récupère la couleur originale de l'image.
float4 c = tex2D(TextureSampler, texCoord);
// Ajustement pour garder seulement les valeurs plus claires que le seuil fixé..
return saturate((c - BloomThreshold) / (1 - BloomThreshold));
}

technique BloomExtract
{
pass Pass1
{
PixelShader = compile ps_2_0 PixelShaderFunction();
}
}

Si vous regardez le code de l'effet du listing 1, une des premières choses à noter est que cet effet utilise les pixel shaders 2.0 (ps_2_0). Cela est correct pour DirectX 9, mais pour OpenGL et DirectX 11 cela doit être modifié. Avant de changer le code, il est nécessaire de noter que vous pouvez utiliser des définitions conditionnelles dans les fichiers d'effets pour changer le comportement selon le modèle de shaders ciblé. Si vous ciblez le modèle de shaders 4, vous pouvez utiliser :

#if SM4
// code
#endif

pour gérer ce cas spécial. Ces définitions sont toujours valides lorsque vous utilisez le « Content pipeline » de MonoGame, donc pour faire en sorte que ce shader supporte toutes les plateformes que nous voulons, nous devons mettre à jour la partie technique pour gérer toutes les plateformes cibles. Dans ce cas, nous devons supporter le modèle de shaders 4 pour DirectX 11 et le modèle de shaders 3 pour OpenGL/GLES. Sachant cela, la passe devient :

pass Pass1
{
#if SM4
PixelShader = compile ps_4_0_level_9_1 PixelShaderFunction();
#elif SM3
PixelShader = compile ps_3_0 PixelShaderFunction();
#else
PixelShader = compile ps_2_0 PixelShaderFunction();
#endif
}

Pour chaque type de modèle de shaders, nous définissons un pixel shader différent. Vous pouvez aussi faire cela avec les vertex shaders, donc une déclaration vs_2_0 deviendra vs_3_0 pour les modèles de shaders 3 et vs_4_0_level_9_1 pour les modèles de shaders 4.

Ensuite, regardons les paramètres passés à la fonction PixelShaderFunction. Dans cet exemple, la fonction ne prend qu'un paramètre, mais afin que cet effet fonctionne correctement avec l'effet SpriteBatch de MonoGame, nous devons ajouter des paramètres supplémentaires. (C'est une limitation de MonoGame qui sera probablement résolue dans le futur.) La bonne nouvelle est que l'ajout de ces paramètres supplémentaires ne casse pas la compatibilité avec XNA, donc, dans ce cas, nous pouvons simplement ajouter les paramètres manquants comme suit :

void PixelShaderFunction( float3 position: POSITION0, float4 color : COLOR0, float2 texCoord : TEXCOORD0)

Dans XNA 3.1, les fonctions PixelShader et VertexShader étaient appelées PixelShader et VertexShader. Cela n'est plus valide en XNA 4.0 ou dans MonoGame, ce qui explique pourquoi, dans le listing 1, nous renommons les fonctions : VertexShaderFunction et PixelShaderFunction. Bien sûr, vous pouvez les nommer comme vous le souhaitez.

Supergiant Games a utilisé un fork du code de MonoGame pour porter Bastion sur iPad.

Si vous appliquez ces techniques à tous les effets inclus dans l'échantillon de Bloom, le portage du projet pour Windows 8, Android et iOS devient juste une question d'utilisation du constructeur de contenu pour produire les fichiers .xnb pour chaque plateforme cible et ensuite lier ces fichiers à votre projet.

VII - MonoGame pour mobiles

Donc, vous avez un bon jeu sur Xbox 360 ou Windows que vous souhaitez porter sur mobile. Quelles sont les choses dont vous devez vous soucier ? Certains points sont évidents : la taille de l'écran, les commandes et la performance. Voici comment gérer ces détails dans MonoGame.

VII-A - Résolution d'écran

Sur certaines plateformes, comme Windows Phone 7 et iOS, vous pouvez presque garantir la taille de l'écran des périphériques sur lesquels vous travaillez, mais avec d'autres périphériques et plateformes, ce n'est pas si simple. Windows Phone 7/8 supportent le redimensionnement matériel mais avec Android, Ouya, Windows 8 et les écrans Retina sur iPad et Mac, les développeurs MonoGame doivent prendre en considération de nombreuses résolutions d'écran. Quelques fois, vous allez vous retrouver naviguant dans un champ miné de résolutions d'écran allant de 320x200 jusqu'à la full HD.

Une technique qui a plutôt bien été utilisée dans le passé est le redimensionnement du SpriteBatch. Avec cette méthode, vous pouvez créer votre jeu pour qu'il s'exécute avec une résolution précise, puis, pendant l'exécution, trouver une matrice de redimensionnement qui redimensionnera votre jeu pour correspondre à la taille de l'écran du périphérique sur lequel il s'exécute. Cette matrice est passée au SpriteBatch, qui redimensionne vos graphismes. Dans le code suivant, nous pouvons voir comment calculer la matrice. Notre résolution virtuelle est ici de 800x600.

var virtualWidth = 800;
var virtualHeight = 600;
var scale = Matrix.CreateScale(
(float)GraphicsDevice.Viewport.Width / virtualWidth,
(float)GraphicsDevice.Viewport.Height / virtualHeight,
1f);

Une fois la matrice calculée, nous pouvons appeler le SpriteBatch avec le paramètre de la matrice comme suit :

spriteBatch.Begin(SpriteSortMode.Immediate, null, null, null, null, null, scale);
// affichage
spriteBatch.End();

Cela appliquera la matrice de redimensionnement pour les éléments affichés par le batch. Il y a d'autres considérations telles que le ratio et les formats que vous devez prendre en compte, mais pour ceux-ci, il y a plein de ressources, originellement écrites pour XNA et pouvant être réutilisées avec MonoGame et appliquées aux nouvelles plateformes. (Pour plus d'informations sur ce sujet, lisez cette discussion.)

À partir d'un certain point, le redimensionnement ne résoudra pas vos problèmes. En rétrécissant de trop vos graphismes, ils deviendront pixelisés et l'agrandissement les rendra flous. C'est là que vous devez repenser vos ressources. Une technique que vous pouvez utiliser avec iOS est d'avoir deux ensembles de ressources : un pour les écrans normaux et l'autre pour les écrans Retina. Vous pouvez le faire en ajoutant un suffixe @2x aux noms des plus grandes ressources et les inclure dans votre paquet de jeu. Le pipeline de contenu de MonoGame a été programmé pour se servir de cette astuce sur iOS, donc si vous avez un fichier de ressources .xnb brut qui possède une version @2x et que vous l'exécutez sur un périphérique avec écran Retina, la ressource ayant une plus grande résolution sera chargée. (Cela augmente malheureusement la taille de votre paquet.)

L'autre option est d'avoir deux versions du jeu, une pour les périphériques normaux et une version HD, chacune utilisant un ensemble de ressources différent. Avec cette méthode, les gens auront le choix de télécharger une version HD du jeu ou la version normale.

VII-B - Gestion des commandes

Changer de plateforme signifie que vous devez supporter de nombreux périphériques d'entrée. Sur les plateformes de bureau (Windows, Linux et Mac), MonoGame utilise la bibliothèque Simple Direct Media Library (SDL) pour interfacer les différents joysticks et manettes de jeu pouvant être disponibles. Les entrées de ces périphériques sont redirigées à travers la classe GamePad. La SDL semble avoir des problèmes pour lire la description USB de certains contrôleurs Xbox 360, donc lorsque cela arrivera, il aura du mal à appliquer la configuration adéquate.

Les entrées de la souris et des touchpads sont un point sur lequel MonoGame a dévié par rapport à XNA. Sur Windows Phone 7 et 8, si vous utilisez l'implémentation de XNA fournie par Microsoft, tous vos événements tactiles seront dirigés vers la souris. Cela peut rendre très facile le portage des jeux Windows et Xbox 360 vers ces plateformes. Par contre, avec l'introduction de Windows 8, des périphériques peuvent maintenant avoir une souris et un écran tactile et il est possible que certains jeux les utilisent séparément. Sachant cela, si vous avez un jeu Windows que vous souhaitez porter sur l'application Windows Store, vous devez ajouter le support des écrans tactiles, car votre code gérant la souris ne sera pas utilisé.

VII-C - Pousser les performances

Les versions iOS et Android de MonoGame s'exécutent au-dessus de la plateforme Mono. Mono possède un bon compilateur et ces deux plateformes embarquent aussi un éditeur de liens, qui est utilisé pour réduire la taille du paquet de votre application en retirant le code non utilisé. Il possède aussi un très bon garbage collector, mais même s'il y a eu des améliorations majeures sur celui-ci ces dernières années, vous devez garder à l'esprit que vous exécutez votre code sur des mobiles et que ces derniers varient radicalement en termes de performances (surtout avec les périphériques Android). Assurez-vous de regarder vos méthodes Update. Vous pouvez donner du travail au garbage collector en créant de nombreux objets temporaires qui ne seront que jetés. Vous devez aussi réfléchir à l'obligation de faire des calculs d'une certaine façon : après tout, le code le plus rapide et celui qui n'est pas exécuté. Considérons cette définition de classe :

public class Player
{
public Vector2 Position;
public Vector2 Scale;
public void Update(GameTime gameTime) { &#8230; }
public void Draw(GameTime gameTime) { &#8230; }
}

Dans ce morceau de code, nous définissons un joueur ayant une position et une échelle (scale). Maintenant, supposons que nous utilisions la propriété Matrix du SpriteBatch pour afficher ce joueur en utilisant les données de position et d'échelle, mais aussi pour la détection de collisions. Une méthode simple pour créer la matrice est de le faire dans la méthode Update, comme suit :

var matrix = Matrix.CreateTransform(Position) * Matrix.CreateScale(Scale);

Sur les machines de bureau, cela fonctionnera sûrement correctement, mais sur des périphériques mobiles moins puissants cela pourra être un problème. Même si la classe Matrix est une structure et est peu coûteuse à créer, il en reste que nous faisons ce calcul à chaque appel à la fonction Update. Si votre jeu s'exécute à 30 images par seconde, rien que ce code provoque de nombreux calculs de matrices que vous pouvez éviter. À la place, vous pouvez déclarer un champ pour la matrice et le mettre à jour dans la méthode Update simplement. Ou, encore mieux, vous pouvez simplement mettre à jour la matrice lorsque les propriétés Position ou Scale ont été modifiées (voir listing 2).

Listing 2 : optimisation des appels à Update pour les périphériques mobiles

public class Player
{
Vector2 position;
Vector2 scale;
Matrix matrix;

public Vector2 Position {
get { return position; }
set {
if (position != value) {
position = value;
UpdateMatrix();
}
}
}

public Vector2 Scale {
get { return scale; }
set {
if (scale != value) {
scale = value;
UpdateMatrix();
}
}
}

public void UpdateMatrix() {
matrix = Matrix.CreateTransform(Position) * Matrix.CreateScale(Scale);
}
public void Update(GameTime gameTime) { &#8230; }
public void Draw(GameTime gameTime) { &#8230; }
}

Je sais que c'est un simple exemple, mais si vous pensez aux petites améliorations que vous pouvez faire, alors il a fait son travail. Parmi vous, ceux qui connaissent les mathématiques sauront que l'on peut certainement enlever les propriétés de position et d'échelle de la classe et simplement garder la matrice.

Un autre exemple est la gestion des projectiles tels que les tirs d'une arme ou d'un vaisseau. Une façon de gérer cela est d'avoir une List<Bullet> où vous ajoutez les nouveaux projectiles au fur et à mesure et vous les retirez lorsqu'ils sortent de l'écran ou de la zone de jeu. Lorsque vous ajoutez des éléments à une liste, cela entraîne l'expansion de sa capacité, vous créez de nouvelles instances de Bullet à chaque fois. Un système plus efficace serait d'avoir un cache d'instances de Bullet que vous pourriez utiliser pour peupler une liste de projectiles « actifs » en cours d'utilisation. Lorsque le projectile sort du jeu, nous pouvons juste le replacer dans le cache.

Bien sûr, vous n'avez certainement pas besoin d'une infinité de projectiles. La plupart des jeux limitent le nombre de projectiles ou missiles que l'on peut tirer. Dans ce cas, vous pouvez garder un petit cache afin de ne pas utiliser trop de mémoire et vous pouvez définir une capacité pour la liste des projectiles actifs à l'avance afin que sa taille n'augmente pas en cours de jeu.

Si vous devez créer énormément de variables temporaires pendant le chargement du niveau ou lors de n'importe quelle autre sorte de traitement, vous pouvez essayer d'appeler GC.Collect(0) aussi souvent que vous le pouvez. Cela assurera que le garbage collector collecte les éléments temporaires au lieu d'attendre la prochaine collection automatique. De plus, vous allez souhaiter éviter qu'une collection se produise pendant le jeu. Si le garbage collector doit faire une collection majeure pendant votre boucle de mise à jour, vous allez sans aucun doute voir une pause dans votre jeu. Cela peut être pour seulement quelques secondes, mais cela se remarquera. Notez que contrairement à GC.Collect(0), GC.Collect() effectue une collection complète à travers les ressources allouées sur le tas. Cela peut prendre jusqu'à 100-200 millisecondes (plusieurs trames) donc vous souhaiterez éviter les appels à GC.Collect durant le jeu, sinon, cela introduira une pause ou un lag.

Dernier point, n'utilisez pas trop d'instances de SpriteBatch. Généralement, dans les jeux XNA vous allez vouloir minimiser le nombre d'instances de SpriteBatch. C'est aussi vrai pour MonoGame. L'implémentation de MonoGame possède un cache interne de SpriteBatchItems que nous recyclons pour garder le nombre d'objets alloués au minimum. Par défaut, nous créons 1000 éléments dans notre cache, donc plus vous avez d'instances, moins vous avez de mémoire système et vous devez faire avec.

VII-D - Éditeur de liens Android et iOS

Lorsque vous ciblez les plateformes Android et iOS en utilisant la suite d'outils Xamarin, vous devez être conscient de l'éditeur de liens qui est exécuté sur votre code pendant la compilation. Cet éditeur de lien réduit la taille du code de votre paquet en enlevant les parties inutilisées de votre code ou du framework suivant les paramètres de l'outil. Le résultat est que votre paquet final contiendra un framework mono optimisé et non le framework tout entier et les parties inutilisées de votre jeu seront enlevées, elles aussi.

Si vous chargez des objets dynamiquement à travers le pipeline de contenu, vous allez quelques fois vous trouver dans la situation où l'éditeur de liens ne connaît pas le type des objets que vous utilisez et les retire du code. Cela mène habituellement à une exception MissingMethodException lorsque vous essayez de construire ou d'appeler une méthode d'un de ces types non liés. La bonne nouvelle est qu'il y a plusieurs méthodes pour informer l'éditeur de liens que vous souhaitez préserver certains objets tels qu'ils sont et qu'il ne les enlève pas. Une méthode consiste à utiliser PreserveAttribute, qui est fourni sur iOS et Android :

#if ANDROID

[Android.Runtime.Preserve(AllMembers=true)]

#elif IOS

[MonoTouch.Foundation.Preserve(AllMembers=true)]

#endif

public class Example {

public Example ()
{
}
}

Cela assure que pour les plateformes Android et iOS la classe ne sera pas retirée par l'éditeur de liens.

Il y a d'autres méthodes pour contrôler le comportement de l'éditeur de liens. Si vous souhaitez en apprendre plus, lisez les documentations d'Android et iOS disponibles sur le site de Xamarin :

- documentation pour iOS ;

- documentation pour Android.

VIII - Aidez-nous !

Cet article n'a fait qu'effleurer la surface de MonoGame, mais heureusement cela vous motivera pour essayer et peut-être même le rendre meilleur ! Nous avons un certain nombre d'objectifs à l'horizon pour lesquels nous souhaitons être aidés, comme construire un pipeline de contenu multiplateforme, ajouter le support de nouvelles plateformes telles que Windows Phone 8 et Raspberry Pi, utiliser DirectX 11 et étendre XNA. Donc, si vous souhaitez nous aider, rejoignez http://www.monogame.net/.

IX - Remerciements

Merci à Dean Ellis de nous avoir permis de traduire son article.

Merci à Winjerome pour ses corrections et à ClaudeLELOUP et zoom61 pour leur relecture orthographique.