程序代写代做代考 4 XNA Input

4 XNA Input

ITP4710

2D/3D Graphics Programming
04
MonoGame Input

XNA Framework provides support for three categories of user input devices
Keyboard
USB Keyboards with more than 100 digital keys
Each key have one of two states – pressed or released
Mouse
Mouse position, 3 mouse buttons and scroll wheel values can be retrieved.
Gamepad
Maximum 4 gamepads
2
MonoGame Input

Input status from GamePad, Keyboard and Mouse are collected through polling.
During every frame, your game will ask the controller what its current state is
The information is stored in XNA structures GamePadState, KeyboardState and MouseState
The device state will be updated every frame and should be passed as parameter(s) to your methods
Polling may seem inefficient and you might think it will miss player input between GetState() calls.
The truth is that you are getting ~60 states each second and a player is very unlikely to press and release a button between any two polling requests
3
Polling Input Device State

Keyboards have 100+ keys, each treated as a digital button
KeyboardState information is retrieved using the GetState() method of Keyboard class
KeyboardState keyState = Keyboard.GetState();
To see if a particular key is being pressed/released, you can call the IsKeyDown() / IsKeyUp() method of KeyboardState structure
if (keyState.IsKeyDown(Keys.Up)) { /* do something */ }
To retrieve a complete list of the currently pressed key, you can call the GetPressedKeys() function, which returns a Keys array of pressed keys.
4
Keyboard

protected override void Update(GameTime gameTime) {
// Poll for current keyboard state
KeyboardState state = Keyboard.GetState();
// If they hit esc, exit
if (state.IsKeyDown(Keys.Escape)) Exit();
// Print to debug console currently pressed keys
System.Text.StringBuilder sb = new StringBuilder();
foreach (var key in state.GetPressedKeys())
sb.Append(“Key: “).Append(key).Append(” pressed “);
if (sb.Length > 0) System.Diagnostics.Debug.WriteLine(sb.ToString());
else System.Diagnostics.Debug.WriteLine(“No Keys pressed”);
// Move our sprite based on arrow keys being pressed:
if (state.IsKeyDown(Keys.Right)) position.X += 10;
if (state.IsKeyDown(Keys.Left)) position.X -= 10;
if (state.IsKeyDown(Keys.Up)) position.Y -= 10;
if (state.IsKeyDown(Keys.Down)) position.Y += 10;
base.Update(gameTime);
}
© VTC 2016
5
Sample Code For Keyboard Input

MouseState information is retrieved using GetState() function of Mouse class
MouseState mouseState = Mouse.GetState();
Supports LeftButton, RightButton and MiddleButton.
The state of the buttons is either ButtonState.Pressed or ButtonState.Releasted.
MouseState also support two special button XButton1 and XButton2, which are used by some modern mouse to as back and forward buttons that help navigating websites.
Mouse position retrieved from member properties X and Y
You can also explicitly set the mouse position through SetPosition() method.
ScrollWheelValue gets the cumulative mouse scroll wheel value since the game was started.
It’s common to want to display the mouse cursor, this is easily accomplished using:
IsMouseVisible = true;

6
Mouse

protected override void Update(GameTime gameTime) {
MouseState state = Mouse.GetState();
// Update our sprites pos to the current cursor location
position.X = state.X;
position.Y = state.Y;
// Check if Right Mouse Button pressed, if so, exit
if (state.RightButton == ButtonState.Pressed)
Exit();
base.Update(gameTime);
}
© VTC 2016
7
Sample Code For Keyboard Input

To handle input from a gamepad or joystick controller, GamePadState information is retrieved using GetState() function of GamePad class
Example:
GamePadState padState1 = GamePad.GetState(PlayerIndex.One);
The state of a GamePad is undefined when the GamePad is disconnected.
Check if a game pad is connected before polling the data:
// Check the device for Player One
GamePadCapabilities capabilities
= GamePad.GetCapabilities( PlayerIndex.One);
// If there a controller attached, handle it
if (capabilities.IsConnected) {
// Do something here
}
8
GamePad

9
Typical Gamepad –
Xbox 360 Controller

