Astuces DotNet (Sébastien Courtois)

28/01/2012

[Kinect SDK] Presentation de Kinect SDK

Filed under: C#, C++, Débutant, Jeux vidéos, Kinect — Étiquettes : , , , , , , , — sebastiencourtois @ 08:44

Cet article est le premier d’une série d’articles sur le SDK de Kinect qui sort le 1er février. Ce SDK pour PC permet de dialoguer avec Kinect en .NET ainsi qu’en C++.

Au travers de cette série d’articles, vous apprendrez à récupérer les informations que fournissent les différents capteurs Kinect. Ce post d’introduction va présenter les différentes possibilités du SDK.

 

1. Kinect : Le Matériel

kinect-hardware

Kinect est composé de :

* une camera video RGB : Il s’agit d’une caméra couleur d’une résolution 640×480 (30 images/seconde) ou 1280×960 (15 images/seconde).

* une caméra de profondeur : Il s’agit d’un laser infrarouge (capteur de gauche) qui balaie la pièce de rayon infrarouge. Ces rayons sont visualisés par un capteur infrarouge (capteur de droite). La sensibilité de ce capteur s’ajuste automatiquement en fonction des conditions de la pièce (luminosité, obstacles…) Ce capteur de profondeur a une résolution de 320×240 ou 80×60 (30 images par secondes).

* 4 microphones chargés d’enregistrer le son et de réaliser des opérations de traitements du signal afin de supprimer les parasites (bruits extérieurs, éclos…). Ce système de microphone réparti sur l’ensemble du capteur permet de détecter la direction du son et ainsi reconnaitre le joueur qui a parlé.

* Un moteur pour incliner verticalement Kinect. Kinect peut aller de –27 degrés à + 27 degrés d’inclinaison. Cela permet au développeur d’adapter la vue si elle n’est pas adéquate. (Par exemple, si on voit le corps d’une personne, mais pas sa tête, le développeur peut incliner Kinect vers le haut afin d’avoir le corps en entier.)

 

2. Le SDK et la partie logicielle de Kinect

Le SDK Kinect est disponible sur le site : Kinect For Windows.

En plus des fonctions de bases de Kinect, le SDK embarque aussi :

* Le tracking de personnes (Skeleton Tracking) : Kinect peut indiquer si elle reconnait une personne et permet de tracker 20 points du corps en temps réel.

* En plus de la récupération d’un son sans parasites, le SDK fournit des aides pour la reconnaissance de la parole basée sur l’API Windows Speech (aussi utilise dans Windows Vista et 7 pour la reconnaissance de la parole).

kinect-voicelocator

Kinect Voice Locator : Un des samples du SDK

3. Les caractéristiques techniques et limitations de Kinect

Pour la caméra vidéo, Kinect fournit des images de 640×480 (30 images/seconde) ou 1280×960 (15images/seconde). Chaque pixel est codé en BGR sur 32 bits.

Pour le capteur de profondeur, Kinect fournit des images en 320×240 (30 images/seconde). Les données du capteur de profondeur sont codées sur 13 bits. Elle représente une distance en millimètre allant de 800 mm à 4000 mm. Lorsque le tracking des personnes est actif, les données de reconnaissance des personnes sont fusionnées avec les données de profondeur. Au final, chaque pixel correspond à 16 bits (13 pour la profondeur et 3 pour l’identification d’une personne). Il est possible de tracker 2 personnes en temps réel + 4 autres personnes « passives » (les personnes sont détectes, mais il n’y a pas de tracking de leur squelette).

L’une des difficultés est que les images venant de la caméra vidéo et du capteur de profondeur ne sont pas synchronisées par le SDK. Si le développeur souhaite faire du traitement d’images en utilisant les deux capteurs, il devra réaliser lui même la synchronisation. Cela peut s’avérer difficile, car les framerates entre les capteurs peuvent être différents et ne sont pas toujours constants.

Le moteur d’inclinaison de Kinect possède aussi ses limitations. En dehors de sa plage de valeurs (allant de –27 dégrées a +27 dégrées d’inclinaison verticale), il n’est pas possible d’envoyer des ordres a Kinect plus d’une fois par secondes ou plus de quinze fois toutes les 20 secondes. Cela est du a des limitations matériel, car le moteur n’est pas conçu pour bouger constamment. De plus, le fait de bouger la caméra prend du temps et peut perturber les capteurs Kinect.

La reconnaissance de la parole est entièrement basée sur des grammaires que le développeur doit fournir. Les grammaires correspondantes aux mots à reconnaitre. Cela peut être défini dans un fichier XML ou directement dans le code.

 

4. Conclusion

Nous avons fait un petit tour du propriétaire du composant Kinect et de ses possibilités. Dans les prochains articles Kinect, nous verrons comment récupérer les différentes informations (flux vidéo & profondeur, détections et tracking de joueurs…) et comment les utiliser (traitement d’images, dessin des squelettes…).

16/05/2011

[XNA/DirectX/OpenGL] Les bases de la programmation 3D

Filed under: 3D, Débutant, DirectX, Intermediaire, Jeux vidéos, OpenGL, Windows Phone, XBOX 360, XNA — Étiquettes : , , , , , , , , — sebastiencourtois @ 09:00

