Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Input and done #56

Merged
merged 3 commits into from
Sep 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
132 changes: 132 additions & 0 deletions articles/getting_to_know/howto/input/HowTo_DetectGamePadInput.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
---
title: Detecting input from a GamePad
description: The code in this topic describes how to detect input on a GamePad.
requireMSLicense: true
---

## Overview

By using [GamePad.GetState](xref:Microsoft.Xna.Framework.Input.GamePad#Microsoft_Xna_Framework_Input_GamePad_GetState_System_Int32_) a game can determine which buttons are being held down. A game often needs to detect when a user has pressed or released a button. For example, there is the case of an action title that requires users to press and release keys in rapid succession. The example uses a cached [GamePadState](xref:Microsoft.Xna.Framework.Input.GamePadState) object to determine if buttons were pressed or released in a given frame.

Unlike Keyboards however, multiple GamePads can be connected to a computer or console at the same time, so the [GamePad.GetState](xref:Microsoft.Xna.Framework.Input.GamePad#Microsoft_Xna_Framework_Input_GamePad_GetState_System_Int32_) call requires an Index parameter for which controller is being polled. You also need to query the system the game is currently on for its [GamePad.MaximumGamePadCount](xref:Microsoft.Xna.Framework.Input.GamePad#Microsoft_Xna_Framework_Input_GamePad_MaximumGamePadCount) to determine how many controllers are supported and how many need to be polled for each frame. Also unlike GamePads, GamePads can be disconnected (especially if the battery dies) at any time and most consoles require you to validate this to avoid player issues.

> [!NOTE]
> It is also worth noting, that when maintaining the state of connected gamepads, most console vendors **REQUIRE** your game to mange GamePad disconnection states (because it was unplugged, lost power, etc), ensuring the user experience is managed when the user CANNOT play.

Depending on game design, there may be times when checking for a button press needs to occur more frequently, and other times it does not. It is possible in the case of very fast button presses that more than one key press could occur within one frame. In such a case, the last button press is returned. Writing code that checks as often as possible for button presses is the best way to handle this case.

## Types of GamePad input

Most GamePads include a variety of different input options, including (but not limited to)

- Thumbsticks - providing ranged motion in two axis.
- Buttons (including buttons on the Thumbsticks) - Digital on/off buttons (similar to keyboard keys)
- Triggers - providing ranged motion in a singular axis.
- Touchpads - in some advanced controllers (such as the PlayStation Dual Shock controller) include a small touchpad.

Additionally, most controllers also support haptic feedback (vibration) in the controller, which is different depending on the controller being used and for which system.

> [!NOTE]
> Joysticks also work the same as GamePads, but use their own [Joystick](xref:Microsoft.Xna.Framework.Input.Joystick) and [JoystickState](xref:Microsoft.Xna.Framework.Input.JoystickState) classes. Operationally however, they work the same as GamePads.

## Detecting input changes on a GamePad

1. Declare a [GamePadState](xref:Microsoft.Xna.Framework.Input.GamePadState) object to hold the last known GamePad state (in this example, the **oldState** object).

2. Assign this object a value in your constructor.

3. Call [GamePad.GetState](xref:Microsoft.Xna.Framework.Input.GamePad#Microsoft_Xna_Framework_Input_GamePad_GetState_System_Int32_) to retrieve the current GamePad state (in this example, the **newState** object).

4. Compare the values in your **newState** object to the values in the **oldState** object.

Buttons pressed in the **newState** object that were not pressed in the **oldState** object were pressed during this frame. Conversely, buttons pressed in the **oldState** object that are not pressed in the **newState** object were released during this frame.

> For Thumbsticks and Triggers, it is not necessary to compare to the previous value unless you also need to calculate the difference, e.g. Was the variable controller moved fast or slow. Reading just the current value is usually enough.

5. Update **oldState** object to the **newState** object before leaving **Update**.

```csharp
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;

namespace GamePadInput
{
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
GamePadState oldState;

public Game1()
{
graphics = new GraphicsDeviceManager(this);
}

protected override void Initialize()
{
base.Initialize();
oldState = GamePad.GetState(PlayerIndex.One);
}

protected override void Update(GameTime gameTime)
{
// Allows the game to exit
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
{
this.Exit();
}

UpdateInput();

base.Update(gameTime);
}

private void UpdateInput()
{
GamePadState newState = GamePad.GetState(PlayerIndex.One);

// Is the A Button down?
if (newState.IsButtonDown(Buttons.A))
{
if (!oldState.IsButtonDown(Buttons.A))
{
// If not down last update, the button has just been pressed.
}
}
else if (oldState.IsButtonDown(Buttons.A))
{
// Button was down last update, but not down now, so it has just been released.
}

// Which direction is the right thumbstick being moved?
Vector2 direction = newState.ThumbSticks.Right;

// How much is the left trigger being squeezed?
float leftTriggerAmount = newState.Triggers.Left;

// Update saved state.
oldState = newState;
}

protected override void Draw(GameTime gameTime)
{
base.Draw(gameTime);
}
}
}
```

The above sample demonstrates sampling just the first connected controller, to support multiple controllers, you will need to sample from all connected controllers (as well as managing their connected state in case one is disconnected) and use an array of [GamePadState](xref:Microsoft.Xna.Framework.Input.GamePadState) to maintain the cache of all controllers.

> [!NOTE]
> P.S. Most mobiles these days can support Bluetooth GamePads, so make sure you also support them if you intend to ship your game on mobile!!

## See Also

- [Detecting a Key Press](HowTo_DetectKeyPress.md)
- [Working with Touch Input](HowTo_UseMultiTouchInput.md)

### Reference

- [Microsoft.Xna.Framework.Input](xref:Microsoft.Xna.Framework.Input)
- [GamePadState](xref:Microsoft.Xna.Framework.Input.GamePadState)
- [JoystickState](xref:Microsoft.Xna.Framework.Input.JoystickState)
104 changes: 104 additions & 0 deletions articles/getting_to_know/howto/input/HowTo_DetectKeyPress.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
---
title: Detecting a Key Press
description: The code in this topic describes how to detect a key press or release on the keyboard.
requireMSLicense: true
---

## Overview

By using [Keyboard.GetState](xref:Microsoft.Xna.Framework.Input.Keyboard.GetState) a game can determine which keys are being held down. A game often needs to detect when a user has pressed or released a key. For example, there is the case of an action title that requires users to press and release keys in rapid succession. The example uses a cached [KeyboardState](xref:Microsoft.Xna.Framework.Input.KeyboardState) object to determine if keys were pressed or released in a given frame.

Depending on game design, there may be times when checking for a key press needs to occur more frequently, and other times it does not. It is possible in the case of very fast key presses that more than one key press could occur within one frame. In such a case, the last key press is returned. Writing code that checks as often as possible for key presses is the best way to handle this case.

## Detecting a Key Press or Release

1. Declare a [KeyboardState](xref:Microsoft.Xna.Framework.Input.KeyboardState) object to hold the last known keyboard state (in this example, the **oldState** object).

2. Assign this object a value in your constructor.

3. Call [GetState](xref:Microsoft.Xna.Framework.Input.Keyboard.GetState) to retrieve the current keyboard state (in this example, the **newState** object).

4. Compare the values in your **newState** object to the values in the **oldState** object.

Keys pressed in the **newState** object that were not pressed in the **oldState** object were pressed during this frame. Conversely, keys pressed in the **oldState** object that are not pressed in the **newState** object were released during this frame.

5. Update **oldState** object to the **newState** object before leaving **Update**.

```csharp
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;

namespace Keypress
{
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
KeyboardState oldState;

public Game1()
{
graphics = new GraphicsDeviceManager(this);
}

protected override void Initialize()
{
base.Initialize();
oldState = Keyboard.GetState();
}

protected override void Update(GameTime gameTime)
{
// Allows the game to exit
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
{
this.Exit();
}

UpdateInput();

base.Update(gameTime);
}

private void UpdateInput()
{
KeyboardState newState = Keyboard.GetState();

// Is the SPACE key down?
if (newState.IsKeyDown(Keys.Space))
{
if (!oldState.IsKeyDown(Keys.Space))
{
// If not down last update, key has just been pressed.
}
else
{
// If down last update, key is being held.
}

}
else if (oldState.IsKeyDown(Keys.Space))
{
// Key was down last update, but not down now, so it has just been released.
}

// Update saved state.
oldState = newState;
}

protected override void Draw(GameTime gameTime)
{
base.Draw(gameTime);
}
}
}
```

## See Also

- [Detecting a Button Press](HowTo_DetectGamePadInput.md)
- [Working with Touch Input](HowTo_UseMultiTouchInput.md)

### Reference

- [Microsoft.Xna.Framework.Input](xref:Microsoft.Xna.Framework.Input)
- [KeyboardState](xref:Microsoft.Xna.Framework.Input.KeyboardState)
73 changes: 73 additions & 0 deletions articles/getting_to_know/howto/input/HowTo_Detect_Gestures.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
---
title: Detecting Gestures on a multi-touch Screen
description: This topic demonstrates how to detect and use multi-touch gestures in a MonoGame game.
requireMSLicense: true
---

## Overview

The code in this topic shows you the technique for detecting and using multi-touch gestures. You can download a complete code sample for this topic, including full source code and any additional supporting files required by the sample.

MonoGame supports multi-touch gesture-based input on Mobile. The primary class that provides this support is [TouchPanel](xref:Microsoft.Xna.Framework.Input.Touch.TouchPanel), which provides the ability to:

- Designate which gestures should be detected.
- Query to see if any gestures are available for processing.

> [!NOTE]
> Gesture support is provided as a convenient subset of the features possible on a multi-touch input device. For more information about general multi-touch programming, see [Working with Touch Input](HowTo_UseMultiTouchInput.md).

## How to detect Gestures on a multi-touch Screen

1. Set the gestures to enable with [TouchPanel.EnabledGestures](xref:Microsoft.Xna.Framework.Input.Touch.TouchPanel). This can be one value, or a combination of values, in the [GestureType](xref:Microsoft.Xna.Framework.Input.Touch) enumeration. Performance can be decreased by enabling all gestures, so it is a good practice to enable only the gestures you will be using in your game.

2. During your game loop, check to see if any gestures are available with [TouchPanel.IsGestureAvailable](xref:Microsoft.Xna.Framework.Input.Touch.TouchPanel.IsGestureAvailable). When [IsGestureAvailable](xref:Microsoft.Xna.Framework.Input.Touch.TouchPanel.IsGestureAvailable) is **false**, there are no more gestures in the queue.

3. If gestures are available, call [TouchPanel.ReadGesture](xref:Microsoft.Xna.Framework.Input.Touch.TouchPanel) to get a [GestureSample](xref:Microsoft.Xna.Framework.Input.Touch) that contains the data for the gesture.

> Some gestures will be preceded by another gesture that begins the gesture. For instance, a **DoubleTap** gesture is always preceded by a **Tap** gesture. For more information about the various gesture types supported, see [GestureType](xref:Microsoft.Xna.Framework.Input.Touch).

## Example

The following code illustrates the procedure for detecting gestures on a multi-touch screen.

- Enabling gestures in the game's constructor:

```csharp
// set up touch gesture support: make vertical drag and flick the
// gestures that we are interested in.
TouchPanel.EnabledGestures =
GestureType.VerticalDrag | GestureType.Flick;
```

- Detecting gestures in the game's Update method:

```csharp
// get any gestures that are ready.
while (TouchPanel.IsGestureAvailable)
{
GestureSample gs = TouchPanel.ReadGesture();
switch (gs.GestureType)
{
case GestureType.VerticalDrag:
// move the poem screen vertically by the drag delta amount.
poem.offset.Y -= gs.Delta.Y;
break;

case GestureType.Flick:
// add velocity to the poem screen (only interested in changes to Y velocity).
poem.velocity.Y += gs.Delta.Y;
break;
}
}
```

## See Also

- [Working with Touch Input](HowTo_UseMultiTouchInput.md)

### Reference

- [Microsoft.Xna.Framework.Input.Touch](xref:Microsoft.Xna.Framework.Input.Touch)
- [TouchPanel](xref:Microsoft.Xna.Framework.Input.Touch.TouchPanel)
- [GestureType](xref:Microsoft.Xna.Framework.Input.Touch.GestureType)
- [GestureSample](xref:Microsoft.Xna.Framework.Input.Touch.GestureSample)
80 changes: 80 additions & 0 deletions articles/getting_to_know/howto/input/HowTo_UseMultiTouchInput.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
---
title: How to work with Touch Input
description: This topic demonstrates how to detect and use multi-touch input in a MonoGame game.
requireMSLicense: true
---

## Overview

MonoGame supports multi-touch input on Mobile. The primary class that provides this support is [TouchPanel](xref:Microsoft.Xna.Framework.Input.Touch.TouchPanel), which can:

* Determine the touch capabilities of the current device.
* Get the current state of the touch panel.
* Detect touch gestures such as flicks, pinches, and drags. (For more information, see [Detecting Gestures on a multi-touch Screen](HowTo_Detect_Gestures.md).)

## Determining the Capabilities of the Touch Input Device

By using [TouchPanel.GetCapabilities](xref:Microsoft.Xna.Framework.Input.Touch.TouchPanel.GetCapabilities) you can determine if the touch panel is available. You also can determine the maximum touch count (the number of touches that can be detected simultaneously).

## To determine the capabilities of the touch device

1. Call [TouchPanel.GetCapabilities](xref:Microsoft.Xna.Framework.Input.Touch.TouchPanel), which returns a [TouchPanelCapabilities](xref:Microsoft.Xna.Framework.Input.Touch.TouchPanelCapabilities) structure.

2. Ensure [TouchPanelCapabilities.IsConnected](xref:Microsoft.Xna.Framework.Input.Touch.TouchPanelCapabilities) is **true**, indicating that the touch panel is available for reading.

3. You then can use the [TouchPanelCapabilities.MaximumTouchCount](xref:Microsoft.Xna.Framework.Input.Touch.TouchPanelCapabilities) property to determine how many touch points are supported by the touch panel.

> All touch panels for mobile return a [MaximumTouchCount](xref:Microsoft.Xna.Framework.Input.Touch.TouchPanelCapabilities) value of 4 in MonoGame.

The following code demonstrates how to determine if the touch panel is connected, and then reads the maximum touch count.

```csharp
TouchPanelCapabilities tc = TouchPanel.GetCapabilities();
if(tc.IsConnected)
{
return tc.MaximumTouchCount;
}
```

## Getting multi-touch Data from the Touch Input Device

You can use [TouchPanel.GetState](xref:Microsoft.Xna.Framework.Input.Touch.TouchPanel) to get the current state of the touch input device. It returns a [TouchCollection](xref:Microsoft.Xna.Framework.Input.Touch.TouchCollection) structure that contains a set of [TouchLocation](xref:Microsoft.Xna.Framework.Input.Touch.TouchLocation) structures, each containing information about position and state for a single touch point on the screen.

## To read multi-touch data from the touch input device

1. Call [TouchPanel.GetState](xref:Microsoft.Xna.Framework.Input.Touch.TouchPanel) to get a [TouchCollection](xref:Microsoft.Xna.Framework.Input.Touch.TouchCollection) representing the current state of the device.

2. For each [TouchLocation](xref:Microsoft.Xna.Framework.Input.Touch.TouchLocation) in the [TouchCollection](xref:Microsoft.Xna.Framework.Input.Touch.TouchCollection), read the location and state data provided for each touch point.

The following code demonstrates how to get the current state of the touch input device and read touch data from each [TouchLocation](xref:Microsoft.Xna.Framework.Input.Touch.TouchLocation). It checks to see if a touch location has been pressed or has moved since the last frame, and if so, draws a sprite at the touch location.

```csharp
// Process touch events
TouchCollection touchCollection = TouchPanel.GetState();
foreach (TouchLocation tl in touchCollection)
{
if ((tl.State == TouchLocationState.Pressed)
|| (tl.State == TouchLocationState.Moved))
{

// add sparkles based on the touch location
sparkles.Add(new Sparkle(tl.Position.X,
tl.Position.Y, ttms));

}
}
```

## See Also

- [Detecting Gestures on a Multi-touch Screen](HowTo_Detect_Gestures.md)
- [Detecting a Key Press](HowTo_DetectKeyPress.md)
- [Detecting a Button Press](HowTo_DetectGamePadInput.md)

### Reference

- [Microsoft.Xna.Framework.Input.Touch](xref:Microsoft.Xna.Framework.Input.Touch)
- [TouchPanel](xref:Microsoft.Xna.Framework.Input.Touch.TouchPanel)
- [TouchPanelCapabilities](xref:Microsoft.Xna.Framework.Input.Touch.TouchPanelCapabilities)
- [TouchLocation](xref:Microsoft.Xna.Framework.Input.Touch.TouchLocation)
- [TouchLocationState](xref:Microsoft.Xna.Framework.Input.Touch.TouchLocationState)
Loading