Game pad can have up to 14 digital buttons
A, B, X, Y, Start, Back, LeftShoulder and RightShoulder buttons
The four direction buttons of the DPad (DPadLeft, DPadRight, DPadUp and DPadDown)
Left and Right thumbsticks can be pressed and behave as digital buttons (LeftStick and RightStick)
Media button is not supported
Digital buttons have only 2 states – pressed and released.
Example:
if (padState1.Buttons.A == ButtonState.Pressed)
// Do something here

10
Digital Buttons

Unlike digital buttons, analog buttons report a range of values
Two triggers on the back side of the game pad
represented by a float from 0.0f (not pressed) to 1.0f (fully pressed)
Two directional thumbsticks
each thumbsticks has x-axis and y-axis represented by a single Vector2
each axis is represented by a float from -1.0f (left/down) to 1.0f (right/up)
11
Analog Buttons

GamePadState.Buttons.
A
B
X
Y
LeftShoulder
RightShoulder
LeftStick
RightStick
Start
Back
GamePadState.DPad.
Up
Down
Left
Right
GamePadState.ThumbSticks
Left (Vector2)
Right (Vector2)
GamePadState.Triggers
Left
Right
12
GamePad Buttons

protected override void Update(GameTime gameTime) {
// Check the device for Player One
GamePadCapabilities capabilities =
GamePad.GetCapabilities( PlayerIndex.One);
// If there a controller attached, handle it
if (capabilities.IsConnected) {
// Get the current state of Controller1
GamePadState state = GamePad.GetState(PlayerIndex.One);
// You can check if a gamepad has support for a feature
if (capabilities.HasLeftXThumbStick) {
// Check the direction in X axis of left analog stick
if (state.ThumbSticks.Left.X < -0.5f) position.X -= 10.0f; if (state.ThumbSticks.Left.X > 0.5f) position.X += 10.0f;
}
// You can also check the controllers “type”
if (capabilities.GamePadType == GamePadType.GamePad) {
if (state.IsButtonDown(Buttons.A)) Exit();
}
base.Update(gameTime);
}
© VTC 2016
13
Sample Code For GamePad Input

You can have up to 4 different controllers attached, each accesible by passing the appropriate PlayerIndex to GetEvents().
The following device types can be returned:
AlternateGuitar, ArcadeStick, BigButtonPad, DancePad, DrumKit, FlightStick, GamePad, Guitar, Wheel or Unknown.
Each devices supports a different set of features, which can be polled invdividually using the GamePadCapabilities struct returned by Gamepad.GetCapabilities().
© VTC 2016
14
Supported Gamepads

When at rest, the thumbsticks will always be slightly off center.
Default GamePad.GetState() method automatically disregards values that are below a certain threshold, which is known as the dead zone.
The default setting of dead zone processing uses GamePadDeadZone.IndependentAxes which processed the deadzone of X, Y components independently.
You can also set the dead zone processing method to Circular (combining X-Y components in processing) or None (raw values without any processing) using overloaded GetState() method.
GamePadState state =
GamePad.GetState(PlayerIndex.One, GamePadDeadZone.Circular);
15
Dead Zone Processing

Gamepad can have two vibration motors
Left low-frequency rumble motor
Right high-frequency rumble motor
Each motor can be activated with different speed using GamePad.SetVibration() function
GamePad.SetVibration(
PlayerIndex.One, // player index
1.0f, // speed of left motor (0.0f – 1.0f)
1.0f); // speed of right motor (0.0f – 1.0f)
16
Vibration

17
Example – Shooting Bullets
In the following example, the player will control a plane flying around a sheet of graph paper.
Press up/down to move forward/backward
Press left/right to turn the plane
Press space to shoot a bullet
Press escape to quit the program
The plane will actually remain in the center of the screen. It appears to be moving because the background game world move relatively.
The game is tuned to use a fixed frame rate of 30 fps in the Initialize() method
IsFixedTimeStep = true;
TargetElapsedTime = TimeSpan.FromMilliseconds(33);

18
Example – Shooting Bullets

All bullets in the game is stored in an array, with a maximum size of BULLET_MAX (75)
m_Bullets = new Bullet[BULLET_MAX];
for(int i=0; i 0) m_nBulletCountDown–;
// Shoot Bullet (only if bullet delay count == 0)
if (keyState.IsKeyDown(Keys.Space)) Shoot();

base.Update(gameTime);
}
21
Update() – Handling Input
Rotate Ship
Move Ship