Je n’ai pas été très bavard ces derniers temps (mon dernier post remonte à 5 mois… Confus). Une des mes excuses est mon départ de France pour travailler pour une société américaine à San Francisco. Je suis bien installé maintenant et je vais me remettre à bloguer un peu plus Sourire.

Cela fait quelques temps que je fais des posts sur la 3D mais je n’arrivais jamais à expliquer les bases de la programmation 3D de façon simple et claire. Au travers de mes recherches dans ce domaine, je suis tombé sur le site de Bobby Anguelov. Plutôt spécialisé en Intelligence Artificielle, il a écrit des cours très agréables à lire sur DirectX 10 en C++. Il a aussi été enseignant à l’université de Pretoria (Afrique du Sud). C’est un de ses cours que j’ai décidé de traduire et de publier ici.

Pourquoi ? :

  • Le cours est claire, simple et bien illustré. Pourquoi refaire quelque chose qui a déjà été bien fait par quelqu’un d’autre ? Sourire
  • Le cours est vraiment grand public/débutant. Il suffit d’aimer la 3D et de connaitre les bases de la programmation pour pouvoir lire ce cours.
  • Le cours est plutôt générique et les informations contenues dans ces documents peuvent aussi s’appliquer à toutes les technologies 3D (DirectX/OpenGL/XNA) ==> Il n’y a aucun code source dans ce cours.

Note : La traduction a été complexe car de nombreux termes sont les termes utilisés dans les blogs/forums … Par conséquent, j’ai essayé un maximum de conserver ces termes tout en fournissant les traductions françaises.

Le cours se découpe en 6 chapitres :

  1. Introduction et historique de la 3D (30 Slides)
  2. Mathématiques appliquées à la 3D (37 Slides)
  3. Le pipeline graphique (27 Slides)
  4. L’étape applicative du pipeline graphique (23 Slides)
  5. L’étape géométrique du pipeline graphique (24 Slides)
  6. L’étape rastérisation du pipeline graphique (84 Slides)

Le cours complet en francais est disponible en format zip.

Si vous préférez la version anglaise, vous pourrez trouver les cours à cette adresse : http://takinginitiative.net/computer-graphics-course-slides/

NOTE : Si vous comptez utiliser ces documents pour les publier ou les enseigner, merci de nous prévenir. Nous ne voulons pas de droit d’auteurs sur ces documents Sourire mais nous souhaitons juste savoir où sont utilisés ces informations (par fierté Sourire) et être cité (lien vers nos blogs …). Si vous souhaitez la version Powerpoint, contactez nous (commentaire sur ce blog ou celui de Bobby).

  • La suite … ?

J’ai pas mal d’idées de posts pour la suite. Les statistiques de ce blog montrent que XNA 4 est très populaire en ce moment et j’envisage deux tutoriaux sur le HLSL en XNA 4. Je vais continuer les posts sur DirectX. Toutefois, je vais me focaliser sur DirectX 11. Enfin, j’ai récupérer le SDK de PhysX 3 (sorite ce mois ci) et je vais faire des cours d’introduction à cette API physique très populaire dans les jeux vidéos. Je vais aussi voir pour des tutoriaux sur le Cry Engine 3 quand le SDK sera publique (Août aux dernières nouvelles).

En ce qui concerne XNA sur Silverlight 5…. Je ferais des tutoriaux lors de la sortie finale car l’API actuelle n’est pas encore complète (fin d’année je pense).

N’hésitez pas à mettre des commentaires sur ce cours et si vous avez des idées de tutoriaux/sujets que vous voudriez voir approfondis.

18/09/2010

[XNA 4] Tutoriel 4 : Gestion des entrées : Clavier, Souris, Manette XBOX 360, Windows Phone Touch

Filed under: .NET, C# 4, Débutant, Jeux vidéos, XBOX 360, XNA — Étiquettes : , , , , , , , , , , , — sebastiencourtois @ 13:50

Jusqu’a présent, nous avons fait des applications démos tournant automatiquement. Même si certaines démos commerciales ou films d’animations peuvent être agréables à regarder, un jeu vidéo est intéressant grâce à l’interaction joueur/univers du jeu.

Code Source pour commencer ce tutoriel

Au travers de ce tutoriel, nous allons voir quatre outils d’interactions avec le joueur pour déplacer le tank du tutoriel précédent :

    • Clavier (PC & XBOX 360)
    • Souris (PC uniquement)
    • Touch (Windows Phone uniquement)
    • Manette XBOX 360 (PC / XBOX 360)

Remarques : Il est possible de brancher un clavier USB à une XBOX 360 et récupérer les entrées du clavier comme s’il s’agissait d’un pc. Pour le touch, XNA ne prend pas en charge que le toucher des écrans multitouch PC vendus dans le commerce.

Comme tout les codes de mise à jour du jeu non graphique, la gestion des interactions avec l’utilisateur se réalise dans la méthode Update() de la boucle de jeu.

  • Gestion du clavier

La première chose à faire est de récupérer l’état du clavier à un instant T. Cela se réalise par la méthode statique GetState() de la classe Keyboard

KeyboardState kbState = Keyboard.GetState();

Remarque : GetState() peut avoir un paramètre PlayerIndex (allant de Player.One à Player.Four). Cela est utilisé pour identifier la manette de l’utilisateur utilisant un Chatpad (clavier se branchant directement sur la manette). Pour le PC, on utilisera la version sans paramètre.

