Subscribe

RSS Feed (xml)

Powered By

Powered by Blogger

Google
 
xnahelp.blogspot.com
Tampilkan postingan dengan label input. Tampilkan semua postingan
Tampilkan postingan dengan label input. Tampilkan semua postingan

Kamis, 03 April 2008

Working with mouse Devices

This input device is only available for Windows, so if we are deploying our game for the
Xbox 360 we will need to put the XBOX360 compilation directive check we learned about
in Chapter 2 around any code that references the mouse as an input device. So we will
create a private member field with this preprocessor check inside of our InputHandler
class. We need to set up a private member field to hold our previous mouse state and
another one to hold our current mouse state:
#if !XBOX360
private MouseState mouseState;
private MouseState prevMouseState;
#endif
Then in our constructor we tell XNA that we want the mouse icon visible in our window
and we store our current mouse state:
#if !XBOX360
Game.IsMouseVisible = true;
prevMouseState = Mouse.GetState();
#endif
In our Update method of the input handler game component we need to set the previous
state to what our current state is and then reset our current state as follows:
#if !XBOX360
prevMouseState = mouseState;
mouseState = Mouse.GetState();
#endif
98 CHAPTER 5 Input Devices and Cameras
Now we need to expose these internal fields so our camera (and any other) object can get
their values. First we need to add the properties to our interface as follows:
#if !XBOX360
MouseState MouseState { get; }
MouseState PreviousMouseState { get; }
#endif
Now we can implement those properties in our class:
#if !XBOX360
public MouseState MouseState
{
get { return(mouseState); }
}
public MouseState PreviousMouseState
{
get { return(prevMouseState); }
}
#endif
In our camera’s Update method we want to get the latest state of our mouse and compare
the current X value to the previous X value to determine if we moved the mouse left or
right. We also want to check if the left mouse button is pushed before updating our
cameraYaw variable. Of course, all of this is wrapped in our compilation preprocessor
condition as follows:
#if !XBOX360
if ((input.PreviousMouseState.X > input.MouseState.X) &&
(input.MouseState.LeftButton == ButtonState.Pressed))
{
cameraYaw += (spinRate * timeDelta);
}
else if ((input.PreviousMouseState.X < input.MouseState.X) &&
(input.MouseState.LeftButton == ButtonState.Pressed))
{
cameraYaw -= (spinRate * timeDelta);
}
#endif
We can compile and run the code and test the latest functionality on Windows. If the
preprocessor checks are in place correctly, we should be able to deploy this demo to the
Xbox 360 as well, although it will not do anything different than it did before we added
the mouse support.

Read More......

Working with gamepad Devices

