EDIT : Cet article a été mis à jour pour XNA 4.0
Objectifs :
Cette partie est dédiée à tout ce qui peut remplir la méthode Update() : collisions et déplacements en particulier.
Sommaire :
- Installation et découverte
- Hello World
- Affichage d’images, de sprites, de backgrounds
- Déplacements, collisions, rotations
- >>>>>Entrées / sorties
- Squelette générique d’un jeu 2D
XNA : Gestion des entrées / sorties pour un jeu
C’est bien beau d’avoir un cactus qui se balade tout seul sur l’écran, mais c’est quand même un jeu qui l’on souhaite produire. Donc quelque chose qui propose un minimum d’interaction avec l’utilisateur.
XNA est prévu pour PC et Xbox 360 et est développé par Microsoft, il n’est donc pas surprenant que le clavier, la souris et le GamePad xbox360 soit supporté nativement (ce dernier pouvant être relié à un PC). Nous ne parlerons pas ici de l’utilisation du tactile pour Windows Phone 7 (mais certains principes restent vrais !)
Si par contre vous voulez gérer des manettes autres, branchées sur le port USB par exemple, là c’est une autre histoire… XNA ne propose rien pour cela.
EDIT : Mais ce n’est pas forcément compliqué ! Merci à J-F. Sébum de Canard PC pour son code, disponible ici :
-> http://www.irrlicht.fr/forum/viewtopic.php?id=64
Vous y trouverez un bout de code permettant dé gérer sous Windows toute sorte de « bâtons de joie » (joysticks et joypads). Je peux également vous envoyer un exemple d’utilisation (de TGPA) sur demande.
Gardez toujours à l’esprit que nous nous intéressons ici uniquement à ce qu’XNA propose, et donc par extension ce qu’il est possible de faire sur Xbox et Windows Phone. Sur PC vous avez accès à toute l’API .NET et il est donc possible de tout faire.
Le clavier
La gestion du clavier en XNA est à la fois simple et catastrophique. Simple car il suffit de récupérer un objet pour avoir accès à toutes les touches enfoncées / relevées, etc.
1 2 3 4 5 6 | //Entrée joueur : clavier KeyboardState keyboard = Keyboard.GetState(); if (keyboard.IsKeyDown(Keys.Left)) { //... } |
L’énumération Keys contient toutes les touches que vous pouvez trouver sur un clavier actuel, même les touches de contrôle de médias comme la gestion du volume.
Difficile de s’étendre longtemps sur l’utilisation donc. Par contre si vous voulez faire de la saisie de texte (le nom du joueur par exemple), alors là bon courage ! XNA ne gère pas de composant tout magique comme un champ de texte, il va falloir vous créer le votre, et gérer aussi bien l’ajout de caractères que les retours arrières, etc. J’imagine que c’est trouvable tout fait sur Internet mais c’est quand même dommage de ne rien avoir par défaut.
La souris
Je serai bref : la souris se gère comme le clavier :
1 2 3 4 5 6 | //Entrée joueur : souris MouseState mouse = Mouse.GetState() if (mouse.LeftButton == ButtonState.Released) { ... } |
MouseState possède comme propriétés les différents boutons que vous pouvez espérer trouver pour une souris normale.
Petit truc qui peut servir, il est facile de forcer le curseur de la souris à se placer à une position précise de l’écran grâce à:
1 | Mouse.SetPosition(x,y) |
;
Manette Xbox 360
Le périphérique le mieux géré à mon avis par XNA est bien la manette de Microsoft. Pas besoin de chercher pourquoi, mais il faut admettre que ce contrôleur est plutôt bien. XNA permet de gérer jusqu’à 4 manettes en même temps : idéal pour un jeu multijoueurs en écran splitté.
Sans surprise la récupération des informations pour une manette est similaire aux autres périphériques :
1 | GamePadState pad = GamePad.GetState(PlayerIndex.One); |
Notez que PlayerIndex est un simple entier valant entre 0 et 3. Il correspond au numéro du joueur qui tient la manette.
pad contient :
- Les flèches directionnelles : Dpad
- Les boutons de la manette, et des méthodes isButtonDown/Up() pour connaître leur état
- Le joystick gauche : ThumbSticks.Left
- et droite : ThumbSticks.Right
- Les gachettes : Gauche et droite respectivement Triggers.Left et Triggers.Right
Que demander de plus ?
Les vibrations bien sûr !
Elles sont ajustables grâce à :
1 | GamePad.SetVibration(PlayerIndex.One, 1.0f, 1.0f); |
Où 1.0f est une valeur arbitraire qui peut être ajuster pour correspondre à la sensation souhaitée. Si vous essayez cette méthode, vous remarquerez que les vibrations ne s’arrêtent jamais : c’est normal ! Il faut soi-même la faire décroître en ré-appelant SetVibration(..) tout en faisant décroître la valeur de la secousse.
Une bonne manière de gérer plusieurs périphériques
Laisser le choix des armes à son joueur vous fera toujours gagner quelque points de sympathie avec ce dernier (Même si ce n’est applicable que sur PC). Une bonne manière de gérer plusieurs entrées de manière très simple est la suivante :
- Vous contrôlez les différents états des périphériques
- En fonction des boutons / directions, vous mettez des variables booléennes à vrai
- En fonction de ces variables, vous effectuez des actions
Soit, pour mieux comprendre :
1 2 3 | KeyboardState keyboard = Keyboard.GetState(); MouseState mouse = Mouse.GetState(); GamePadState pad1 = GamePad.GetState(PlayerIndex.One); |
1 2 3 4 5 6 7 8 9 10 | bool tirer = false; if (keyboard.IsKeyDown(Keys.Space)) tirer = true; if (mouse.LeftButton == ButtonState.Pressed) tirer = true; if (pad1.IsButtonDown(Buttons.A)) tirer = true; >if (tirer) { ///... } |
On peut encore factoriser ça mais c’est pour que le code reste lisible. Vous séparez ainsi l’acquisition de l’action du joueur par un contrôleur et le traitement de cet action.
Mais il y a un problème avec cette solution : tant que le bouton est appuyé, la condition est vraie. Donc l’action tirer sera ici vraie pendant plusieurs secondes, ce qui signifie plusieurs centaines de frames !
Autrement dit le chargeur de votre arme va se vider bien vite… il va falloir ajouter un délai et/ou affiner la détection d’appui des touches.
Première idée : le délai
Déclarez dans votre classe (pas dans la méthode donc) :
float tirerAttente = 0f;
Dans Update() :
…
1 2 3 4 5 | if(tirerAttente > 0f) tirerAttente -= (float)gameTime.ElapsedGameTime.TotalMilliseconds; if(tirer && tirerAttente <= 0f) { tirerAttente = 1500f; //1,5 sec d'attente entre deux tirs ... } |
Le tir n’est donc possible au mieux que toutes les 1500ms, peut importe ce que le joueur fait avec sa manette / son clavier / son téléphone.
Deuxième idée : affiner la détection
Le plus simple (quoique jugé non professionnel, ne me demandez pas pourquoi c’est ce que l’on m’a dit pour TGPA) est de détecter le relâchement d’une touche.
Il suffit à chaque frame de sauver l’état précédent des périphériques.
Déclarez de nouvelle variable dans votre classe :
1 2 3 | KeyboardState precKeyboard; MouseState precMouse; GamePadState precPad1; |
Et ajouter à la fin de votre méthode Update() :
1 2 3 4 | ... precKeyboard = keyboard; precMouse = mouse; precPad1 = pad1 ; |
Grâce à cela, vous pouvez désormais tester l’appui puis le relâchement d’une touche, et pas seulement l’appui.
1 2 3 | if ((precKeyboard.IsKeyDown(Keys.Space)) && (keyboard.IsKeyUp(Keys.Space))) tirer = true; if ((precMouse.LeftButton == ButtonState.Pressed) && (mouse.LeftButton == ButtonState.Released)) tirer = true; if ((pad1.IsButtonDown(Buttons.A)) && (pad1.IsButtonUp(Buttons.A))) tirer = true; |
Bien sur cela est à adapter à vos besoins.
Les sorties
Les sorties possibles ne sont pas l’intérêt principal d’un jeu vidéo. Sauf pour le partage de score, et de quelques autres données par Internet, on ne peut pas dire que cet élément soit crucial pour le jeu.
Outre l’écran, il est possible (même sur Xbox) de lire/écrire des fichiers (texte, binaires ou XML).
Il est aussi possible d’envoyer / recevoir des données par Internet, mais n’ayant jamais traité cette partie je vous invite à chercher par vous-mêmes.
Les fichiers
Important pour la Xbox/WP7 : pour accéder aux fichiers stockés dans votre solution, comme vous ne pouvez pas savoir où ils sont stockés, il vous faut utiliser une classe qui le sait :
1 | System.IO.Stream stream = TitleContainer.OpenStream("Nom de fichier"); |
Une fois ce flux ouvert vous pouvez le lire, par exemple avec le parseur XML détaillé plus loin.
Pour gérer vos sauvegardes, je vous conseille la librairie EasyStorage. Une discussion sur ce sujet vous permettra de mieux comprendre comment l’utiliser, ici :
http://www.dev-fr.org/index.php/topic,5227.msg49119/topicseen.html
Les fichiers textes
Idéal pour lire des fichiers contenant du texte (sous-titres, descriptions, format de niveau).
On utilisera les classes StreamReader / StreamWriter de l’assembly System.IO.
Exemple pour la lecture :
1 2 3 4 | StreamReader sr = new StreamReader(chemin); while(String ligne = sr.ReadLine()) { //Traitement de la ligne }; |
Les fichiers binaires
Pour lire et sauver des objets instanciés, il est possible de les stocker dans un fichier.
Il suffit d’utiliser les classes BinaryReader / BinaryWriter de l’assembly System.IO.
Même principe que pour le fichier texte.
Les fichiers XML
Le framework 4.0 fournit une nouvelle classe pour le XML qui rend très facile le parsage.
Pour lire un fichier XML :
1 | XElement element = XElement.Load(TitleContainer.OpenStream(filename)); |
Vous pouvez ensuite rechercher des éléments très simplements, un peu comme avec XPath :
1 | XElement e = element.Element("monElement"); |
L’élément récupéré peut lui aussi être exploré de la même manière, et ainsi de suite. Pour accéder à un attribut (ici sa valeur en plus) :
1 | e.Attribute("monAttribut").Value |
Conclusion
Vous avez peut-être l’impression que je suis allé trop vite, et, oui, je pense aussi que je ne me suis pas attardé. Il existe une tonne d’aide pour la gestion des fichiers, qui est déjà très simplifiée en .NET, donc plutôt que de vous expliquer la roue je préfère me contenter de vous la montrer.
Vous aurez aussi compris que la gestion des contrôles en XNA est très simple et agréable, même si cela pourrait être encore mieux (gestion d’un délai entre deux appuis de touches, gestion automatique de l’atténuation des vibrations, etc).
A la demande de LapinouFou le prochain article devrait être sur la structure du code pour un petit jeu telle que je la conçois, même si ce n’est qu’une possibilité parmi une infinité.
Annexe
Le code source de cette partie combiné à la partie précédente est disponible ici :
=> http://nopaste.info/6d57f48de4.html



Ping : Didacticiel XNA : Partie 1 – Installation et découverte | :: Valryon.blog ::