On récupère un structure KeyboardState contenant les informations sur les touches pressées ou non. KeyboardState contient 3 méthodes :

    • GetPressedKeys() : Méthode renvoyant un tableau des touches enfoncées (enum Keys)
    • IsKeyUp(Keys key) : Indique si la touche du clavier passée en paramètre est relaché (true si relâchée)
    • IsKeyDown(Keys key) : Indique si la touche du clavier passée en paramètre est enfoncée (true si enfoncée)

L’énumération Keys est une énumération de l’ensemble des touches du clavier (Keys.Up correspond à la flèche du haut, Keys.B à la touche B…). Il est possible d’utiliser les valeurs numériques correspondant à ces alias.

Partant des principes ci-dessus, on souhaite déplacer le tank en utilisant les touches du clavier et doubler la vitesse si, en plus on appuie sur la touche majuscule. On divisera par deux la vitesse si on appuie sur la touche control pendant le déplacement.

//Déplacement remise à 0 du déplacement
TankVelocity = Vector2.Zero;
//Vitesse maximun du tank
int TankMaximunSpeed = 2;

//Gestion du clavier
KeyboardState kbState = Keyboard.GetState();

if (kbState.IsKeyDown(Keys.Up))
    TankVelocity.Y -= TankMaximunSpeed;
if (kbState.IsKeyDown(Keys.Down))
    TankVelocity.Y += TankMaximunSpeed;
if (kbState.IsKeyDown(Keys.Left))
    TankVelocity.X -= TankMaximunSpeed;
if (kbState.IsKeyDown(Keys.Right))
    TankVelocity.X += TankMaximunSpeed;
if (kbState.IsKeyDown(Keys.LeftShift) || kbState.IsKeyDown(Keys.RightShift))
    TankVelocity *= 2;
if (kbState.IsKeyDown(Keys.LeftControl) || kbState.IsKeyDown(Keys.RightControl))
    TankVelocity /= 2;

La variable TankMaximunSpeed est une constante définie comme la vitesse maximum du tank dans une direction donnée. TankVelocity décrit le vecteur de déplacement du tank pour l’itération courante.

  • Gestion de la souris

Comme nous l’avons fait pour le clavier, la première tâche pour récupérer l’état de la souris.

//Gestion de la souris
MouseState mouseState = Mouse.GetState();

La structure MouseState contient trois propriétés importantes :

    • Propriétés *Button : Permet de choisir un des boutons de la souris et de savoir s’il est pressé ou non (Enumération ButtonState).
    • Propriétés X, Y : Indique la position (X,Y) du curseur sur l’écran de l’ordinateur (la position en dehors de la fenêtre de jeu est transmise).
    • Propriété ScrollWheelValue : Indique le nombre d’utilisation du scroll depuis le début du jeu.(positif si scroll vers l’avant).

Si l’on souhaite déplacer le tank vers le clic de l’utilisateur, on utilisera le code suivant (le bouton gauche de la souris doit rester enfoncé pour faire avancer le tank).

if (mouseState.LeftButton == ButtonState.Pressed)
{
    Vector2 PositionMouse = new Vector2(mouseState.X, mouseState.Y);
    TankVelocity = PositionMouse - TankPosition;
    TankVelocity.Normalize();
    TankVelocity *= TankMaximunSpeed;
}

Par défaut, XNA ne gère pas les doubles clics ou les clics longs. C’est au développeur de gérer ces cas. Nous verrons, dans un prochain post, comment réaliser ces opérations particulières.

  • Gestion du Touch Windows Phone

Pour utiliser le Touch, il faut tout d’abord vérifier si le matériel peut gérer cette capacité.

//Gestion du touch
TouchPanelCapabilities touchCap = TouchPanel.GetCapabilities();
if (touchCap.IsConnected)
{
   [...]
}

Un fois la compatibilité matérielle vérifié, on récupère l’état de l’interface tactile.

TouchCollection touches = TouchPanel.GetState();