The Microsoft Xbox 360 wired controller works on the PC. XNA provides us with helper
classes that make it very easy to determine the state of our game pad. The template
already provided one call to the game pad helper class. This call is also in the Update
method. Let’s take a look at what is provided for us already.
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
The template is calling the built-in XNA class GamePad and calling its GetState method
passing in which player’s controller they want to check. The template then checks the
Back button on that controller to see if it has been pressed. If the controller’s Back button
has been pressed, the game exits. Now, that was pretty straightforward. To be consistent
we can use our input class to check for the condition.
Before we can do that, we need to update our interface and add the appropriate property
as well as actually getting the game pad state just like we did for our keyboard. Let’s jump
to our input handler code and do some of these things. We can start by adding a property
to get to our list of game pads in our interface:
GamePadState[] GamePads { get; }
Now we can create the member field and property to get that field like the following code:
private GamePadState[] gamePads = new GamePadState[4];
public GamePadState[] GamePads
{
get { return(gamePads); }
}
Working with Input Devices 95
5
We need to initialize each game pad state and can do that in the Update method of the
input handler object:
gamePads[0] = GamePad.GetState(PlayerIndex.One);
gamePads[1] = GamePad.GetState(PlayerIndex.Two);
gamePads[2] = GamePad.GetState(PlayerIndex.Three);
gamePads[3] = GamePad.GetState(PlayerIndex.Four);
Now, let’s remove the code that checks to see if the Back button is pressed on player one’s
game pad from our demo. We can add this code in the Update method of our
InputHandler game component to get the same effect:
if (gamePads[0].Buttons.Back == ButtonState.Pressed)
Game.Exit();
Let’s update our yaw rotation code inside of the camera game component so that we can
get the same result with our controller. We can modify our existing code that checks for
left and right to also handle input from our controller. So we modify our two conditional
statements that set the cameraYaw to also check the right thumb stick state of the game
pad we are examining:
if (input.KeyboardState.IsKeyDown(Keys.Left) ||
(input.GamePads[0].ThumbSticks.Right.X < 0))
{
cameraYaw += (spinRate * timeDelta);
}
if (input.KeyboardState.IsKeyDown(Keys.Right) ||
(input.GamePads[0].ThumbSticks.Right.X > 0))
{
cameraYaw -= (spinRate * timeDelta);
}
The thumb stick x and y axis provide a float value between -1 and 1. A value of 0 means
there is no movement. A value of -0.5 means the stick is pushed to the left halfway. A
value of 0.9 would be the stick is pushed to the right 90 percent of the way.
We did not change the keyboard code, we simply added another “or” condition to handle
our controller. We can see it is very simple, as we only needed to check the
ThumbSticks.Left property. We check the x axis of that joystick and if it is less than zero
the user is pushing the stick to the left. We check to see if it is positive (user pushing to
the right) in the second condition. We leave our cameraYaw variable to be set by our spin
rate (taking into account our time delta). At this point, regardless if players are using the
keyboard or the game pad they will get the same result from the game: The camera will
rotate around the y axis. Compile and run the program to try it out. We can also try the
game on the Xbox 360 because we have hooked up our game pad code.
At this point we know how to get access to any of the buttons (they are treated the same
way as the Back button) and either thumb stick but we have not discussed the D-pad yet.
96 CHAPTER 5 Input Devices and Cameras
The D-pad is actually treated like buttons. If we also wanted to allow the player to rotate
the camera left or right by using the D-pad, we simply need to add the following as part
of our condition:
gamePadState.DPad.Left == ButtonState.Pressed
Add that condition along with a check for the right D-Pad being pressed to our code.
Compile and run the code again and make sure that the demo allows us to look left or
right by using the keyboard, thumb stick, and D-pad. The code should now look like the
following:
if (keyboardState.IsKeyDown(Keys.Left) ||
(gamePadState.ThumbSticks.Right.X < 0) ||
(gamePadState.DPad.Left == ButtonState.Pressed))
{
cameraYaw += spinRate;
}
if (keyboardState.IsKeyDown(Keys.Right) ||
(gamePadState.ThumbSticks.Right.X > 0) ||
(gamePadState.DPad.Right == ButtonState.Pressed))
{
cameraYaw -= spinRate;
}
The shoulder buttons are just that—buttons—and we know how to handle those already.
We can determine when we press down on the left or right thumb stick because those are
also considered buttons. However, the final item we discuss regarding our game pad
controller is the triggers. Now, a good use of our triggers for this demo would be to turn
on vibration!
Before we actually determine how to use the triggers, we can look at another property of
the game pad state we have access to and that is if the controller is actually connected or
not. We can check this by getting the value of the IsConnected property.
The trigger values return a float between 0 and 1 to signify how much the trigger is
pressed (0 = not pressed; 1 = fully pressed). The Xbox 360 controller has two motors that
create its vibration. The motor on the left is a low-frequency motor whereas the motor on
the right is a high-frequency motor. We can set the values on both motors in the same
method call. We do this by calling the GamePad.SetVibration method. Because this is just
something we are doing for our demo and not really a part of the library, we will put this
code in our Game1.cs file inside the Update method:
if (input.GamePads[0].IsConnected)
{
GamePad.SetVibration(PlayerIndex.One, input.GamePads[0].Triggers.Left,
input.GamePads[0].Triggers.Right);
}
Working with Input Devices 97
5
The first thing we are doing with this new code is checking to see if the game pad is actually
connected. If it is connected then we set the vibration of both the left and right
motors based on how much the left and right triggers are being pressed. We are calling
the GamePad’s static SetVibration method. There is currently no benefit in wrapping
that into a method inside of our input handler.
We can also change the information being displayed in our window title bar to include
the left and right motor values. This can help you determine what values you should use
as you implement vibration in your games! The following is the code to accomplish that
task:
this.Window.Title = “left: “ +
input.GamePads[0].Triggers.Left.ToString() + “; right: “ +
input.GamePads[0].Triggers.Right.ToString();
Go ahead and add this debug line inside of the IsConnected condition and compile and
run the code to check the progress. We will no longer be able to see our frame rate with
this code so we could just comment out the fps object until we are ready to actually
check on our performance.

Read More......

Working with keyboard Devices