The plane sits still in the center of the screen
When the plane moves forward/backward, the background and the bullets will move around
The background is formed by tiling a 51×51 sprite.
The movement is created by shifting the origin between (0,0) and (50,50).
To keep the background from appearing wavy, we round the origin to the nearest pixel before drawing the tiles in Draw()
To rotate the plane, we just need to update the rotation angle m_angle.
22
Moving and Rotating the Plane

private void MoveShip(float delta) {
// distance to travel per frame, split into X and Y
float dx = delta * (float)Math.Cos(m_angle);
float dy = delta * (float)Math.Sin(m_angle);
// update graph
m_GraphOrigin.X += dx;
m_GraphOrigin.Y += dy;
// make sure x,y are between -50 and 0
while (m_GraphOrigin.X < 0) m_GraphOrigin.X += 50.0f; while (m_GraphOrigin.X > 50) m_GraphOrigin.X -= 50.0f;
while (m_GraphOrigin.Y < 0) m_GraphOrigin.Y += 50.0f; while (m_GraphOrigin.Y > 50) m_GraphOrigin.Y -= 50.0f;
UpdateBullets(dx, dy);
}

private void TurnShip(float delta) { m_angle += delta; }
23
MoveShip() and TurnShip()

Vector2 loc = new Vector2(0, 0); // sprite position
float height = GraphicsDevice.Viewport.Height;
float width = GraphicsDevice.Viewport.Width;
GraphicsDevice.Clear(Color.CornflowerBlue);
_spriteBatch.Begin();
for (int y = 0; y <= height / background.Height + 1; y++) { loc.Y = y * background.Height; for (int x = 0; x <= width / background.Width + 1; x++) { loc.X = x * background.Width; _spriteBatch.Draw(background, loc, null, Color.White, 0, m_GraphOrigin, 1, SpriteEffects.None, 0); } } _spriteBatch.Draw(plane, m_CenterScreen, null, Color.White, m_angle, new Vector2(plane.Width / 2, plane.Height / 2), 1, SpriteEffects.None, 1); _spriteBatch.End(); © VTC 2016 24 Draw() (partial) All bullets in the bullet array were initially inactive. When player shots a bullet, we will check if enough time have been waited since last shot If there is an inactive bullet in the array to be re-initialized Bullet position and velocity will be initialized if the above conditions are satisfied When a bullet moves on the screen, it combines the velocity of the plane (as it sits still on the screen) and its own velocity. We also needs to check if the bullet is out-of-screen 25 Shooting and Updating Bullets private void Shoot() { if (m_nBulletCountDown == 0) { // check if waited enough time for (int i = 0; i < m_Bullets.Length; i++) { if (!m_Bullets[i].Active) { // check for available slot m_Bullets[i].Location = m_CenterScreen; // calc distance to travel per frame, split into X and Y float dx = -3.0f * (float)Math.Cos(m_angle); float dy = -3.0f * (float)Math.Sin(m_angle); m_Bullets[i].Motion = new Vector2(dx, dy); m_Bullets[i].Angle = 0.0f; // init rotation m_Bullets[i].Active = true; // mark as active m_nBulletCountDown = BULLET_DELAY; // reset delay counter break; // we're done, so exit the loop } } } } 26 Shoot() private void UpdateBullets(float dxShip, float dyShip) { for (int i = 0; i < m_Bullets.Length; i++) { if (m_Bullets[i].Active) { // update active bullets // see if the bullet has left the screen if ( m_Bullets[i].Location.X < -64 || m_Bullets[i].Location.X > SCREEN_WIDTH + 64 ||
m_Bullets[i].Location.Y < -64 || m_Bullets[i].Location.Y > SCREEN_HEIGHT + 64 ) {
m_Bullets[i].Active = false;
} else {
m_Bullets[i].Location.X +=
dxShip + m_Bullets[i].Motion.X;
m_Bullets[i].Location.Y +=
dyShip + m_Bullets[i].Motion.Y;
m_Bullets[i].Angle += 0.45f; // rotate the bullet
}
}
}
}
27
UpdateBullets()