La struncture TouchCollection est un tableau de TouchLocation contenant chacune un identifiant, une position et un état TouchLocationState parmi les 4  états suivants :

    • Pressed : Un nouveau point de pression est disponible
    • Released : Un point pression existant a disparu (l’utilisateur a retiré son doigt de l’écran
    • Moved : Un point de pression existant lors de l’itération précédente est toujours là et la position a été mise à jour
    • Invalid : Problème de reconnaissance des points de pressions (souvent un nouveau point de pression qui est pris pour un point existant).

Si l’on souhaite réaliser la même chose que l’exemple précédent avec la souris, on utilisera le code suivant : (on ne prend que le premier contact tactile pour simuler un curseur de souris).

//Gestion du touch
TouchPanelCapabilities touchCap = TouchPanel.GetCapabilities();
if (touchCap.IsConnected)
{
   TouchCollection touches = TouchPanel.GetState();
   if (touches.Count >= 1)
   {
      Vector2 PositionTouch = touches[0].Position;
      TankVelocity = PositionTouch - TankPosition;
      TankVelocity.Normalize();
      TankVelocity *= TankMaximunSpeed;
   }
}
XNA_WindowsPhoneInput 

L’utilisation de l’interface Touch du Windows Phone sera décrit plus en détail dans un prochain post (notamment l’utilisation de gestures et du multitouch).

  • Gestion de la manette XBOX 360

La manette XBOX 360 est accessible au travers de l’API XNA. La  première étape consiste à voir si une ou plusieurs manettes sont connectées puis de récupérer son état. Dans notre exemple, nous ferons cela juste pour le premier joueur.

GamePadState gamepadState = GamePad.GetState(PlayerIndex.One);
if (gamepadState.IsConnected)
{
    [...]
}

La manette XBOX 360 n’est pas la seule utilisable avec XNA. Un certain nombre d’autres manettes peuvent être vu par XNA (sur PC uniquement). Afin de vérifier les éléments disponibles sur ces manettes, la classe GamepadCapabilities permet d’indiquer la présence ou non des joysticks/boutons.

GamePadCapabilities gamepadCaps = GamePad.GetCapabilities(PlayerIndex.One);

if (gamepadCaps.HasLeftXThumbStick && gamepadCaps.HasLeftYThumbStick)
    TankVelocity = gamepadState.ThumbSticks.Left * TankMaximunSpeed;

else if (gamepadCaps.HasLeftXThumbStick && gamepadCaps.HasLeftYThumbStick)
    TankVelocity = gamepadState.ThumbSticks.Right * TankMaximunSpeed;

else if (gamepadCaps.HasDPadUpButton && gamepadCaps.HasDPadLeftButton && gamepadCaps.HasDPadRightButton && gamepadCaps.HasDPadDownButton)
{
    if (gamepadState.IsButtonDown(Buttons.DPadUp))
       TankVelocity.Y -= TankMaximunSpeed;
    if (gamepadState.IsButtonDown(Buttons.DPadDown))
       TankVelocity.Y += TankMaximunSpeed;
    if (gamepadState.IsButtonDown(Buttons.DPadLeft))
       TankVelocity.X -= TankMaximunSpeed;
    if (gamepadState.IsButtonDown(Buttons.DPadRight))
       TankVelocity.X += TankMaximunSpeed;
}

Pour notre exemple, nous utilisons le joystick gauche s’il existe sinon nous utilisons le joystick droit s’il existe sinon nous utilisons la croix directionnelle (si elle existe). Vous pouvez remarquer que le GamepadState a deux méthodes IsButtonDown/IsButtonUp qui fonctionne de la même façon que le clavier.

Les joysticks (Thumbstick) ont un fonctionnement légèrement différent.La propriété ThumbSticks regroupe l’ensemble des joysticks (2 joysticks au maximum : Left et Right). Chaque joystick est un Vector2 indiquant le décalage  (X,Y) par rapport au point central. Le point central est (0,0) et les “extrémités” étant –1 et 1. On obtient donc une valeur comprise entre –1 et 1 pour chacun des axes.

Certaines manettes (la manette 360 notamment) sont équipées de moteurs pour faire vibrer celle-ci lors de certains évènements. Pour cela, on utilisera la méthode statique SetVibration de la classe GamePad.

if (gamepadCaps.HasLeftVibrationMotor && gamepadCaps.HasRightVibrationMotor)
    GamePad.SetVibration(PlayerIndex.One, 0.7, 0.25);

Les valeurs possibles pour chacun des moteurs vont de 0 (aucune vibration) à 1 (vibration maximum).

Un utilitaire disponible sur le site XNA montre plus clairement la gestion de la manette.

  • Conclusion

Vous pouvez maintenant récupérer les informations provenant de l’utilisateur et modifier l’environnement du jeu en conséquence. Cela conclut la première partie des tutoriels 2D de base sur XNA. Les prochains tutoriels auront pour thème les animations, le son, l’IA, les effets 2D et la gestion de contenu avancé (Content Pipeline) pour arriver sur la 3D.

Code Source de ce tutoriel

  • Exercices pour aller plus loin
  1. Changer le système de déplacement clavier/manette afin que les touches gauche/droite fasse tourner le tank et que les touches haut/bas fasse avancer/reculer le tank en fonction de son orientation.
  2. Faire tourner le tank dans la direction du clic de souris (ou du touch) pendant le déplacement (l’avant du tank doit toujours être “face” à sa destination).

La solution sera fournis prochainement.

17/09/2010

[XNA 4] Tutoriel 3 : Affichage de texte

Filed under: .NET, C# 4, Débutant, Jeux vidéos, XBOX 360, XNA — Étiquettes : , , , , , , , — sebastiencourtois @ 13:39

Après avoir appris à afficher et déplacer des images, nous allons apprendre à écrire du texte à l’écran. Pour ce tutoriel, nous partirons de ce projet (Solution des exercices du Tutoriel 2).

  • Création d’une police de caractère (font)

Afin de pouvoir afficher du texte, il faut indiquer quel police de caractères (aussi appelé font), on souhaite utiliser. Pour cela, on ajoute un nouvel élément au projet Content (Les fonts sont généralement stockés dans le projet Content comme l’ensemble des ressources XNA).

xna_tuto3_1

On sélectionne un élément de type “SpriteFont” en indiquant un nom et on clique sur OK.

xna_tuto3_2

A l’instar des images, les fonts ont aussi un assetName visible et modifiable par la fenêtre Propriétés. 

Si l’on ouvre le fichier contenant la police de caractères, on obtient le fichier XML suivant :

<?xml version="1.0" encoding="utf-8"?>
<XnaContent xmlns:Graphics="Microsoft.Xna.Framework.Content.Pipeline.Graphics">
  <Asset Type="Graphics:FontDescription">
    <FontName>Kootenay</FontName>
    <Size>14</Size>
    <Spacing>0</Spacing>
    <UseKerning>true</UseKerning>
    <Style>Regular</Style>
    <CharacterRegions>
      <CharacterRegion>
        <Start>32</Start>
        <End>126</End>
      </CharacterRegion>
    </CharacterRegions>
  </Asset>
</XnaContent>

La balise FontName permet de définir le nom de la police utilisée. Les fonts disponibles sont uniquement des fonts de type TrueType (Liste). La communauté a créé des générateur de font personnalisé (Exemple : FontBuilder). Les plus utilisés sont souvent Arial ou Verdana.

La balise Size indique la taille du texte comme cela se fait dans les suites bureautiques.

La balise Spacing permet d’indiquer si l’on souhaite un espace entre les lettres (valeur en pixel).

La balise UseKerning permet de définir si l’on autorise le kerning. Pour faire simple, le kerning est le fait que deux lettres puissent “se superposer” (voir l’article et cette image qui décrit le kerning).

La balise Style indique si l’on souhaite mettre en gras/italique. Valeurs possibles : Regular, Bold, Italic ou Bold Italic.

La balise CharacterRegions défini les plages de valeurs ascii utilisable par la police (ici de 32 à 126 ce qui correspond au caractères de ‘ ‘ à ‘~’ en incluant les lettres en minuscules et majuscules, les chiffres ainsi que certains signes de ponctuations (cf tableau ASCII). Nous verrons qu’il est possible de rajouter d’autres plages.

  • Chargement de la police de caractères

Une fois défini, il est nécessaire de charger la police de caractères lors du lancement de l’application. Pour cela, on utilise le même principe que pour les textures.

SpriteFont textFont;

protected override void LoadContent()
{
    [...]
    this.textFont = Content.Load<SpriteFont>("MyFont");
}

Rappel : On utilise toujours le AssetName du fichier avec la méthode Load(). On doit donner aussi le type de sortie (SpriteFont pour les polices de caractères).

  • Affichage de texte

L’affichage du texte se déroule dans la méthode Draw() en utilisant le spriteBatch comme pour les textures.

Pour l’exemple, nous allons réutiliser l’exemple du chapitre précédent pour afficher en temps réel les coordonnées du tank, son angle de rotation ainsi que l’angle de rotation de son canon.

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

   string text1 = string.Format("Position du tank : X = {0}   Y = {1}",this.TankPosition.X,this.TankPosition.Y);
   spriteBatch.DrawString(this.textFont, text1, Vector2.Zero, Color.Red);
   string text2 = string.Format("Rotation du tank : {0}", TankRotation);
   spriteBatch.DrawString(this.textFont, text2, new Vector2(0,20), Color.DarkGreen);
   string text3 = string.Format("Rotation du canon : {0}", CanonRotation);
   spriteBatch.DrawString(this.textFont, text3, new Vector2(0, 40), Color.Yellow);

   spriteBatch.Draw(this.tank, TankPosition, null, Color.White, MathHelper.ToRadians(TankRotation), TankOriginPoint, 1.0f, SpriteEffects.None, 0);            
   spriteBatch.Draw(this.canon, TankPosition, null, Color.White, MathHelper.ToRadians(CanonRotation), new Vector2(canon.Width / 2 - 4.0f, canon.Height / 2), 1.0f, SpriteEffects.None, 0);
            
   spriteBatch.End();
   base.Draw(gameTime);
} 

On utilise la méthode DrawString () de spriteBatch. Cette méthode prend 3 paramètres :

  1. Police de caractères (SpriteFont)
  2. Position (en pixel à l’écran)
  3. Couleur du texte.

Le résultat en image :

xna_tuto3_3

  • Si je veux rajouter le ° à coté de l’angle.

Si vous tentez de faire le changement suivant :

string text2 = string.Format("Rotation du tank : {0} °", TankRotation);
spriteBatch.DrawString(this.textFont, text2, new Vector2(0,20), Color.DarkGreen);

Vous allez rencontre l’erreur : Argument Exception : The character ‘°’ (0x00b0) is not available in this SpriteFont. If applicable, adjust the font’s start and end CharacterRegions to include this character. Parameter name: character

Cela est dû au fait que la balise CharacterRegions ne contient pas ce  caractère dans sa liste de caractère disponible. (‘°’ a le code hexa 0xb0 => 176 en décimal). Il suffit de rajouter une range dans le fichier xml pour ajouter le caractère.

<CharacterRegions>
      <CharacterRegion>
        <Start>32</Start>
        <End>126</End>
      </CharacterRegion>
      <CharacterRegion>
        <Start>176</Start>
        <End>176</End>
      </CharacterRegion>
 </CharacterRegions>

Si vous recompilez et lancez l’application, le symbole apparait.

xna_tuto3_4

  • Conclusion

Vous pouvez maintenant écrire du texte à l’écran. Dans le prochain article, nous verrons l’utilisation du clavier/souris/manette XBOX 360 et Touch sur Windows Phone.

Code de ce tutorial

16/09/2010

[XNA 4] Tutoriel 2 : Gestion des images (2D)

Filed under: .NET, Débutant, Windows Phone, XBOX 360, XNA — Étiquettes : , , , , , , , , — sebastiencourtois @ 16:34

Remarque : Ce tutorial fait suite au Tutorial 1 et reprend le projet utilisé dans ce dernier.

Nous allons voir dans ce tutorial, comment charger, afficher et déplacer des images (aussi appelé sprites). Vous trouverez ici les images utilisées pour ce tutorial.

  • Ajout des images au projet

Lorsque vous souhaitez utiliser une image dans un projet XNA (que ce soit en 2D ou en 3D), il est nécessaire de l’ajouter au projet Content associé au projet XNA (Tutorial2DContent dans notre exemple).

xna_tuto2_1

Clic droit sur le projet Tutorial2DContent > Ajouter > Elément existant.

xna_tuto2_2

On sélectionne les fichiers que l’on souhaite ajouter et on clique sur le bouton “Ajouter”. Une fois que les fichiers sont ajoutés, on peut voir leurs propriétés.

xna_tuto2_3

La propriété Asset Name est le nom de l’image que nous utiliserons au sein de l’application. Vous pouvez noter qu’il n’y a pas d’extension. Vous pouvez la modifier si vous le souhaitez.

  • Chargement des images

Une fois que nous avons ajouté les images au projet, nous allons les charger au démarrage de l’application. Cela se fait généralement dans la méthode LoadContent() de la classe Game.

protected override void LoadContent()
{
    spriteBatch = new SpriteBatch(GraphicsDevice);
    //Chargement des deux textures
    this.tank = Content.Load<Texture2D>("tank_body");
    this.canon = Content.Load<Texture2D>("tank_canon");
}

Pour charger des images, il suffit d’appeler la méthode Load de la propriété Game.Content. Il est nécessaire de lui donner le type de données que l’on souhaite charger. Dans notre cas, on souhaite charger une image qui est représenté, dans XNA, par la classe Texture2D. On passe en paramètre  l’Asset Name de l’image à charger (et non pas le nom du fichier).

Le résultat du chargement est stocké dans une propriété de type Texture2D.

//Stockage de la texture du corps du tank
Texture2D tank;
//Stockage de la texture du canon
Texture2D canon;

  • Libération de la mémoire prise par les images (Optionnel)

Bien que .NET soit pourvu d’un Garbage collector nettoyant régulièrement les zones mémoires non utilisés, il est possible de faire le ménage soit même. Ainsi, si l’on souhaite libérer la mémoire prise par ces deux textures, il suffit d’aller dans la méthode UnloadContent de Game et d’appeler les Dispose() sur chacune des textures.

protected override void UnloadContent()
{
   this.tank.Dispose();
   this.canon.Dispose();
}

Rappel : La méthode UnloadContent() est appelée lorsque l’on sort de la boucle de jeu courante.

  • Affichage des images

Maintenant que nous avons chargé nos images, nous allons les afficher. Cela se passe dans la méthode Draw() de la classe Game.

//Position du tank
 Vector2 TankPosition = new Vector2(30, 40);

 protected override void Draw(GameTime gameTime)
 {
     GraphicsDevice.Clear(Color.CornflowerBlue);
     spriteBatch.Begin();
     spriteBatch.Draw(this.tank, TankPosition, Color.White);
     spriteBatch.End();
     base.Draw(gameTime);
 }

On utilise spriteBatch pour dessiner les textures à l’écran. On doit “préparer” spriteBatch avant son utilisation en appelant la méthode Begin() (nous parlerons de ses paramètres optionnels plus loin). On utilise ensuite la méthode Draw() afin d’afficher l’image. Dans sa version la plus simple, Draw comprend 3 paramètres :

  1. L’image à afficher
  2. La position de l’image par rapport au coin haut gauche de l’écran. La position est définie dans une structure Vector2. Afin de simplifier le code, on a créé une variable TankPosition pour stocker et manipuler la position de l’image.
  3. La teinte de l’image. Si l’on souhaite avoir l’image originale sans modification, on met la couleur blanche.

Une fois que l’on a dessiné l’ensemble des images souhaités, on appelle la méthode End() du spriteBatch afin que celui-ci envoie l’ensemble des informations à la carte graphique (ce comportement dépend du mode de spriteBatch choisi… voir plus loin dans cet article …).

  • Déplacement des images

Si l’on souhaite déplacer l’image, il suffit de modifier les données de la variable TankPosition entre chaque appel de la méthode Draw(). Si vous vous rappelez de la structure d’une boucle de jeu XNA, une méthode est appelé avant chaque Draw() ==> Update(). Cette méthode est destinée à faire toutes les tâches non graphiques (qui n’interagisse pas directement avec la carte graphique). Ainsi si l’on souhaite déplacer notre tank d’un pixel vers la droite et d’un pixel vers le bas, on utilisera le code suivant :

protected override void Update(GameTime gameTime)
{
    if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
      this.Exit();

   TankPosition.X += 1;
   TankPosition.Y += 1;
   base.Update(gameTime);
}
  • Système de coordonnées & Origines

Par défaut, l’ensemble des entités 2D de XNA (fenêtres, sprites …) sont définies dans un système de coordonnées cartésienne orthonormé dont l’unité est le pixel.

xna_tuto2_4

Le coin haut gauche de l’entité est l’origine (0,0) et les x sont positif lorsque l’on va vers la droite. Les y sont positif quand on va vers le bas.

Il est important de noter que le point d’origine est le même que ce soit pour la position de l’entité comme pour d’autres transformations comme la rotation. Nous allons voir, dans le paragraphe suivant, qu’il est possible de modifier ce point d’origine.

  • Rotation des images

Nous allons maintenant faire tourner le tank sur lui-même. Pour cela nous allons rajouter une propriété permettant de conserver la rotation

//Rotation en degré du tank
float TankRotation = 30.0f;

Attention : La rotation 0 est l’image tel qu’importée dans XNA. De plus la rotation se fait selon l’axe du point d’origine. Si l’on souhaite faire tourner une image sur elle-même, il est nécessaire de déplacer le point d’origine au centre de l’image (Width/2, Height/2).

Pour réaliser la rotation,nous utilisons une version plus avancée de la méthode Draw du spritebatch :

protected override void Draw(GameTime gameTime)
{
    GraphicsDevice.Clear(Color.CornflowerBlue);
    spriteBatch.Begin();
    spriteBatch.Draw(this.tank,                                  // Texture (Image)
                     TankPosition,                               // Position de l'image
                     null,                                       // Zone de l'image à afficher
                     Color.White,                                // Teinte
                     MathHelper.ToRadians(TankRotation),         // Rotation (en rad)
                     new Vector2(tank.Width/2,  tank.Height/2),  // Origine
                     1.0f,                                       // Echelle
                     SpriteEffects.None,                         // Effet
                     0);                                         // Profondeur
    spriteBatch.End();
    base.Draw(gameTime);
}

Les deux premiers et le quatrième paramètres ont déjà été décrit précédemment. Intéressons-nous aux autres paramètres :

    • Zone de l’image : Il est possible de ne copier qu’une partie de la texture à l’écran. Dans ce cas, on indique un rectangle indiquant la partie de la texture à afficher. Si l’on souhaite afficher la texture en entier, on passe la valeur null.
    • Rotation : Dans ce paramètre, on indique la rotation que l’on souhaite appliquer à la texture. Attention, l’angle de rotation doit être donné en RADIANS. Pour vous aider,  XNA fournir une classe MathHelper avec une méthode statique convertissant les degrés en radians.
    • Origine : Ce paramètre permet d’indiquer le point d’origine de la texture pour l’ensemble des transformations (déplacement, rotation…). Par défaut, il est situé en haut à gauche mais il est possible de le modifier comme indiqué dans notre exemple (le point d’origine de notre exemple se trouve au centre de la texture afin que celle-ci tourne sur elle-même.).
    • Echelle : Il est possible d’agrandir et de réduire la taille de votre texture. La valeur 1 permet de conserver la taille originale.
    • Effet : Ce paramètre permet l’application d’un effet de renversement (renversement vertical ou horizontal).Si vous ne souhaitez pas utiliser ces effets, mettre à SpriteEffects.None.
    • Profondeur : Le dernier paramètre permet d’indiquer la profondeur à laquelle vous souhaitez mettre votre texture. Cela permet de gérer les cas de chevauchement de texture (voir paragraphe suivant).

L’ensemble des méthodes Draw() de spriteBatch sont décrites en détail dans la MSDN.

  • Superposition et transparence

Si nous faisons la même chose avec le canon du tank, on obtient le code suivant :

//Position du tank
Vector2 TankPosition = new Vector2(30, 40);
//Rotation en degré du canon
float CanonRotation = 40.0f;

protected override void Draw(GameTime gameTime)
{
   GraphicsDevice.Clear(Color.CornflowerBlue);
   spriteBatch.Begin();
   spriteBatch.Draw(this.canon, TankPosition, null, Color.White, MathHelper.ToRadians(CanonRotation), new Vector2(canon.Width / 2 - 4.0f, canon.Height / 2), 1.0f, SpriteEffects.None, 0);
   spriteBatch.Draw(this.tank, TankPosition, null, Color.White, MathHelper.ToRadians(TankRotation), new Vector2(tank.Width / 2, tank.Height / 2), 1.0f, SpriteEffects.None, 0);
   spriteBatch.End();
   base.Draw(gameTime);
}

Remarque : Le point d’origine pour le canon contient un –4.0f pour X. Cela provient du décalage entre le centre de la texture du tank et celle du canon. Afin d’avoir un affichage un peu plus réaliste, j’ai décalé légèrement le point d’origine du canon.

Cela semble correct mais lorsque l’on affiche le résultat :

xna_tuto2_5a

xna_tuto2_5b

Canon et Tank correctement placé

Lors de la rotation du canon, une partie de celui ci disparait sous le tank lui même.

Ce problème est du à la façon dont spriteBatch affiche les sprites. Cela peut être défini dans la méthode Begin() grâce au premier paramètre qui est l’énumération SpriteSortMode

Valeur

Description

Deferred

Valeur par défaut et la plus utilisée. Envoi les opérations à la carte graphique lors de l’appel de End(). Cela permet d’utiliser plusieurs spritesBatchs sans risquer d’avoir de conflit au niveau de la carte graphique. Dépend du paramètre profondeur de la méthode Draw.Le premier plan étant 1 et le fond 0.

BackToFront

Affichage des sprites selon le paramètre de profondeur passé par  la méthode Draw. Le premier plan étant 1 et le fond 0.

FrontToBack

Affichage des sprites selon le paramètre de profondeur passé par  la méthode Draw. Le premier plan étant 0 et le fond 1.

Immediate

Affiche les images en écrasant les pixels déjà présent. Ce mode est le plus rapide mais celui qui gère le moins bien les transparences et supperposition ainsi que l’utilisation de multiples spritesBatch.

Texture

Affiche les images dans l’ordre des textures. Ainsi, si plusieurs appels à Draw se font avec la même texture, l’ensemble des appels sera fait en même temps pour gagner du temps en transfert de données vers la carte graphiques.

Pour la documentation originale sur SpriteSortMode : La page MSDN.

Begin peut prendre aussi un autre paramètre pour indiquer comment il doit gérer les cas d’écrasement de pixel (vouloir dessiner un pixel qui a déjà été dessiné par une autre texture). Ce paramètre est de type BlendState et comprend 4 valeurs possibles.

Valeur

Description

AlphaBlend

Valeur par défaut. Fusion du pixel source/destination en tenant compte du canal alpha (transparence).

Additive

Ajoute les canaux RGBA entre les deux pixels

NonPremultiplied

Ajoute les canaux RGB entre les deux pixels sans tenir compte de la transparence

Opaque

La couleur du nouveau pixel écrase celle du tampon.

Pour la documentation originale sur BlendState: La page MSDN.

Pour résoudre le problème que nous avons rencontré, il y a donc deux solutions :

    • Intervertir les deux méthodes Draw()
protected override void Draw(GameTime gameTime)
{
    GraphicsDevice.Clear(Color.CornflowerBlue);
    spriteBatch.Begin();
    spriteBatch.Draw(this.tank, TankPosition, null, Color.White, MathHelper.ToRadians(TankRotation), new Vector2(tank.Width / 2, tank.Height / 2), 3.0f, SpriteEffects.None, 0);            
    spriteBatch.Draw(this.canon, TankPosition, null, Color.White, MathHelper.ToRadians(CanonRotation), new Vector2(canon.Width / 2 - 4.0f, canon.Height / 2), 3.0f, SpriteEffects.None, 0);
    spriteBatch.End();
    base.Draw(gameTime);
}

    • Changer la méthode Begin
protected override void Draw(GameTime gameTime)
{
     GraphicsDevice.Clear(Color.CornflowerBlue);
     spriteBatch.Begin(SpriteSortMode.FrontToBack,null);
     spriteBatch.Draw(this.canon, TankPosition, null, Color.White, MathHelper.ToRadians(CanonRotation), new Vector2(canon.Width / 2 - 4.0f, canon.Height / 2), 3.0f, SpriteEffects.None, 0);
     spriteBatch.Draw(this.tank, TankPosition, null, Color.White, MathHelper.ToRadians(TankRotation), new Vector2(tank.Width / 2, tank.Height / 2), 3.0f, SpriteEffects.None, 0);
     spriteBatch.End();
     base.Draw(gameTime);
}

On obtient un affichage “correct” :

xna_tuto2_6

Remarque : Les petites zones bleues proviennent de mon placement tank/canon qui n’est pas parfait sur pour ces images.

  • Conclusion

Vous savez maintenant charger ,afficher et déplacement un image dans un univers 2D XNA. Dans un prochain post, nous verrons comment déplacer ces images en fonction des entrées de l’utilisateurs (souris,clavier,Manette XBOX 360, Touch Windows Phone). Le prochain post est consacré à l’affichage de texte dans la fenêtre.

Téléchargement du résultat final

  • Exercices pour tester ses compétences
  1. Faire se déplacer le char dans l’écran en le faisant rebondir sur les coins de l’écran.
    • Indice 1 : Attention au point d’origine
    • Indice 2 : Les dimensions de l’écran sont disponibles au travers de graphics.GraphicsDevice.Viewport
    • Indice 3 : Attention au pixel transparent autour du tank
  2. Faire le même exercices en gérant le couple char+canon.

Solution possible

05/05/2009

Introduction à Small Basic en français.

Filed under: .NET, Débutant, Small Basic — Étiquettes : , , , , , , — sebastiencourtois @ 09:21

Après plusieurs semaines de travail, une équipe de MSP a traduit la documentation anglaise de Small Basic en français.

Pour ceux qui ne connaissent pas Small Basic, il s’agit un projet de Microsoft fournissant aux débutants en programmation un environnement simple pour commencer doucement dans ce monde parfois obscur. Avec une syntaxe proche du Visual Basic, ce langage contient de nombreuses classes simplifiées fournissant facilement les fonctionnalités réellement nécessaires aux débutants.

SB

Petit tour de l’équipe qui a réalisé la traduction :

Au passage, un grand merci à Florie Perouze de l’équipe Education de Microsoft France qui nous a permis de réaliser ce projet.

Site officiel Small Basic

Blog officiel Small Basic

Documentation Français

Propulsé par WordPress.com.