Plus....

Beginning Game Development

Part IV – DirectInput

Traduit par Valentin BILLOTTE

Consultez cet article en anglais  

Cet article n’a pas été traduit par Microsoft. Il n’a pas été relu ou vérifié par Microsoft.

Sur cette page

Part IV – DirectInput Part IV – DirectInput
nettoyage de code nettoyage de code
Skybox Skybox
CLASSE Camera CLASSE Camera
Controller les entrées utilisateur Controller les entrées utilisateur
AJOUTER DirectInput AJOUTER DirectInput
Detecter les devices Detecter les devices
Se connecter à uN clavier Se connecter à uN clavier
Se connecter à uNe souris Se connecter à uNe souris
Se connecter à un joystick Se connecter à un joystick
Déterminer les actions de l’utilisateur Déterminer les actions de l’utilisateur
répondre aux actions de l’utilisateur répondre aux actions de l’utilisateur
Conclusion Conclusion

Part IV – DirectInput

Bienvenue dans le quatrième article sur l’initiation à la programmation de jeux. Dans cet article nous allons couvrir la partie de gestion d’entrées de DirectX nommée DirectInput. Avec DirectInput nous pouvons contrôler les joysticks, la souris, ou le clavier.

Avant de commencer, revenons sur les retours effectués par les lecteurs (merci énormément pour vos remarques à propos des précédents articles.

Haut de page Haut de page

nettoyage de code

Pour rendre le développement de notre jeu plus simple et rendre le code plus maintenable, j’ai déplacé une partie du code de la classe GameEngine vers des classes à part comme Camera. Encapsulé les fonctionnalités de la camera dans un objet à part rend le projet plus simple à comprendre et le code plus simple à lire. Ces changement sont dors et déjà pris en compte dans le code qui accompagne cet article.

  1. La classe FrameworkTimer disparait. Son contenu a été ajouté à l’intérieur d’une toute nouvelle classe nommée HiResTimer. L’instruction using pour le namespace Microsoft.Samples.DirectX.UtilityToolkit a donc été supprimée. Pour la version VB la classe FrameworkTimer a été adaptée au VB et la référence vers la librairie sample DirectX supprimée.
  2. J’ai modifié la portion de code consacrée à la création du device dans la classe GameEngine pour la placer à l’intérieur d’une nouvelle méthode nommée ConfigureDevice.
  3. J’ai modifié toutes les portions de code qui utilisent le device dans la méthode OnPaint de la classe GameEngine pour les placer dans une seule et unique méthode nommée Render.
  4. J’ai modifié le code qui gère la caméra pour le placer dans une classe utilitaire a part nommée Camera.
  5. J’ai supprimé les méthodes CreateCrossHairVertexArrayTop, CreateCrossHairVertexArrayBottom,CreateTestTriangle, et CreateTestCube de la classe GameEngine.
  6. J’ai supprimé les usings vers les namespaces System.Collections.Generic, System.ComponentModel, System.Data et System.Text de la classe GameEngine.
  7. J’ai supprimé tous les codes d’expérimentations sur la gestion de la caméra.

En plus de cette maintenance de code hebdomadaire, j’ai ajouté quelques lignes de code pour rendre la portion consacrée à DirectInput plus intéressante.

Haut de page Haut de page

Skybox

L'espace 3D infini que nous avons créé possède un problème : il est infini. Nous n’avons aucun point sur lequel se baser pour s’orienter et aucune idée de direction vers laquelle s’orienter. Nous pourrions créer un grand nombre d’objets 3D complexes afin d’afficher un terrain 3D aussi réel que possible, mais notre jeu serait très lent et un haut degré de réalisme n’est pas vraiment utile pour ce que nous voulons faire. Pour créer une illusion d’horizon et de terrain gigantesque on utilise la technique de la skybox. Le principe est similaire à la Géode, cette salle de cinéma projette une image d’un paysage à 360° autour de nous. Si nous sommes au centre nous avons l’impression d’être immergé dans la scène projetée.

Pour notre jeu, nous allons créer un cube et afficher des textures à l’intérieur. Le sommet intérieur du cube contiendra une texture de ciel, la base, une texture correspondant au sol, et les quatre autres parois contiendrons une image d’horizon et de terrain. Ces textures sont dessinées de manière à ce qu’elles s’imbriquent parfaitement en produisant un effet de paysage alentour réaliste. Pour dessiner parfaitement un paysage avec cette technique nous devons nous assurer d’annuler tout effet de profondeur toute notion de distance afin de pouvoir facilement simuler des proportions gigantesque au cube lorsque nous aurons placé la caméra à l’intérieur. On réalise cela en annulant le Z-Buffering avant d’afficher la skybox et en le réactivant juste après.

Visual C#

_device.RenderState.ZBufferWriteEnable = false;
// draw the skybox here
_device.RenderState.ZBufferWriteEnable = true;

Visual Basic

_device.RenderState.ZBufferWriteEnable = False
'draw the skybox here
_device.RenderState.ZBufferWriteEnable = True

Nous devons de même nous assurer que le joueur ne pourra jamais se trouver proche de la paroi de la skybox auquel cas l’illusion serait visible. On réalise cela en s’assurant que la position de la caméra se trouve toujours au centre de la skybox.

Nous assignons tout d’abord la matrice identité à la matrice monde. Ceci nous assure que les vertices de la skybow ne seront pas déplacée lorsqu’elles seront placées dans le monde. Nous utilisons ensuite la matrice view de la caméra pour spécifier la matrice View de la skybox. Nous aurons ainsi une vue spéciale pour afficher le ciel à l’écran lors de la transformation en 2D et une autre vue pour l’affichage du terrain et de ses objets.

Visual C#

Matrix worldMatrix = Matrix.Identity;
Matrix viewMatrix = cam.View; viewMatrix.M41 = 0.0f;
viewMatrix.M42 = 0.0f; viewMatrix.M43 = 0.0f;
_device.Transform.View = viewMatrix;
_device.Transform.World = worldMatrix;

Visual Basic

Dim worldMatrix As Matrix = Matrix.Identity
Dim viewMatrix As Matrix = cam.View viewMatrix.M41 = 0.0F
viewMatrix.M42 = 0.0F
viewMatrix.M43 = 0.0F
 _device.Transform.View = viewMatrix
  _device.Transform.World = worldMatrix

Le dessin de la skybox suit le même principe que celui explicité dans l’article précédent. Les étapes à suivre pour cela sont les suivantes :

  1. Définir un tableau de vertices PositionNormalTextured pour définir les quatre coins de chacune des faces du cube..
  2. Charger la texture pour chaque face du cube à partir d’un fichier.
  3. Définir les vertices de chacun des faces..
  4. A chaque entrée dans la méthode Render réajuster la skybox.
  5. A chaque Render annuler le Z-buffering.
  6. A chaque Render dessiner les faces du cube.
  7. A chaque Render rétablir le Z-buffering.

Si vous jetez un œil à la méthode RenderFace de la classe SkyBox class, vous noterez que le code est identique à celui utilise pour afficher le cube et le triangle dans l’article précédent..

Visual C#

_device.SetStreamSource ( 0, faceVertexBuffer, 0 );
_device.VertexFormat = CustomVertex.PositionNormalTextured.Format;
_device.SetTexture ( 0, faceTexture );
_device.DrawPrimitives ( PrimitiveType.TriangleStrip, 0, 2 );

Visual Basic

_device.SetStreamSource(0, faceVertexBuffer, 0)
_device.VertexFormat = CustomVertex.PositionNormalTextured.Format
_device.SetTexture(0, faceTexture)
_device.DrawPrimitives(PrimitiveType.TriangleStrip, 0, 2)
Haut de page Haut de page

CLASSE Camera

Une autre modification majeure que j’ai fait au code de l’article précédent a été de déplacer toutes les instructions relatives à l’utilisation de la camera à l’intérieur de la classe Camera. Les valeurs utilisées pour le calcul de la matrice de projection comme le FoV ou le ratio, sont maintenant des propriétés. Des méthodes on été ajoutée pour permettre de déplacer la caméra vers la gauche, la droite, en haut ou en bas. Ces méthodes seront utiles pour nous lorsque nous intégrerons les entrées avec DirectInput.

Maintenant que tout ce qui à trait au graphique pour le jeu est fait, tentons de déplacer le tank pour explorer notre monde.

Haut de page Haut de page

Controller les entrées utilisateur

Le Contrôle les device d’entrées n’est pas aussi amusant que la gestion des graphismes, mais sans lui, pas de jeu. Faire réagir le jeu aux actions de l’utilisateur permet à ce dernier de se déplacer et d’interagir avec l’univers 3D que nous avons créé.

L’API DirectInput permet de contrôler la souris, le clavier, le joystick ou une la manette. Certains jeux permettent même un contrôle à la voix, mais nous somme là dans un monde dans lequel nous n’entrerons pas.

Haut de page Haut de page

AJOUTER DirectInput

La première étape lorsqu’on ajoute un support des entrées utilisateur est d’ajouter une référence vers l’assembly Microsoft.DirectX.DirectInput.dll. L’étape suivant est d’ajouter les instructions using à chaque classe qui utilisent les classes DirectInput.

Haut de page Haut de page

Detecter les devices

Une bonne API est une API consistante et logique pour chacune des fonctionnalités/classes qu’elle abrite. Cela est vrai pour DirectX pour lequel les devices physiques comme les cartes vidéos, les cartes sonores et les devices d’entrées se gère tous par l’intermédiaire d’une classe abstraite Device. Cette classe évite au développeur d’avoir à traiter les spécificités de chaque matériel installé sur la machine du joueur.

Dans le même sens la classe Manager permet aussi d’avoir toutes les informations à propos des adapters et de connaître les possibilités offertes par chaque matériel installé sur la machine et ceci que ce soit pour Direct3D ou pour DirectInput.

Pour obtenir une liste spécifique de devices comme tous les claviers connectés à l’ordinateur, utilisez la méthode GetDevices de la classe Manager. Donnez en paramètre une valeur de l’énumération DeviceClass ou de DeviceType et une de EnumDevicesFlags.

Note: La plupart du temps nous utiliserons le flag EnumDevicesFlags.AttachedOnly pour s’assurer de n’avoir que les devices actuellement connecté à l’ordinateur.

Pour rendre les choses plus difficiles qu’elles ne le sont, la souris est appelée «pointer» dans l’énumération DeviceClass. Vous pouvez utiliser une combinaison de plusieurs drapeau pour ramener plusieurs sortes de devices différents.

Chaque appel à la méthode GetDevices renvoie un objet de type DeviceList. DeviceList contient une structure de type DeviceInstance pour chaque device. La structure DeviceInstance contient des informations à propos de chaque device et notamment le InstanceGuid. Il s’agit d’un identifiant unique pour chaque device qui permet une communication directe.

Note: La présence d’un device dans la DeviceList ne veut pas forcement dire qu’il est actuellement connecté. Vous pouvez utiliser l’InstanceGuid et la méthode GetDeviceAttached pour savoir si le device est branché.

La classe Manager possède une propriété Devices qui contient une DeviceList.

Notez que la structure DeviceInstance n’est pas un device; Elle ne sert qu’à fournir un GUID nous permettant de connecter à un device.

Haut de page Haut de page

Se connecter à uN clavier

Le premier device vers lequel nous allons nous connecter est le clavier. Il s’agit sans doute du matériel connecté à un pc le plus couramment utilisé. Tous les jeux modernes permettent un contrôle au clavier et à la souris dans la mesure où un seul d’entre eux ne permettrait pas de couvrir tous les besoins. Il faut toujours garder à l’esprit qu’il existe des machines comme les tablets pc qui ne possèdent pas de clavier mais des moyens de substitution. Il est donc nécessaire de toujours prévoir des moyens de substitution afin d’élargir le nombre de joueurs susceptibles d’être intéressés par notre jeu.

Les étapes pour l’initialisation d’un Device restent les mêmes :

  1. Instancier un objet de type Device avec le type de device voulu.
  2. Définir le niveau de coopération du device (une autre application pourra t’elle écouter le device en même temps que notre jeu?).
  3. Définir la structure des données renvoyée par le device.
  4. Acquérir une connexion vers le device..
  5. Lancer le device.
  6. Lire le rapport du device pour déterminer les actions effectuées par l’utilisateur.

Suivant notre principe de programmation objet stricte nous commençons par créer une classe Keyboard qui va encapsuler toutes les fonctionnalités liées à l’utilisation d’un clavier et nous donner un point d’accès unique vers celles-ci.

Tout d’abord nous allons créer un objet pour le clavier. Nous faisons cela en utilisant le flag Keyboard de l’énumération SystemGuid. Cela nous permet de nous connecter au clavier par défaut ce qui est plus sécurisé que d’énumérer tous les claviers et d’en choisir un sans savoir lequel prendre.

Visual C#

_device = new Device ( SystemGuid.Keyboard );

Visual Basic

_device = New Device(SystemGuid.Keyboard)

L’étape suivant consiste à définir le niveau de coopération du device. Les valeurs de l’énumération CooperativeLevelFlags indiquent le degré de contrôle de notre application sur un device et quelle liberté nous laissons aux autres applications pour l’utiliser.

L’énumération CooperativeLevelFlags contient cinq valeurs.

  • Exclusive
  • NonExclusive
  • Foreground
  • Background
  • NoWindowsKey

Les valeurs Background et Foreground ne peuvent pas être utilisées en même temps, tout comme les valeurs Exclusive et NonExclusive. L’option Foreground spécifie que nous voulons des retours du device uniquement si la fenêtre que nous avons donnée en paramètre à la méthode SetCooperativeLevel a le focus. L’option Background spécifie simplement que nous voulons toujours les données venant du device. Exclusive indique que nous avons la priorité sur le device alors que NonExclusive non. Même lorsque le drapeau Exclusive est utilise, il est possible de perdre la connexion vers le device, il est donc nécessaire d’utiliser le méthode Poll pour s’assurer que nous sommes toujours en liaison avec ce dernier lorsque nous voulons lire les données liées aux entrées utilisateur. L’option NoWindowsKey peut être combinée avec n’importe laquelle des autres valeurs de l’énumération pour spécifier que nous ne voulons pas que la touche «windows» du clavier soit prise en compte. Cette option est importante parce que la touche «windows» fait perdre le focus à l’application. Si nous sommes en plein écran, le joueur se voit retourner sous sons système d’exploitation.

Pour BattleTank 2005 nous allons combiner les drapeaux Background et NonExclusive afin de perttre aux autres applications de pouvoir continuer a recevoir des messages en provenance du clavier.

Nous allons en plus de ces drapeaux passer la fenêtre qui va être concernées par les données en provenance du clavier.

Visual C#

_device.SetCooperativeLevel
( form, CooperativeLevelFlags.Background | CooperativeLevelFlags.NonExclusive );

Visual Basic

_device.SetCooperativeLev_device.SetCooperativeLevel
(form, CooperativeLevelFlags.Background Or CooperativeLevelFlags.NonExclusive)

L’étape suivante vise à spécifier le format des données que le device doit nous fournir. Nous reviendrons plus en détails sur cette opération plus tard.

Visual C#

_device.SetDataFormat ( DeviceDataFormat.Keyboard );

Visual Basic

_device.SetDataFormat(DeviceDataFormat.Keyboard)

La dernière étape vise à se connecter aux device à l’aide de la méthode Acquire. Une masse de problèmes peut intervenir à ce point, la meilleure chose à faire rester d’encapsuler cette opération dans un block try/catch.

Visual C#

try { _device.Acquire ( ); }
catch ( DirectXException ex )
{ Console.WriteLine ( ex.Message ); }

Visual Basic

Try _device.Acquire()
Catch ex As DirectXException
Console.WriteLine(ex.Message) End Try

Après la connexion au device, nous pouvons lire son état sous la forme d’un tableau de bytes. Les 256 premières valeurs concernent des données en provenance du clavier, les 8 suivantes, concernent la souris et les 32 dernières l’état du joystick. La structure KeyboardState contient les 256 bytes de l’état du clavier au moment de la lecture du device.

Visual C#

private KeyboardState _state;

Visual Basic

Private _state As KeyboardState

Pour lire cet état, nous devons commencer par appeler la méthode Poll. Celle-ci communique avec le matériel pour lui demander son état. Nous copions alors cet état à l’intérieur d’un variable locale (notre variable_state).

Sachant que nous allons effectuer cette opération à chaque frame, j’ai place cette séquence d’instructions à l’intérieur d’une méthode unique de la classe Keyboard nommée Poll. Il nous suffit alors dans la boucle de jeu d’appeler _keyboard.Poll() et d’utiliser la variable qui contient l’état pour analyser quelles sont les touches qui ont été pressées.

Visual C#

try { _device.Poll ( ); _state = _device.GetCurrentKeyboardState ( ); }
catch ( NotAcquiredException )
{
// try to reqcquire the device try { _device.Acquire ( );
}
catch ( InputException iex )
{ Console.WriteLine ( iex.Message ); // could not get the device } }
catch ( InputException ex2 ) { Console.WriteLine ( ex2.Message ); }

Visual Basic

Try _device.Poll() _state = _device.GetCurrentKeyboardState
Catch generatedExceptionVariable0 As NotAcquiredException
Try _device.Acquire() Catch iex As InputException
Console.WriteLine(iex.Message) End Try Catch ex2 As InputException
  Console.WriteLine(ex2.Message) End Try

La dernière étape vise à examiner les données renvoyées pour déterminer les actions effectuées par l’utilisateur.

Nous devons enfin nous assurer de bien libérer le device lorsque nous n’en avons plus besoin en utilisant la méthode Unacquire à l’intérieur de la méthode Dispose.

Visual C#

if ( _device != null ) _device.Unacquire ( );

Visual Basic

If Not (_device Is Nothing) Then _device.Unacquire() End If
Haut de page Haut de page

Se connecter à uNe souris

La connexion à une souris est sensiblement identique à la connexion à un clavier. Les différences résident tout d’abord sur le SystemGuid passé au constructeur de la classe Device, à la structure de données DeviceDataFormat utilisée pour stocker l’état des données et enfin, à la méthode utilisée pour obtenir cet état.

Visual C#

_device = new Device ( SystemGuid.Mouse );
_device.SetDataFormat ( DeviceDataFormat.Mouse );
  private MouseState _state; public void Poll ( )
   { _device.Poll ( ); _state = _device.CurrentMouseState; }

Visual Basic

_device = New Device(SystemGuid.Mouse)
_device.SetDataFormat(DeviceDataFormat.Mouse)
Private _state As MouseState Public Sub Poll()
_device.Poll() _state = _device.CurrentMouseState End Sub

L’utilisation de la souris donne la possibilité de définir une valeur X, Y et Z (non ne déplacez pas votre souris dans l’espace, la valeur Z correspond à la roulette de votre souris). Ces valeurs évoluent dans le temps. Spécifier la propriété AxisModeAbsolute à true renvoie les coordonnées de la souris par rapport aux coordonnées de l’écran, tandis que spécifier false renvoie la différence en pixels des déplacements sur X, Y et Z de la souris depuis le dernier état. Cette propriété est définie sitôt que le device est connecté.

Visual C#

_device.Acquire ( ); _device.Properties.AxisModeAbsolute = false;

Visual Basic

_device.Acquire ( );
_device.Properties.AxisModeAbsolute = false;

Utilisez l’option false si la vitesse de déplacement de la souris dans le temps est un critère important dans le jeu, utilisez true si la position de la souris à l’écran est importante.

Haut de page Haut de page

Se connecter à un joystick

Là encore la connexion vers un joystick est similaire à celle effectuée vers un clavier ou une souris. Toutefois, étant donné qu’il n’y a pas de notion de joystick par défaut, il n’y a pas de SystemGuid correspondant. A la place, nous devons utiliser la méthode GetDevices de la classe Manager, en passant le type GameControl pour DeviceClass et AttachedOnly pour EnumDevicesFlags afin d’énumérer tous les joysticks actuellement connectés au PC.

Visual C#

DeviceList gameControllerList = Manager.GetDevices( DeviceClass.GameControl,
EnumDevicesFlags.AttachedOnly);
 if (gameControllerList.Count > 0)
  { foreach (DeviceInstance deviceInstance in gameControllerList)
   { _device = new Device(deviceInstance.InstanceGuid);
    _device.SetCooperativeLevel(form, CooperativeLevelFlags.Background |
CooperativeLevelFlags.NonExclusive);
     break; }
  }

Visual Basic

Dim gameControllerList As DeviceList
 gameControllerList = Manager.GetDevices(DeviceClass.GameControl,
EnumDevicesFlags.AttachedOnly)
 If (gameControllerList.Count > 0) Then
 Dim deviceInstance As DeviceInstance
  For Each deviceInstance In gameControllerList _device = New Device
(deviceInstance.InstanceGuid)
  _device.SetCooperativeLevel(Form, CooperativeLevelFlags.Background
Or CooperativeLevelFlags.NonExclusive)
   Break() Next End If

L’étape suivante doit spécifier un nouveau DeviceDataFormat et un nouveau type pour la structure de données _state. Au final les données sont rapatriée à l’aide de la méthode Poll.

Visual C#

_device.SetDataFormat ( DeviceDataFormat.Joystick );
private JoystickState _state;
public void Poll ( ) { _device.Poll ( );
_state = _device.CurrentJoystickState; }

Visual Basic

_device.SetDataFormat(DeviceDataFormat. Joystick)
Private _state As JoystickState Public Sub Poll()
_device.Poll() _state = _device.CurrentJoystickState End Sub

Dans BattleTank 2005 nous n’utiliserons pas de joystick, mais vous êtes libre d’utiliser cette possibiltié si vous disposez de ce type de matériel. A noter au passage que DirectX gère parfaitement le force-feedback.

Maintenant que nous avons accès aux différentes formes de matériels d’entrées utilisateur et que nous savons comment rapatrier les données qui leur sont liés, nous avons besoin de savoir comment analyser ces données et réagir en conséquence.

Haut de page Haut de page

Déterminer les actions de l’utilisateur

Chacune des structures de données pour l’état sont des tableaux de bytes. La structure KeyboardState est un tableau de 256 bytes. Chaque byte représente l’état d’une touché sur le clavier et la position du byte dans le tableau correspond à la valeur de l’énumération Key. L’indexeur de renvoie une valeur booléenne. Si nous voulons savoir si l’utilisateur a préssé la touche Echap, nous avons juste à tester si notre tableau d’array, à la position Key.Escape possède la valeur true.

Chaque appel à Poll peut renvoyer les valeurs pour plusieurs touches clavier comme par exemple la combinaison Ctrl+Alt+Delete. DirectInput support jusqu’à cinq touches en même temps. Evidemment il est préférable d’associer une action du jeu à une touché plutôt qu’à cinq.

Visual C#

_state[Key.Escape]

Visual Basic

_keyboard.State(Key.Escape)

La structure MouseState fournit trois propriétés publiques pour les valeurs X, Y et Z et un tableau de 8 bytes par l’intérimédiaire de la méthode GetMouseButtons.

Déterminer les boutons de la souris pressés suit le même principe que celui vu précédemment pour les touches du clavier.

Visual C#

if ( 0 != mouseButtons[0]) Console.WriteLine ( "Primary Button pressed" );

Visual Basic

If Not (0 = _mouse.MouseButtons(0)) Then Console.WriteLine("Fire!") End If

La valeur 0 représente le premier bouton qui peut être le gauche ou le droit suivant la configuration de la souris.

Suivant la valeur de AxisModeAbsolute, les valeurs X, Y et Z renvoie la position absolue ou relative de la souris. Quelque soit AxisModeAbsolute, les valeurs sur l’axe X sont positives à droite et négatives à gauche. Positive vers le haut et négative vers le bas pour l’axe Y. Positive lorsque la roulette est avancée et négative lorsqu’elle est reculée pour Z.

Haut de page Haut de page

répondre aux actions de l’utilisateur

Maintenant que nous pouvons détecter ce que fait l’utilisateur, il est temps de réagit à cela afin de manipuler notre monde.

Nous allons commencer par créer une méthode nommée CheckForInput qui va contenir tout le code lié à l’analyse des actions de l’utilisateur (nous verrons plus tard que ce n’est pas là, la meilleure chose à faire et qu’un système comme l’Action Mapping peut être utilisé pour réduire la taille du code et éviter toute duplication d’instructions). Pour l’heure nous allons modifier le code de BattleTank 2005 pour répondre au déplacement de la souris et déplacer la caméra en conséquence. Notons que cette opération ne déplacera pas la caméra, elle lui permettra jute de déplacer sa vue vers le haut, le bas, la gauche ou la droite. La première étape de cette opération consiste à «Poll» les devices pour obtenir les derniers états pour le clavier et la souris.

Visual C#

_keyboard.Poll ( ); _mouse.Poll ( );

Visual Basic

_keyboard.Poll() _mouse.Poll()

Nous testons ensuite les touches voulues pour réagir en consequence.

Then we test the state for the keys we are interested in and react accordingly.

Visual C#

if ( _keyboard.State[Key.LeftArrow] ) _camera.MoveCameraLeftRight ( -0.5f );
if ( _keyboard.State[Key.RightArrow] ) _camera.MoveCameraLeftRight ( 0.5f );
if ( _keyboard.State[Key.UpArrow] ) _camera.MoveCameraUpDown ( -0.5f );
if ( _keyboard.State[Key.DownArrow] ) _camera.MoveCameraUpDown ( 0.5f );

Visual Basic

If _keyboard.State(Key.LeftArrow)
Then _camera.MoveCameraLeftRight(-0.5F) End If
If _keyboard.State(Key.RightArrow)
Then _camera.MoveCameraLeftRight(0.5F) End If
If _keyboard.State(Key.UpArrow)
Then _camera.MoveCameraUpDown(-0.5F) End If
If _keyboard.State(Key.DownArrow)
Then _camera.MoveCameraUpDown(0.5F) End If

Nous voulons effectuer la meme operation avec la souris :

Visual C#

if ( 0 != ( _mouse.State.X | _mouse.State.Y ) )
{ _camera.MoveCameraLeftRight ( _mouse.State.X / 10 );
_camera.MoveCameraUpDown ( _mouse.State.Y / 10 ); }

Visual Basic

If Not (0 = (_mouse.State.X Or _mouse.State.Y)) Then
_camera.MoveCameraLeftRight(_mouse.State.X / 10)
_camera.MoveCameraUpDown(_mouse.State.Y / 10) End If

Vous pouvez ajuster les méthodes MoveCameraLeftRight et MoveCameraUpDown pour rendre les mouvements de la camera plus rapides ou plus lents.

La dernière étape ici consiste à ajouter la clé Echap pour permettre de quitter l’application :

Visual C#

if ( _keyboard.State[Key.Escape] ) { Application.Exit ( ); }

Visual Basic

If _keyboard.State(Key.Escape) Then Application.Exit() End If

En plus de déplacer le regard de la camera, nous voulons aussi la déplacer elle-même afin de simuler le déplacement du tank. Le seul problème vient du fait que nous n’avons aucun point de repère auquel se référer pour avoir une impression de mouvement (nous affichons notre skybox en dehors de toute impression de distance en étant toujours au centre de celle-ci). Afin de contourner ce léger problème, et en attendant d’ajouter des unités dans le prochain article, nous allons simplement écrire la position courante de la caméra dans la console.

Visual C#

if ( _keyboard.State[Key.W] ) _camera.MoveCameraPosition ( 10, 0, 0 );
if ( _keyboard.State[Key.S] ) _camera.MoveCameraPosition ( -10, 0, 0 );
if ( _keyboard.State[Key.A] ) _camera.MoveCameraPosition ( 0, 10, 0 );
if ( _keyboard.State[Key.D] ) _camera.MoveCameraPosition ( 0, -10, 0 );
if ( oldX != _camera.X ) {
Console.WriteLine ( _camera.X + ", " + _camera.Y ); oldX = _camera.X;
}

Visual Basic

If _keyboard.State(Key.W)
Then _camera.MoveCameraPosition(10, 0, 0) End If
If _keyboard.State(Key.S)
Then _camera.MoveCameraPosition(-10, 0, 0) End If
If _keyboard.State(Key.A)
Then _camera.MoveCameraPosition(0, 10, 0) End If
If _keyboard.State(Key.D)
Then _camera.MoveCameraPosition(0, -10, 0) End If
If Not (oldX = _camera.X)
Then Console.WriteLine(_camera.X & ", " & _camera.Y)
oldX = _camera.X End If

La dernière pièce à ajouter dans notre contrôle des actions du joueur est l’écoute des boutons de la souris. Décidons dès à présent que le bouton par défaut de la souris provoque un tir du tank. Nous ajouterons bien d’autres actions et possibilités plus tard, pour l’heure, cette action ne provoquera qu’un «fire!» sur la console.

Visual C#

if ( 0 != _mouse.MouseButtons[0] ) Console.WriteLine ( "Fire!" );

Visual Basic

If Not (0 = _mouse.MouseButtons(0)) Then Console.WriteLine("Fire!") End If;

La gestion des actions utilisateur est terminée. Comme je l’ai mentionné précédemment il y’a de meilleures façon de faire, ce que nous avons fait ici a le mérite d’être simple à comprendre et rapide à développer. Nous noterons que quelques fois, une seule action provoque deux mouvements; cela est simplement du au fait que nous laissons le bouton pressé assez longtemps pour être pris en compte dans deux boucles de jeu. Ce problème sera corrigé dans le prochain article.

Haut de page Haut de page

Conclusion

Encore une fois ou je n’ai pas eu la place de tout expliquer et tout faire en un seul article ! Mais j’espère que je vous ai fourni assez de travail pour que vous puissiez patienter jusqu’au prochain article avec de nombreuses expérimentations possibles. Nous continuerons quoi qu’il en soit à améliorer à chaque article notre jeu, plutôt que de le faire en une seule passe: c’est là le principe du développement avec la méthode Agile.

Nous savons maintenant nous déplacer dans notre monde, c’est une étape très excitante, notre prochain objectif vise à ajouter des unités et des objets 3D à notre monde qui seront immobile ou mobile, nous ferons aussi la détection de collision. Nous affinerons le regard de la caméra en affichant à l’écran que les objets situés dans le frustum. Enfin, la mire que nous avons vue précédemment fera son grand retour par l’intermédiaire d’une classe qui lui sera spécifiquement dédiée.

D’ici là, joyeux développements!

Haut de page Haut de page Précédent 4 sur 7 Suivant