Transcript
In order to determine whether the mouse has moved, add a class-level MouseState variable at the top of your class: MouseState prevMouseState;
This variable will keep track of the mouse state from the previous frame. You’ll use it to compare the previous state to the current state of the mouse in each frame. If the values of the X and/or Y properties are different, you know the player has moved the mouse and you can move the three rings sprite to the new mouse position. Add the following code to the end of your Update method, just before the call to base.Update: MouseState mouseState = Mouse.GetState( ); if(mouseState.X != prevMouseState.X || mouseState.Y != prevMouseState.Y) ringsPosition = new Vector2(mouseState.X, mouseState.Y); prevMouseState = mouseState;
This code will move the three rings sprite to the position of the mouse, but only if the mouse has been moved. If you compile and run at this point, you should see that you are now able to control the rings sprite with the mouse or the keyboard.
Gamepad Input If you’re developing a game for Windows, you can still program for an Xbox 360 controller. You’ll have to have a wired controller, or you can purchase an Xbox 360 Wireless Receiver for around $20, which will allow you to connect up to four wireless controllers to a PC. The wireless Xbox 360 controller actually does come with a wire if you buy the charge pack for that controller, but there is no data transfer over that cable, so even when it’s plugged in it’s still a wireless controller. The cable on the charge pack transfers electricity for the charge, and nothing more.
Just as XNA provides a Mouse class for mouse input and a Keyboard class for keyboard input, it provides a GamePad class for reading input from an Xbox 360 gamepad. And yes, that’s right, there’s a GetState method for the GamePad class, just as there is for the other devices. There’s something to be said for standards, and Microsoft’s XNA Framework is, for the most part, a superb example of how standardization across a large-scale system (in this case, a framework and API) can be of such great benefit. Most of the time, you can tell how to use an object just by understanding the type of the object and knowing how similarly typed objects function. That’s a tribute to a great design by the XNA team—kudos to them. The GetState method for the GamePad class accepts an enum parameter called PlayerIndex that indicates which player’s controller you want to access, and it
Gamepad Input
|
47
returns a GamePadState struct that you can use to get data from the selected controller. Key properties of the GamePadState struct are listed in Table 3-3. Table 3-3. Key properties of the GamePadState struct Property
Type
Description
Buttons
GamePadButtons
Returns a struct that tells which buttons are currently pressed. Each button is represented by a ButtonState enum that specifies whether the button is pressed or not pressed.
DPad
GamePadDPad
Returns a struct that tells which directions on the DPad are pressed. The DPad struct has four buttons (up, down, left, and right), each of which is represented by a ButtonState enum that specifies whether the button is pressed or not pressed.
IsConnected
boolean
Indicates whether the controller is currently connected to the Xbox 360.
ThumbSticks
GamePadThumbSticks
Returns a struct that determines the directions of the thumbsticks. Each thumbstick (left and right) is a Vector2 object with X and Y values that have limits of -1 to 1 (e.g., for the left thumbstick, if you push it all the way left, its X value will be -1; if you don’t push it at all, the X value will be 0; and if you push it all the way to the right, the X value will be 1).
Triggers
GamePadTriggers
Returns a struct that tells whether the triggers are pressed. The Triggers struct contains two float values (left and right). A value of 0 means the trigger is not pressed at all, while a value of 1 means the trigger is fully pressed.
The GamePadState struct contains two methods that will give you most of the functionality you need. These methods are listed in Table 3-4. Table 3-4. Key methods of the GamePadState struct Method
Description
bool IsButtonDown(Buttons)
Pass in a button or multiple buttons with a bitwise OR. Returns true if all buttons are down, and false otherwise.
bool IsButtonUp(Buttons)
Pass in a button or multiple buttons with a bitwise OR. Returns true if all buttons are up, and false otherwise.
Looking at the properties in Table 3-3, you’ll notice that some of the controls are represented by Boolean or two-state values (either on or off), while others are represented by values that fluctuate between a range of numbers (0 to 1, or –1 to 1). These ranged properties are referred to as analog controls, and because they don’t have a simple on or off value, they offer more accuracy and more precision in a gaming control. You may have noticed that in some games on an Xbox 360 you can move at different speeds with the triggers or thumbsticks—this is because as you press either
48
|
Chapter 3: User Input and Collision Detection
button in a given direction, the controller will send a signal to the application in varying strengths. This is an important concept to remember when programming against an Xbox 360 controller and a feature that you’ll want to incorporate into games that you develop. We’ll cover how to do that in this section. All right, let’s add some code that will let you control your sprite with your Xbox 360 gamepad. Just as before, leave the code for the mouse and keyboard there, too, and you’ll now have three ways to control your sprite. Because the thumbsticks can contain X and Y values ranging from -1 to 1, you’ll want to multiply those values of the ThumbSticks property by the ringsSpeed variable. That way, if the thumbstick is pressed all the way in one direction, the sprite will move at full speed in that direction; if the thumbstick is only slightly pushed in one direction, it will move more slowly in that direction. The following code will adjust your sprite’s position according to how much and in which direction the left thumbstick on player one’s controller is pressed. Add this code to the Update method, just below the code for the keyboard and mouse input: GamePadState gamepadState = GamePad.GetState(PlayerIndex.One); ringsPosition.X += ringsSpeed * gamepadState.ThumbSticks.Left.X; ringsPosition.Y -= ringsSpeed * gamepadState.ThumbSticks.Left.Y;
Compile and run the application now, and you’ll have full control of your three rings sprite using your Xbox 360 controller. Let’s spice things up a bit. Using an Xbox 360 controller should be a bit more fun than it currently is. Let’s add a turbo functionality that doubles your movement speed when active. Of course, when moving so rapidly around the screen in turbo mode, you should feel some vibration in your controller due to the dangerous velocity at which you’ll be moving your sprite. You’ve probably felt the vibrations in an Xbox 360 controller before. This type of mechanism is referred to as force feedback, and it can greatly enhance the gameplay experience because it adds yet another sense that pulls the user into the game. The method SetVibration will set vibration motor speeds for a controller. The method returns a Boolean value indicating whether it was successful (false means that either the controller is disconnected or there is some other problem). The method accepts a player index, and a float value (from 0 to 1) for the left and right motors of the controller. Set the values to zero to stop the controller from vibrating. Anything above zero will vibrate the controller at varying speeds. Modify the code you just added to move the sprite with the Xbox 360 controller to include the following: GamePadState gamepadState = GamePad.GetState(PlayerIndex.One); if (gamepadState.Buttons.A == ButtonState.Pressed) { ringsPosition.X += ringsSpeed * 2 * gamepadState.ThumbSticks.Left.X; ringsPosition.Y -= ringsSpeed * 2 * gamepadState.ThumbSticks.Left.Y; GamePad.SetVibration(PlayerIndex.One, 1f, 1f); }
Gamepad Input
|
49
else { ringsPosition.X += ringsSpeed * gamepadState.ThumbSticks.Left.X; ringsPosition.Y -= ringsSpeed * gamepadState.ThumbSticks.Left.Y; GamePad.SetVibration(PlayerIndex.One, 0, 0); }
The code first checks to see if the A button on the controller is pressed. If it is, turbo mode is activated, which means that you’ll move the sprite at twice the normal speed and activate the vibration mechanism on the controller. If A is not pressed, you deactivate the vibration and move at normal speed. Compile and run the game to get a sense of how it works. As you can see, the gamepad adds a different dimension of input and gives a different feel to the game itself. It’s a powerful tool, but it won’t work well with all game types. Make sure you think about what type of input device is best for the type of game you are creating, because the input mechanism can go a long way toward determining how fun your game is to play.
Keeping the Sprite in the Game Window You have probably noticed that the rings sprite will disappear off the edge of the screen if you move it far enough. It’s never a good idea to have the player controlling an object that is off-screen and unseen. To rectify this, update the position of the sprite at the end of the Update method. If the sprite has moved too far to the left or the right or too far up or down, correct its position to keep it in the game window. Add the following code at the end of the Update method, just before the call to base.Update: if (ringsPosition.X ringsPosition.X if (ringsPosition.Y ringsPosition.Y if (ringsPosition.X ringsPosition.X if (ringsPosition.Y ringsPosition.Y
< = < = > = > =
0) 0; 0) 0; Window.ClientBounds.Width - ringsFrameSize.X) Window.ClientBounds.Width - ringsFrameSize.X; Window.ClientBounds.Height - ringsFrameSize.Y) Window.ClientBounds.Height - ringsFrameSize.Y;
Compile and run the game at this point, and you should be able to move the rings sprite around the screen just as before; however, it should always stay within the game window rather than disappearing off the edge of the screen.
Collision Detection So, you’ve got a pretty good thing going thus far. Players can interact with your game and move the three rings around the screen—but still there’s not a lot to do. You need to add some collision detection in order to take the next step.
50
|
Chapter 3: User Input and Collision Detection