The game sets a grid of 20×15 cells on the screen
If the mouse is clicked on a cell, the cell color will change permanently
If the mouse moves into a cell, the cell color will change and fade back to origin color after the mouse moves out
The cell status is stored in struct BlockState
bool IsSelected;
double EffectAge;
// representing the remaining time for keeping current color
A 2D array stores status of all cells
private BlockState[,] BlockStates =
new BlockState[GRID_WIDTH, GRID_HEIGHT];
28
Example – Draw with Mouse

29
Example – Draw with Mouse

We need to track the location of the mouse from frame to frame
to highlight the cells that the cursor passes over by initializing EffectAge of the cell
We also need to know when the player has clicked the mouse button
to toggle the IsSelected flag for the clicked cell
To make sure that we don’t register a click more than once, the MouseState from the previous frame needs to be stored
Whenever the previous state doesn’t match the current state, the player has pressed or released the button.
30
Processing Input

MouseState mouse1 = Mouse.GetState();
CursorPosition.X = mouse1.X;
CursorPosition.Y = mouse1.Y;
// which grid cell is this mouse over now?
int gx = (int)Math.Floor(CursorPosition.X / CELL_WIDTH);
int gy = (int)Math.Floor(CursorPosition.Y / CELL_HEIGHT);
for (int y = 0; y < GRID_HEIGHT; y++) { for (int x = 0; x < GRID_WIDTH; x++) { if (gx == x && gy == y) { // mouse on cell BlockStates[x, y].EffectAge = EFFECT_DURATION; if (mouse1.LeftButton == ButtonState.Pressed) { // Check if the click has been registered if (mouse1.LeftButton != LastMouseButtonState) BlockStates[x, y].IsSelected = !BlockStates[x, y].IsSelected; } } else { // no longer mouse over, update effect age BlockStates[x, y].EffectAge -= elapsed; if (BlockStates[x, y].EffectAge < 0) BlockStates[x, y].EffectAge = 0; } } } // remember the last click state so we don't process it again LastMouseButtonState = mouse1.LeftButton; 31 Update() Function (Partial) DrawGrid() draws the blue grid lines between the cells by shifting a thin rectangle DrawCursor() draws the arrow sign to indicate the mouse position No mouse cursor is shown in XNA application by default DrawBlocks() draws the cells If cell is selected, draw the cell using active color (white) If cell is not selected and EffectAge = 0, draw the cell using standard color (blue) Otherwise, the color will be between white and blue, calculated by linear interpolation (MathHelper.Lerp) 32 Drawing the Screen Rectangle pos = BlockRect; Vector3 vColor = Vector3.One Vector3 vColorA = ColorActiveBlock.ToVector3(); Vector3 vColorI = ColorIdleBlock.ToVector3(); for (int y = 0; y < GRID_HEIGHT; y++) { // for each row pos.Y = y * 32 + 2; // row as pixel for (int x = 0; x < GRID_WIDTH; x++) { // for each column pos.X = x * 32 + 2; // column as pixel // state of the current block BlockState state = BlockStates[x, y]; if (state.IsSelected) { batch.Draw(Texture, pos, BlockRect, ColorActiveBlock); } else if (state.EffectAge > 0) {
vColor.X = MathHelper.Lerp(vColorI.X, vColorA.X,
(float)(state.EffectAge / EFFECT_DURATION));
vColor.Y = MathHelper.Lerp(vColorI.Y, vColorA.Y,
(float)(state.EffectAge / EFFECT_DURATION));
vColor.Z = MathHelper.Lerp(vColorI.Z, vColorA.Z,
(float)(state.EffectAge / EFFECT_DURATION));
batch.Draw(Texture, pos, BlockRect, new Color(vColor));
} else {
batch.Draw(Texture, pos, BlockRect, ColorIdleBlock);
}
}
}
33
DrawBlocks() Function

Reference
Joseph Hall, XNA Game Studio Express – Developing Games for Windows and the Xbox 360, Thomson Course Technology
Chapters 7-9
MonoGame Tutorial: Handling Keyboard, Mouse and GamePad Input, GameFromScratch.com (http://www.gamefromscratch.com/post/2015/06/28/MonoGame-Tutorial-Handling-Keyboard-Mouse-and-GamePad-Input.aspx)
34
© VTC 2016