02 janv. 2008

Exploration de XNA : s'amuser avec les gamepad

Nous continuons notre série sur XNA en parlant maintenant du GamePad, ce magnifique ustensile livré en standard avec la XBox 360 et vous permettant de contrôler celle-ci. Mais que les amateurs de jeu PC ne s'y trompent pas: grâce en est rendue à la politique commerciale de Microsoft, car le GamePad est aussi disponible pour PC.

Logo XNA [Télécharger Visual C# 2005 Express Edition] [Télécharger XNA Game Studio 2.0] [Télécharger le Service Pack 1 pour VC# 2005 EE] [TorqueX, de GarageGames.com] [XNA Resources] [Forum MSDN XNA Game Studio] [GameDev.Net - Plenty of 1s and 0s]

Bien, la souris, c'est marrant quelques minutes, mais ça ne marche pas lorsque le programme fonctionne sur une console XBox 360. Sur une console, le principal système permettant les entrées utilisateur reste le contrôleur de la XBox, le GamePad (ou pad). Et bien entendu, XNA propose les interfaces et types nécessaires à l'utilisation du GamePad - non seulement sur la console, mais aussi sur PC, grâce à la version Windows de ce contrôleur (disponible en version filaire et sans fil[1]).

On peut se poser la question de l'intérêt d'avoir un GamePad connecté à un PC Windows. Outre le fait que le contrôleur reste relativement simple d'utilisation, il permet aussi de tester la jouabilité de votre jeu XBox 360 sans avoir à télécharger celui-ci sur la console. Il en résulte un gain de temps non négligeable pendant le cycle de développement.

Mode immédiat, le retour...

Bien évidemment, et comme précisé dans l'article précédent, les acquisitions en provenance du GamePad sont immédiate - c'est à dire qu'on récupère l'état actuel du contrôleur, et non pas l'historique de ce qui s'est passé depuis la dernière lecture. Cela a son importance, notamment si votre jeu devient plus lent : dans ce cas, vous pouvez manquer des actions utilisateurs, donnant à celui-ci l'impression que votre jeu ne traite pas correctement ses décisions. Ce problème devient particulièrement important dès lors que vous souhaitez gérer des combinaisons de touches - par exemple pour déclencher les coups spéciaux dans un jeu de combat. Un joueur expérimenté peut effectuer des combinaisons de touches très rapidement - mais si vous perdez ne serait-ce qu'une seule touche intermédiaire, il est plus que probable que ce joueur aura alors à cœur de vous maudire sur trois générations.

Récupération de l'état courant du pad.

La classe Microsoft.Xna.Framework.Input.GamePad, qui permet de récupérer l'état d'un pad particulier, définit 3 méthodes statiques. Chacune d'entre elle prends en paramètre une énumération du type Microsoft.Xna.Framework.Input.PlayerIndex, qui peut prendre la valeur PlayerIndex.One, PlayerIndex.Two, PlayerIndex.Three ou PlayerIndex.Four. Le framework permet ainsi de gérer jusqu'à 4 GamePad en même temps.

  • GetCapabilities(PlayerIndex playerIndex) permet de récupérer une structure du type GamePadCapabilities. L'instance récupérée peut être ensuite analysée pour déterminer les capacités du pad en question.
  • SetVibration(PlayerIndex playerIndex, float leftMotor, float rightMotor) permet de changer la vitesse de rotation des deux moteurs du pad (si le pad le supporte) renvoie un booléen mis à true si la requète a été traitée correctement. Pour arrêter la rotation sur un des moteurs, il suffit d'appeler la fonction et de lui passer une vitesse nulle (0.0f) pour le moteur sélectionné. Attention : la vitesse de rotation d'un moteur ne change pas tant que SetVibration() n'est pas appelée de nouveau.
  • Enfin, GetState() renvoie une structure GamePadState qui contient l'état courant du GamePad. Cette fonction est surchargée et existe sous deux formes:
    • GamePad.GetState(PlayerIndex, GamePadDeadZone) permet de récupérer l'état d'un GamePad en spécifiant la façon dont la zone morte (Dead Zone) doit être interprétée.
    • GamePad.GetState(PlayerIndex) est la forme simple. Elle correspond à la fonction précédente appelée avec GamePadDeadZone.IndependentAxes.

Une zone morte ?

J'en entends déjà quelques un qui s'écrient : "ouh là là: qu'est-ce donc encore que cette histoire de Dead Zone ?".

Les GamePad et autres joystick sont des périphériques mécaniques et qui dit mécanique dit "avec une certaine précision". Lorsqu'on manipule la manette analogique, un signal électrique est généré et convertit en signal numérique afin d'être interprété par le système. Le problème est que le manque de précision mécanique mêlé aux autres caractéristiques mécaniques du périphérique font que lorsque la manette est au repos, un signal électrique peut être généré quand même, provoquant une série d'acquisition là ou le joueur s'attend à n'avoir aucune réaction du jeu. Afin de palier à ce problème, on définit une zone appelée zone morte : si la manette est dans cette zone morte, on écarte toutes les entrées qui pourrait être acquise.

Il y a deux sortes de zones mortes :

  • GamePadDeadZone.IndependentAxes: une croix qui couvre les axes du manche (|x| < Kx ou |y| < Ky). Des petits déplacement autour de x=0 ou y=0 n'auront pas d'effet. Ce type de paramétrage convient bien à un Shoot'em up, ou l'on doit différentier les positions sur le mode "je vais à droite ou je vais à gauche". Par contre, cela ne convient pas à un jeu ou l'on a besoin d'un contrôle un peu plus fin : la manette analogique est effectivement séparée en 4 quadrants séparés par une bande certes fine, mais présente. De fait, la distance du point courant par rapport au centre du pad n'a que peu d'intérêt puisque dès qu'on entre dans une de ces bandes, cette distance est faussée par le fait qu'on considère une des coordonnées comme étant nulle.
  • GamePadDeadZone.Circular un disque autour de la position neutre (x² + y² < K²). Il faut alors s'éloigner suffisament de la position neutre pour voir le système réagir. Ce type d'interaction corresponds bien à un jeu de plateforme ou le moindre déplacement du pad doit être traduit par une déplacement du personnage à l'écran. On peut alors prends en compte non seulement la direction choisie par le joueur mais aussi la distance par rapport au centre du pad.

Il est bien évidemment possible de spécifier une zone morte inexistante (de manière à implémenter son propre traitement) en spécifiant GamePadDeadZone.None.

Mais, et cet état...

On y vient, on y vient.

La structure GamePadState renvoyée par GamePad.GetState() définit les propriétés suivantes :

  • GamePadState.IsConnected : ce booléen est à true si la manette correspondante est connectée au système. On peut ainsi vérifier la présence de manette en temps réel.
  • GamePadState.Buttons nous donne l'état des boutons (A, B, X, Y, Start, Back, les 2 bumpers (gauche et droit) et les deux sticks). Chacun de ces boutons peut être dans l'état ButtonState.Pressed ou ButtonState.Released.
  • GamePadState.DPad nous donne l'état des boutons unidirectionnels (le Directional Pad, ou DPad). Au plus 2 directions adjacentes parmi les quatre directions possibles peuvent être à l'état ButtonState.Pressed, les autres restant à l'état ButtonState.Released.
  • GamePadState.Triggers renseigne sur l'état des gachettes (triggers) droite (Triggers.Right) et gauche (Triggers.Left). Les triggers sont des variables flottantes codées de 0 à 1. 1 correspond au cas ou le trigger est totalement enfoncé.
  • Enfin, GamePadState.ThumbSticks nous donne l'état des deux manches analogiques droit (GamePadState.ThumbSticks.Right) et gauche (GamePadState.ThumbSticks.Left). Cette information nous est donnée sous la forme d'une structure Vector2. On peut donc récupérer les coordonnées X, Y et la distance par rapport à la position neutre de la manette de pouce.

Et ça s'utilise comment tout ça ?

Et bien, ça s'utilise très simplement - comme les autres entrées utilisateur, que ce soit le clavier ou la souris. Le principe consiste à vérifier l'état des pad dans la méthode Game1.Update() et d'effectuer les traitements basés sur l'état des boutons et autre manettes de pouce.

On verra dans les articles subséquents comment généraliser le système de capture d'entrée de manière à laisser l'utilisateur les personnaliser.

Conclusion

Cet article est court, mais bref[2]. A noter que le site XNA Creators Club offre en téléchargement des fichiers graphiques librement utilisables représentant les boutons des manettes XBox 360 ou la manette elle même. Le but est bien évidemment de vous en servir pour afficher les contrôles de votre jeu ou programme à l'écran, afin d'en faciliter la prise en main.

A bientôt !

Notes

[1] pendant que j'y suis, je précise que j'utilise cette version du contrôleur.

[2] ah! quel humour!

Ajouter un commentaire

Les commentaires peuvent être formatés en utilisant une syntaxe wiki simplifiée.

Fil des commentaires de ce billet