Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

.NET

Using XNA Input for Controllers


Digital Buttons

The Xbox 360 Controller has 14 (accessible) digital buttons. The 10 most obvious digital buttons are the A, B, X, Y, Start, Back, left shoulder, and right shoulder buttons. The four directions of the DPad are actually four separate digital buttons (one for each direction), and the left and right thumbsticks can be pressed, each behaving as a digital button. Digital buttons have only two states_pressed and released -- so they can be represented with Boolean values in your code. The following code demonstrates how you would see if player one is pressing the A button on his controller.

// Poll the current controller state for player one
GamePadState padState1 = GamePad.GetState(PlayerIndex.One);
// make sure the controller is connected
if (padState1.IsConnected)
{
  if (padState1.Buttons.A = = ButtonState.Pressed)
  {
     // player one is pressing the A button
  }
}

Analog Buttons

Unlike their digital siblings, analog buttons can report a range of values. The Xbox 360 Controller has two triggers on the back side of the controller. The state of each trigger is represented by a float, ranging from 0.0f (not pressed) to 1.0f (fully pressed). The controller also sports two directional thumbsticks. Each thumbstick has an x- and a y-axis. Each axis is represented by a float ranging from -- 1.0f to 1.0f. For the x-axis, -- 1.0f indicates that the player is pressing the stick fully to the left, 1.0f indicates that the player is pressing the stick fully to the right, and 0.0f indicates that the stick is not being used at all. Similarly for the y-axis, -- 1.0f represents down, 1.0f represents up, and 0.0f represents no action.

The following code demonstrates how you would see if player one is using the left thumbstick on his controller.

// Poll the current controller state for player one
GamePadState padState1 = GamePad.GetState(PlayerIndex.One);
// make sure the controller is connected
if (padState1.IsConnected)
{
  if (padState1.ThumbSticks.Left.X != 0.0f)
  {
    // player one is directing the left thumbstick to the left or right
  }
  if (padState1.ThumbSticks.Left.Y != 0.0f)
  {
    // player one is directing the left thumbstick up or down
  }
}

When processing analog input from the thumbsticks, there's a concept known as "dead zone processing" that you should be aware of. There are minor variances in manufacturing from controller to controller; and over time, movable parts can wear with use. When at rest, thumbsticks will almost always be slightly off center. To account for this, the GetState method automatically disregards values that are below a certain threshold. That threshold is known as the dead zone. If the dead zone weren't taken into account, you would see what's commonly referred to as "drift" in your game -- phantom user actions, like moving left even though you're not pressing any buttons.

The overloaded version of the GetState API provides three methods of dead zone processing, each represented by a member of the GamePadDeadZone enumeration.

  • IndependentAxes -- The X and Y components of the thumbstick position are processed against the dead zone independently. This is the default behavior of the API if you don't identify a specific dead zone processing method. For most applications, this is the best, general-purpose processing mode.
  • Circular -- The X and Y components of the thumbstick position are combined before processing the dead zone. In some applications, this will provide better control.
  • None -- The raw values reported by the controller are returned to your game, and you can process the dead zone using your own logic.

Vibration

It's amazing how adding simple little details to a game can make it so much more immersive. Vibration effects are an effective way to draw your player into the experience. When his car hits a wall, or a grenade explodes just a few feet away, or he's just fallen to his death from a high-rise apartment complex, shake the controller to provide tactile feedback.

The Xbox 360 Controller has two vibration motors. The left is a low-frequency rumble motor, and the right is a high-frequency rumble motor. Each motor can be activated independently of the other. And each motor supports varying speeds. You can turn the motors on and off, and adjust their speeds, using the SetVibration method of the GamePad class. The following snippet demonstrates how you would enable the vibration motors.

// Poll the current controller state for player one
GamePadState padState1 = GamePad.GetState(PlayerIndex.One);
// make sure the controller is connected
if (padState1.IsConnected)
{
  if (padState1.Buttons.A = = ButtonState.Pressed)
  {
     // shake the controller if the A button is pressed
     GamePad.SetVibration(PlayerIndex.One, 1.0f, 1.0f);
  }
else
{
    // otherwise, disable the motors
    GamePad.SetVibration(PlayerIndex.One, 0f, 0f);
  }
}

(The preceding example simply set each motor to its maximum speed, but you can create all sorts of effects by combining various motor speeds and varying the settings over time. Imagine enabling and disabling the motors in rapid succession to simulate riding over a gravel road or firing a machine gun. Or think about using the low-frequency motor to provide constant, pulsing ambient feedback when the player enters a room filled with humming alien technology.)

Wrapper Class

It's a good idea to wrap the GamePad and GamePadState functionalities within your own custom helper class. That way, you can make global changes to how your game processes input by changing one source code file. Imagine that you've written a game that uses the controller. This game has several types of levels_ each programmed as a separate C# class and each accessing the controller via the XNA Framework's GamePad class. After play testing, you decide to provide an option so that the player can reverse the controls for looking up and down (a common option in most first-person shooter games).

Without the wrapper class, you'll need to edit and test every class that directly accesses the controller APIs. With the wrapper class, you edit one source code file, and the change is inherited by all your custom C# game classes that use it. Of course, you'll also want to provide a way to temporarily return to your default controller mappings for menus, but there is great benefit in centralizing your controller logic.

Let's consider another scenario. Imagine that you've written your game solely for the Xbox 360 game console. When you're done writing it, you decide that you would also like to release it as a Windows game. Not every Windows gamer will have an Xbox 360 Controller connected to his PC, so you decide to add keyboard support. Touching every game screen that accepts controller input will be a pain. You don't want to punish the Windows gamers with Xbox 360 Controllers by simply replacing your controller logic with keyboard logic, so you'll need to make sure that your game logic gracefully combines input from both sources. If you're using a wrapper class, you can intercept keyboard input, map it to controller input, and inject phantom button presses into the controller state that your game uses.

If you do decide to write your own custom wrapper to gather user input, you should be aware of the fact that the GamePadState structure contains a handy little member named PacketNumber that will let you know if the controller state has changed since the last time you polled it. Many times, there will be relatively long spans where the player is pressing the same button or combination of buttons. In a racing game, the player may be on a straightaway, pressing the accelerator all the way in. In a first-person shooter, the player may be crouched in a corner, waiting to snipe one of his buddies. On a pause screen, the player has likely put the controller down and isn't pressing anything.


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.