We will be populating the stub we created for handling our input. We are going to create
a stationary camera and a first person. Both of these cameras will need to respond to user
input. We need to learn how to handle input devices and utilize them to move our
camera and fully see the worlds we create.
Keyboard
The first input device we will talk about is the keyboard. XNA provides us with helper
classes that allow us to easily determine the state of our input devices. We determine the
state of our keyboard by declaring a variable to store our keyboard state and then calling
the GetState method on the Keyboard helper object. We can then query that variable to
determine which key (or keys) is being pressed or released. We can start by adding a
private member field to store our keyboard state. We do this via the following code inside
of our InputHandler game component:
private KeyboardState keyboardState;
Then we can find the Update method that was stubbed out for us when the InputHandler
game component was created.
keyboardState = Keyboard.GetState();
if (keyboardState.IsKeyDown(Keys.Escape))
Game.Exit();
We can put this at the very beginning of the Update method. We are simply storing the
state of the keyboard and then checking to see if the Escape key was pressed. If so, we
simply exit the program. It doesn’t get much simpler than that! So now when we run the
program we can exit by pressing the Escape key (instead of having to close the window
with our mouse).
Although being able to exit our game easily is important, we still haven’t done anything
exciting. Let’s set up our camera so we swivel back and forth if the left or right keys are
pressed. To do this we need to add and initialize a new private member field called
cameraReference inside of our Camera game component:
private Vector3 cameraReference = new Vector3(0.0f, 0.0f, -1.0f);
This camera reference direction will not change throughout the game, but we will be
passing it in as a reference so we cannot declare it as a readonly variable. Typically this
value will either be (0,0,1) or (0,0,-1). We chose to have a negative z value so we can
continue to have our camera face the same way.
Now that we have our camera reference direction set up, we need to apply any movement
and rotation to our view of the world. So if the player wants to look left and right we can
adjust our view matrix accordingly so that our view of the world is from a certain angle.
To look left and right we need to rotate around our y axis. We can add the following code
to our Update method right before our call out to the base object’s Update method (we are
still in our Camera class):
Working with Input Devices 91
5
Matrix rotationMatrix;
Matrix.CreateRotationY(MathHelper.ToRadians(cameraYaw), out rotationMatrix);
// Create a vector pointing the direction the camera is facing.
Vector3 transformedReference;
Vector3.Transform(ref cameraReference, ref rotationMatrix,
out transformedReference);
// Calculate the position the camera is looking at.
Vector3.Add(ref cameraPosition, ref transformedReference, out cameraTarget);
Matrix.CreateLookAt(ref cameraPosition, ref cameraTarget, ref cameraUpVector,
out view);
Because we know we will be rotating, we will create a matrix to hold our rotation. With a
helper function from XNA we will create a matrix with the appropriate values to rotate
our camera on the y axis by a certain number of degrees. We are storing that value in a
variable that we will set with our input devices. We will see how we set that value with
our keyboard soon. Once we have our matrix with all of the translations, scaling, and
rotations that we need (in this case we are only rotating) we can create a transform vector
that will allow us to change the target of the camera. We get this transformed vector by
using another XNA helper method, Vector3.Transform. We then add the transformed
camera reference to our camera position, which will give us our new camera target. To do
this, we could have used the plus (+) operator like the following code:
cameraTarget = cameraPosition + transformedReference;
However, it is much more efficient to use the built-in static Add method of the Vector3
struct because it allows us to pass our vectors by reference instead of having to copy the
values to memory. Finally, we reset our view with our new camera target. We also need to
set the following private member field that we used in the code:
private float cameraYaw = 0.0f;
Now we are to the point where we can compile the code, but our newly added code does
not do anything for us. This is because we are never changing our rotation angle. It stays
at 0 on every frame. Let’s change that now with our keyboard. Inside of our InputHandler
class, we need to update our IInputHandler interface to expose the keyboard state we
retrieved earlier. Let’s add the following code inside of our interface:
KeyboardState KeyboardState { get; }
Now, we need to implement that property inside of the class. An easy way to do this is to
right-click IInputHandler where we derived from it and select Implement Interface. We
will be doing this a couple of times and each time it will create a region so we will have
to clean up the code and remove the extra regions the IDE provides for us. Now we need
to change the get value to retrieve our internal keyboardState value as follows:
92 CHAPTER 5 Input Devices and Cameras
public KeyboardState KeyboardState
{
get { return(keyboardState); }
}
Now that we have exposed our keyboard state we can utilize it inside of our Camera
object. We need to add the following code to our Update method right above the previous
code inside of our camera object:
if (input.KeyboardState.IsKeyDown(Keys.Left))
cameraYaw += spinRate;
if (input.KeyboardState.IsKeyDown(Keys.Right))
cameraYaw -= spinRate;
if (cameraYaw > 360)
cameraYaw -= 360;
else if (cameraYaw < 0)
cameraYaw += 360;
We also need to make sure camera is using the XNA Framework’s Input namespace
because we are accessing the Keys enumeration:
using Microsoft.Xna.Framework.Input;
Finally, we add this constant to the top of our camera class:
private const float spinRate = 2.0f;
In our update code we utilized the current keyboard state we already captured and
checked to see if either the left arrow or right arrow on the keyboard was pressed. If the
player wants to rotate to the left then we add our spin rate constant to our current
camera yaw angle. (Yaw, pitch, and roll are terms borrowed from flight dynamics. Because
we are using a right-handed coordinate system, this means that yaw is rotation around
the y axis, pitch is rotation around the x axis, and roll is rotation around the z axis.) If
the player wants to rotate to the right then we subtract our spin rate constant from our
current camera yaw angle. Finally we just check to make sure that we do not have an
invalid rotation angle.
There is one last thing we need to do before we can run our code again. We need to actually
add our input handler game component to our game’s collection of components. We
can declare our member field as follows:
private InputHandler input;
Now we can actually initialize that variable and add it to the collection inside of our
constructor with this code:
input = new InputHandler(this);
Components.Add(input);
Working with Input Devices 93
5
We can compile and run the code and move knowing that our left and right arrows rotate
the camera. When running we can see that our objects are just flying by. It almost seems
they are blinking we are turning so fast. This is because we are calling our Update statement
as fast as possible. We can modify the game code where we are initializing our fps
variable to use a fixed time step:
fps = new FPS(this, false, true);
For the preceding code to work we need to add another constructor to our FPS code. We
are doing this is so we don’t need to actually pass in our target elapsed time value if we
want it to be the default.
public FPS(Game game, bool synchWithVerticalRetrace, bool isFixedTimeStep)
: this(game, synchWithVerticalRetrace, isFixedTimeStep,
game.TargetElapsedTime) { }
Now when we run the code we can see the objects move by at a consistent and slower
rate. This is because the Update method is now only getting called 60 times a second
instead of whatever rate our machine was running at.
We will notice, however, that as it renders the rectangles that our screen is “choppy.” The
reason is that we are not letting XNA only draw during our monitor’s vertical refresh. We
could do this by setting our second parameter to true and we would see the screen rotate
at a nice even pace with the screen drawing nicely. However, a better way to handle this
is by utilizing the elapsed time between calls to our methods. We need to retrieve the
elapsed time since the last time our Update method was called and then multiply our
spinRate by this delta of the time between calls. We will change the camera code snippet
to match the following:
float timeDelta = (float)gameTime.ElapsedGameTime.TotalSeconds;
if (input.KeyboardState.IsKeyDown(Keys.Left))
cameraYaw += (spinRate * timeDelta);
if (input.KeyboardState.IsKeyDown(Keys.Right))
cameraYaw -= (spinRate * timeDelta);
We can modify our game code to call the default constructor again:
fps = new FPS(this);
Now we are just creeping along. This is because our spin rate is so low. We had it low
because we were relying on the update method to be called 60 times per frame, so we
were basically rotating our camera 120 degrees per second. To get the same effect we
simply set our spinRate to 120. The reason is we are now multiplying it by the time
difference between calls. At this point we can safely set our units and know they will be
used on a per-second basis. Now that we have our spinRate utilizing the delta of the time
between calls we are safe to run at any frame rate and have our objects drawn correctly
based on the amount of time that has elapsed.
94 CHAPTER 5 Input Devices and Cameras
We can have it always run at 60 fps in release mode and run as fast as possible in debug
mode by modifying our game code as follows:
#if DEBUG
fps = new FPS(this);
#else
fps = new FPS(this, true, false);
#endif
This allows us to run as fast as we can in debug mode while consistently moving our
objects no matter the frame rate. It allows us to force XNA to only update the screen
during the monitor’s vertical retrace, which would drop us to 60 fps or whatever rate the
monitor is refreshing at.
Making a game update itself consistently regardless of the frame rate can make the game
more complex. We need to calculate the elapsed time (time delta) since the last frame and
use that value in all of our calculations. With the fixed step mode that XNA provides we
could cut down on development time and rely on the fact that the update code will be
called 60 times a second. This is not sufficient if we are writing a library that can be
plugged into games, as those games might not run at a consistent frame rate.

Read More......