This article details how to use the XNA Framework Input API to take user input from an Xbox 360 Controller and apply it to the model displayed in Tutorial 1.
For more information on using a keyboard to control the model, see Optional Step: Controlling the Ship With Keyboard Input.
The Complete Sample
The code in this tutorial illustrates the technique described in the text. A complete code sample for this tutorial is available for you to download, including full source code and any additional supporting files required by the sample.
Step 1: Connect Your Xbox 360 Controller
The first step in this tutorial is to make sure you can provide some input to your game. We'll use the Xbox 360 Controller. Designed for use with both a Windows computer and an Xbox 360 console, the controller features many analog and digital inputs, as well as vibration motors to give feedback to the user.
This tutorial uses only the Xbox 360 Controller, but there are more ways to take input: the XNA Framework has support for keyboard and mouse devices. Mouse devices are supported only on Windows, not on Xbox 360. For more information on the different input types, see Input Overview.
For now, connect your Xbox 360 Controller and get ready to code!
Step 2: Create Variables to Turn and Move the Model
We want our ship to move around on the screen. To do that, we'll need to create some variables to track the position and orientation of our model in the world.
Fortunately, from our last tutorial (Tutorial 1: Displaying a 3D Model on the Screen), we have two variables to do just that: modelPosition, which is a three-dimensional vector, and modelRotation, which is a floating-point value.
Currently, this system allows three degrees of translation (changing position in the world), but only one degree of rotation (changing orientation). For this demonstration, we will use that limitation to simplify our input. In many 3D games, there are three degrees of translation, and three degrees of rotation, but this is a good start.
What we can do right now to make input a little more interesting is add another vector for velocity. By updating the position with the velocity each frame, our 3D model can accelerate and decelerate smoothly. Let's try it.
The code you've just added to input runs every frame, and does a few different things. First, it gets rid of the code that automatically rotates the ship. You'll be controlling that by using your controller. Next, it calls a method named UpdateInput. That method does not exist yet. You'll have to create it in the next step. Last, it adds the velocity of our model to its position, moving it in the world by its velocity, and decays the velocity so that eventually the model will slow down.
Step 3: Take Input from the User
Now that the model is set up to move with velocity, you now need to provide some logic that will change the velocity based on controller input.
A simple system that we can use is an orientation thrust method: in essence, you can point the front of your model in different directions using your controller's thumbstick, then apply thrust in the direction you are pointing using your controller's trigger. By building up thrust in a direction, the model will begin to move.
We can map our controls to the game this way.
Let's code it!
That method does a lot. Let's take it piece by piece to investigate exactly what you're doing with input and the model.
// Get the game pad state.
GamePadState currentState = GamePad.GetState(PlayerIndex.One);
This call to GetState retrieves a GamePadState object, which contains the information we need about the controller—in this case, thumbstick and trigger positions.
// Rotate the model using the left thumbstick, and scale it down
modelRotation -= currentState.ThumbSticks.Left.X * 0.10f;
Retrieving the x-axis value of the left thumbstick (left and right movement) returns a value that is added to the modelrotation variable. The value is scaled down so that the rotation isn't too fast.
// Create some velocity if the right trigger is down.
Vector3 modelVelocityAdd = Vector3.Zero;
// Find out what direction we should be thrusting,
// using rotation.
modelVelocityAdd.X = -(float)Math.Sin(modelRotation);
modelVelocityAdd.Z = -(float)Math.Cos(modelRotation);
// Now scale our direction by how hard the trigger is down.
modelVelocityAdd *= currentState.Triggers.Right;
A little math here helps translate the rotation of the ship into a vector. Taking the sine value of the rotation gives us the proper amount of X (left and right) movement, and the cosine gives us the Z (forward and back) movement. Then, we take the vector and lengthen it by how hard the player is holding down the right trigger.
// Finally, add this vector to our velocity.
modelVelocity += modelVelocityAdd;
Finally, the created vector is added to the current velocity vector to create the final velocity vector that will be applied to move the model around.
GamePad.SetVibration(PlayerIndex.One,
currentState.Triggers.Right,
currentState.Triggers.Right);
We're using the right trigger values to give some feedback to the player with the Xbox 360 Controller vibration motors, using SetVibration . The Xbox 360 Controller has two motors that run at different speeds, so experiment to find the best combination for the action that's happening in the game.
// In case you get lost, press A to warp back to the center.
if (currentState.Buttons.A == ButtonState.Pressed)
{
modelPosition = Vector3.Zero;
modelVelocity = Vector3.Zero;
modelRotation = 0.0f;
}
This little extra will move the model back to its original position and orientation in case it leaves the screen.
Optional Step: Controlling the Ship With Keyboard Input
An Xbox controller is not the only means of control available for your ship. You can also use the standard keyboard that is hooked up to your computer. The following instructions assume that you have completed the previous steps in this tutorial.
Caution |
|---|
| Keyboard input is not supported for the Xbox 360 platform. Controlling the ship on an Xbox 360 requires an Xbox 360 Controller. |
The keyboard-specific code will be added to the Game1.Update and Game1.UpdateInput methods that were modified earlier. Let's handle the easy stuff first – modification of the Game1.Update method.
Modifying the Update Method
Currently, you can only exit your game with the controller or by clicking the Close button. Let's modify the following code:
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
to match this:
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed ||
Keyboard.GetState().IsKeyDown(Keys.Escape))
The new code now closes the game when you press the Escape key.
Modifying the UpdateInput Method
This step involves more code than the previous step. Once you have modified the code, you can control the ship's rotation with the A (rotate left) and D (rotate Right) keys and accelerate with the Enter key.
In the Game1.UpdateInput method, after the existing declaration of the currentState variable, add the following line of code:
KeyboardState currentKeyState = Keyboard.GetState();
This captures the current state of the keyboard, including which keys were being pressed at the time.
Remove the following line (Don't forget the matching curly brace!):
if (currentState.IsConnected)
{
This allows keyboard input to be received if a controller is not connected.
Search farther down the code and find the line that assigns the X value of the left thumbstick to modelRotation. Right before that line, add the following:
if(currentKeyState.IsKeyDown(Keys.A))
modelRotation += 0.10f;
else if (currentKeyState.IsKeyDown(Keys.D))
modelRotation -= 0.10f;
else
This first examines the keyboard for input (specifically, the A and D keys) and changes the rotation value accordingly. If no keyboard input is detected, the game controller is checked for input.
Search farther down for the following line of code:
modelVelocityAdd *= currentState.Triggers.Right;
Right before that code, add the following:
if (currentKeyState.IsKeyDown(Keys.W))
modelVelocityAdd *= 1;
else
This code checks to see if the W key is pressed and, if so, increases the current velocity. If the W key is not pressed, the game controller is checked for input.
The final modification warps the ship back to its original posiiton if the Enter key is pressed.
Look for the code that checks the state of the A button on the controller (near the end of the method). Modify this line to also check for a key press. After the modification, it should look like this:
if (currentState.Buttons.A == ButtonState.Pressed || currentKeyState.IsKeyDown(Keys.Enter))
Rebuild and run the game and you can now steer the ship with the A and D keys, accelerate with the W key, and warp back with the Enter key!
Congratulations!
At this point, your ship moves and gives you feedback through your Xbox 360 Controller. The player is in control of the action.
When you're ready, let's add the final element—audio—to get you on your way. Once the player can control the action, and see and hear the results of their actions, you're well on your way to creating a game.
Next...
Ideas to Expand
Want to play around some more with input? Try these ideas.
-
Change the game to view your model from the top, as in a top-down arcade game. (Hint: Play with the cameraPosition vector. Note that you can't set it exactly up and down because the camera vector cannot be the same as the "up" vector.)
-
Scale the vibration to occur more powerfully as the ship approaches the viewer. (Hint: Use the distance between modelPosition and cameraPosition.)
-
Try using a keyboard to control the ship. See the Keyboard class. (Hint: You can plug a USB keyboard into your Xbox 360 console.)
-
Get more ideas and resources at XNA Creators Club Online.