Document gamepad.rs
(#5548)
# Objective - Fixes #5544 - Part of the splitting process of #3692. ## Solution - Document everything in the `gamepad.rs` file. - Add a doc example for mocking gamepad input. --- ## Changelog - Added and updated the documentation inside of the `gamepad.rs` file.
This commit is contained in:
parent
704d8e251b
commit
54750deddd
@ -3,65 +3,115 @@ use bevy_ecs::event::{EventReader, EventWriter};
|
|||||||
use bevy_ecs::system::{Res, ResMut};
|
use bevy_ecs::system::{Res, ResMut};
|
||||||
use bevy_utils::{tracing::info, HashMap, HashSet};
|
use bevy_utils::{tracing::info, HashMap, HashSet};
|
||||||
|
|
||||||
|
/// A gamepad with an associated `ID`.
|
||||||
|
///
|
||||||
|
/// ## Usage
|
||||||
|
///
|
||||||
|
/// The primary way to access the individual connected gamepads is done through the [`Gamepads`]
|
||||||
|
/// `bevy` resource. It is also used inside of [`GamepadEvent`]s and [`GamepadEventRaw`]s to distinguish
|
||||||
|
/// which gamepad an event corresponds to.
|
||||||
|
///
|
||||||
|
/// ## Note
|
||||||
|
///
|
||||||
|
/// The `ID` of a gamepad is fixed until the gamepad disconnects or the app is restarted.
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
|
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
|
||||||
pub struct Gamepad {
|
pub struct Gamepad {
|
||||||
|
/// The `ID` of the gamepad.
|
||||||
pub id: usize,
|
pub id: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Gamepad {
|
impl Gamepad {
|
||||||
|
/// Creates a new [`Gamepad`].
|
||||||
pub fn new(id: usize) -> Self {
|
pub fn new(id: usize) -> Self {
|
||||||
Self { id }
|
Self { id }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Debug)]
|
/// A collection of connected [`Gamepad`]s.
|
||||||
/// Container of unique connected [`Gamepad`]s
|
|
||||||
///
|
///
|
||||||
/// [`Gamepad`]s are registered and deregistered in [`gamepad_connection_system`]
|
/// ## Usage
|
||||||
|
///
|
||||||
|
/// It is stored in a `bevy` resource which tracks all of the currently connected [`Gamepad`]s.
|
||||||
|
///
|
||||||
|
/// ## Updating
|
||||||
|
///
|
||||||
|
/// The [`Gamepad`]s are registered and deregistered in the [`gamepad_connection_system`]
|
||||||
|
/// whenever a [`GamepadEventType::Connected`] or [`GamepadEventType::Disconnected`]
|
||||||
|
/// event is received.
|
||||||
|
#[derive(Default, Debug)]
|
||||||
pub struct Gamepads {
|
pub struct Gamepads {
|
||||||
|
/// The collection of the connected [`Gamepad`]s.
|
||||||
gamepads: HashSet<Gamepad>,
|
gamepads: HashSet<Gamepad>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Gamepads {
|
impl Gamepads {
|
||||||
/// Returns true if the [Gamepads] contains a [Gamepad].
|
/// Returns `true` if the `gamepad` is connected.
|
||||||
pub fn contains(&self, gamepad: &Gamepad) -> bool {
|
pub fn contains(&self, gamepad: &Gamepad) -> bool {
|
||||||
self.gamepads.contains(gamepad)
|
self.gamepads.contains(gamepad)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Iterates over registered [Gamepad]s
|
/// An iterator visiting all connected [`Gamepad`]s in arbitrary order.
|
||||||
pub fn iter(&self) -> impl Iterator<Item = &Gamepad> + '_ {
|
pub fn iter(&self) -> impl Iterator<Item = &Gamepad> + '_ {
|
||||||
self.gamepads.iter()
|
self.gamepads.iter()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Registers [Gamepad].
|
/// Registers the `gamepad` marking it as connected.
|
||||||
fn register(&mut self, gamepad: Gamepad) {
|
fn register(&mut self, gamepad: Gamepad) {
|
||||||
self.gamepads.insert(gamepad);
|
self.gamepads.insert(gamepad);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Deregisters [Gamepad.
|
/// Deregisters the `gamepad` marking it as disconnected.
|
||||||
fn deregister(&mut self, gamepad: &Gamepad) {
|
fn deregister(&mut self, gamepad: &Gamepad) {
|
||||||
self.gamepads.remove(gamepad);
|
self.gamepads.remove(gamepad);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The data contained in a [`GamepadEvent`] or [`GamepadEventRaw`].
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
|
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
|
||||||
pub enum GamepadEventType {
|
pub enum GamepadEventType {
|
||||||
|
/// A [`Gamepad`] has been connected.
|
||||||
Connected,
|
Connected,
|
||||||
|
/// A [`Gamepad`] has been disconnected.
|
||||||
Disconnected,
|
Disconnected,
|
||||||
|
|
||||||
|
/// The value of a [`Gamepad`] button has changed.
|
||||||
ButtonChanged(GamepadButtonType, f32),
|
ButtonChanged(GamepadButtonType, f32),
|
||||||
|
/// The value of a [`Gamepad`] axis has changed.
|
||||||
AxisChanged(GamepadAxisType, f32),
|
AxisChanged(GamepadAxisType, f32),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An event of a [`Gamepad`].
|
||||||
|
///
|
||||||
|
/// This event is the translated version of the [`GamepadEventRaw`]. It is available to
|
||||||
|
/// the end user and can be used for game logic.
|
||||||
|
///
|
||||||
|
/// ## Differences
|
||||||
|
///
|
||||||
|
/// The difference between the [`GamepadEventRaw`] and the [`GamepadEvent`] is that the
|
||||||
|
/// former respects user defined [`GamepadSettings`] for the gamepad inputs when translating it
|
||||||
|
/// to the latter. The former also updates the [`Input<GamepadButton>`], [`Axis<GamepadAxis>`],
|
||||||
|
/// and [`Axis<GamepadButton>`] resources accordingly.
|
||||||
|
///
|
||||||
|
/// ## Gamepad input mocking
|
||||||
|
///
|
||||||
|
/// When mocking gamepad input, use [`GamepadEventRaw`]s instead of [`GamepadEvent`]s.
|
||||||
|
/// Otherwise [`GamepadSettings`] won't be respected and the [`Input<GamepadButton>`],
|
||||||
|
/// [`Axis<GamepadAxis>`], and [`Axis<GamepadButton>`] resources won't be updated correctly.
|
||||||
|
///
|
||||||
|
/// An example for gamepad input mocking can be seen in the documentation of the [`GamepadEventRaw`].
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
|
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
|
||||||
pub struct GamepadEvent {
|
pub struct GamepadEvent {
|
||||||
|
/// The gamepad this event corresponds to.
|
||||||
pub gamepad: Gamepad,
|
pub gamepad: Gamepad,
|
||||||
|
/// The type of the event.
|
||||||
pub event_type: GamepadEventType,
|
pub event_type: GamepadEventType,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GamepadEvent {
|
impl GamepadEvent {
|
||||||
|
/// Creates a new [`GamepadEvent`].
|
||||||
pub fn new(gamepad: Gamepad, event_type: GamepadEventType) -> Self {
|
pub fn new(gamepad: Gamepad, event_type: GamepadEventType) -> Self {
|
||||||
Self {
|
Self {
|
||||||
gamepad,
|
gamepad,
|
||||||
@ -70,14 +120,100 @@ impl GamepadEvent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A raw event of a [`Gamepad`].
|
||||||
|
///
|
||||||
|
/// This event is the translated version of the `EventType` from the `GilRs` crate.
|
||||||
|
/// It is available to the end user and can be used for game logic.
|
||||||
|
///
|
||||||
|
/// ## Differences
|
||||||
|
///
|
||||||
|
/// The difference between the `EventType` from the `GilRs` crate and the [`GamepadEventRaw`]
|
||||||
|
/// is that the latter has less events, because the button pressing logic is handled through the generic
|
||||||
|
/// [`Input<T>`] instead of through events.
|
||||||
|
///
|
||||||
|
/// The difference between the [`GamepadEventRaw`] and the [`GamepadEvent`] can be seen in the documentation
|
||||||
|
/// of the [`GamepadEvent`].
|
||||||
|
///
|
||||||
|
/// ## Gamepad input mocking
|
||||||
|
///
|
||||||
|
/// The following example showcases how to mock gamepad input by manually sending [`GamepadEventRaw`]s.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use bevy_input::prelude::*;
|
||||||
|
/// # use bevy_input::InputPlugin;
|
||||||
|
/// # use bevy_input::gamepad::GamepadEventRaw;
|
||||||
|
/// # use bevy_app::prelude::*;
|
||||||
|
/// # use bevy_ecs::prelude::*;
|
||||||
|
/// #
|
||||||
|
/// // This system sets the `bool` resource to `true` if the `South` button
|
||||||
|
/// // of the first gamepad is pressed.
|
||||||
|
/// fn change_resource_on_gamepad_button_press(
|
||||||
|
/// mut my_resource: ResMut<bool>,
|
||||||
|
/// gamepads: Res<Gamepads>,
|
||||||
|
/// button_inputs: ResMut<Input<GamepadButton>>,
|
||||||
|
/// ) {
|
||||||
|
/// let gamepad = gamepads.iter().next().unwrap();
|
||||||
|
/// let gamepad_button= GamepadButton::new(*gamepad, GamepadButtonType::South);
|
||||||
|
///
|
||||||
|
/// *my_resource = button_inputs.pressed(gamepad_button);
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// // Create our app.
|
||||||
|
/// let mut app = App::new();
|
||||||
|
///
|
||||||
|
/// // Add the input plugin and the system/resource we want to test.
|
||||||
|
/// app.add_plugin(InputPlugin)
|
||||||
|
/// .insert_resource(false)
|
||||||
|
/// .add_system(change_resource_on_gamepad_button_press);
|
||||||
|
///
|
||||||
|
/// // Define our dummy gamepad input data.
|
||||||
|
/// let gamepad = Gamepad::new(0);
|
||||||
|
/// let button_type = GamepadButtonType::South;
|
||||||
|
///
|
||||||
|
/// // Send the gamepad connected event to mark our gamepad as connected.
|
||||||
|
/// // This updates the `Gamepads` resource accordingly.
|
||||||
|
/// app.world.send_event(GamepadEventRaw::new(gamepad, GamepadEventType::Connected));
|
||||||
|
///
|
||||||
|
/// // Send the gamepad input event to mark the `South` gamepad button as pressed.
|
||||||
|
/// // This updates the `Input<GamepadButton>` resource accordingly.
|
||||||
|
/// app.world.send_event(GamepadEventRaw::new(
|
||||||
|
/// gamepad,
|
||||||
|
/// GamepadEventType::ButtonChanged(button_type, 1.0)
|
||||||
|
/// ));
|
||||||
|
///
|
||||||
|
/// // Advance the execution of the schedule by a single cycle.
|
||||||
|
/// app.update();
|
||||||
|
///
|
||||||
|
/// // At this point you can check if your game logic corresponded correctly to the gamepad input.
|
||||||
|
/// // In this example we are checking if the `bool` resource was updated from `false` to `true`.
|
||||||
|
/// assert!(app.world.resource::<bool>());
|
||||||
|
///
|
||||||
|
/// // Send the gamepad input event to mark the `South` gamepad button as released.
|
||||||
|
/// // This updates the `Input<GamepadButton>` resource accordingly.
|
||||||
|
/// app.world.send_event(GamepadEventRaw::new(
|
||||||
|
/// gamepad,
|
||||||
|
/// GamepadEventType::ButtonChanged(button_type, 0.0)
|
||||||
|
/// ));
|
||||||
|
///
|
||||||
|
/// // Advance the execution of the schedule by another cycle.
|
||||||
|
/// app.update();
|
||||||
|
///
|
||||||
|
/// // Check if the `bool` resource was updated from `true` to `false`.
|
||||||
|
/// assert!(!app.world.resource::<bool>());
|
||||||
|
/// #
|
||||||
|
/// # bevy_ecs::system::assert_is_system(change_resource_on_gamepad_button_press);
|
||||||
|
/// ```
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
|
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
|
||||||
pub struct GamepadEventRaw {
|
pub struct GamepadEventRaw {
|
||||||
|
/// The gamepad this event corresponds to.
|
||||||
pub gamepad: Gamepad,
|
pub gamepad: Gamepad,
|
||||||
|
/// The type of the event.
|
||||||
pub event_type: GamepadEventType,
|
pub event_type: GamepadEventType,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GamepadEventRaw {
|
impl GamepadEventRaw {
|
||||||
|
/// Creates a new [`GamepadEventRaw`].
|
||||||
pub fn new(gamepad: Gamepad, event_type: GamepadEventType) -> Self {
|
pub fn new(gamepad: Gamepad, event_type: GamepadEventType) -> Self {
|
||||||
Self {
|
Self {
|
||||||
gamepad,
|
gamepad,
|
||||||
@ -86,38 +222,93 @@ impl GamepadEventRaw {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A type of a [`GamepadButton`].
|
||||||
|
///
|
||||||
|
/// ## Usage
|
||||||
|
///
|
||||||
|
/// This is used to determine which button has changed its value when receiving a
|
||||||
|
/// [`GamepadEventType::ButtonChanged`]. It is also used in the [`GamepadButton`]
|
||||||
|
/// which in turn is used to create the [`Input<GamepadButton>`] or
|
||||||
|
/// [`Axis<GamepadButton>`] `bevy` resources.
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
|
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
|
||||||
pub enum GamepadButtonType {
|
pub enum GamepadButtonType {
|
||||||
|
/// The bottom action button of the action pad (i.e. PS: Cross, Xbox: A).
|
||||||
South,
|
South,
|
||||||
|
/// The right action button of the action pad (i.e. PS: Circle, Xbox: B).
|
||||||
East,
|
East,
|
||||||
|
/// The upper action button of the action pad (i.e. PS: Triangle, Xbox: Y).
|
||||||
North,
|
North,
|
||||||
|
/// The left action button of the action pad (i.e. PS: Square, Xbox: X).
|
||||||
West,
|
West,
|
||||||
|
|
||||||
|
/// The C button.
|
||||||
C,
|
C,
|
||||||
|
/// The Z button.
|
||||||
Z,
|
Z,
|
||||||
|
|
||||||
|
/// The first left trigger.
|
||||||
LeftTrigger,
|
LeftTrigger,
|
||||||
|
/// The second left trigger.
|
||||||
LeftTrigger2,
|
LeftTrigger2,
|
||||||
|
/// The first right trigger.
|
||||||
RightTrigger,
|
RightTrigger,
|
||||||
|
/// The second right trigger.
|
||||||
RightTrigger2,
|
RightTrigger2,
|
||||||
|
/// The select button.
|
||||||
Select,
|
Select,
|
||||||
|
/// The start button.
|
||||||
Start,
|
Start,
|
||||||
|
/// The mode button.
|
||||||
Mode,
|
Mode,
|
||||||
|
|
||||||
|
/// The left thumb stick button.
|
||||||
LeftThumb,
|
LeftThumb,
|
||||||
|
/// The right thumb stick button.
|
||||||
RightThumb,
|
RightThumb,
|
||||||
|
|
||||||
|
/// The up button of the D-Pad.
|
||||||
DPadUp,
|
DPadUp,
|
||||||
|
/// The down button of the D-Pad.
|
||||||
DPadDown,
|
DPadDown,
|
||||||
|
/// The left button of the D-Pad.
|
||||||
DPadLeft,
|
DPadLeft,
|
||||||
|
/// The right button of the D-Pad.
|
||||||
DPadRight,
|
DPadRight,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A button of a [`Gamepad`].
|
||||||
|
///
|
||||||
|
/// ## Usage
|
||||||
|
///
|
||||||
|
/// It is used as the generic `T` value of an [`Input`] and [`Axis`] to create `bevy` resources. These
|
||||||
|
/// resources store the data of the buttons and axes of a gamepad and can be accessed inside of a system.
|
||||||
|
///
|
||||||
|
/// ## Updating
|
||||||
|
///
|
||||||
|
/// The resources are updated inside of the [`gamepad_event_system`].
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
|
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
|
||||||
pub struct GamepadButton {
|
pub struct GamepadButton {
|
||||||
|
/// The gamepad on which the button is located on.
|
||||||
pub gamepad: Gamepad,
|
pub gamepad: Gamepad,
|
||||||
|
/// The type of the button.
|
||||||
pub button_type: GamepadButtonType,
|
pub button_type: GamepadButtonType,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GamepadButton {
|
impl GamepadButton {
|
||||||
|
/// Creates a new [`GamepadButton`].
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use bevy_input::gamepad::{GamepadButton, GamepadButtonType, Gamepad};
|
||||||
|
/// #
|
||||||
|
/// let gamepad_button = GamepadButton::new(
|
||||||
|
/// Gamepad::new(1),
|
||||||
|
/// GamepadButtonType::South,
|
||||||
|
/// );
|
||||||
|
/// ```
|
||||||
pub fn new(gamepad: Gamepad, button_type: GamepadButtonType) -> Self {
|
pub fn new(gamepad: Gamepad, button_type: GamepadButtonType) -> Self {
|
||||||
Self {
|
Self {
|
||||||
gamepad,
|
gamepad,
|
||||||
@ -126,53 +317,148 @@ impl GamepadButton {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A type of a [`GamepadAxis`].
|
||||||
|
///
|
||||||
|
/// ## Usage
|
||||||
|
///
|
||||||
|
/// This is used to determine which axis has changed its value when receiving a
|
||||||
|
/// [`GamepadEventType::AxisChanged`]. It is also used in the [`GamepadAxis`]
|
||||||
|
/// which in turn is used to create the [`Axis<GamepadAxis>`] `bevy` resource.
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
|
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
|
||||||
pub enum GamepadAxisType {
|
pub enum GamepadAxisType {
|
||||||
|
/// The horizontal value of the left stick.
|
||||||
LeftStickX,
|
LeftStickX,
|
||||||
|
/// The vertical value of the left stick.
|
||||||
LeftStickY,
|
LeftStickY,
|
||||||
|
/// The value of the left `Z` button.
|
||||||
LeftZ,
|
LeftZ,
|
||||||
|
|
||||||
|
/// The horizontal value of the right stick.
|
||||||
RightStickX,
|
RightStickX,
|
||||||
|
/// The vertical value of the right stick.
|
||||||
RightStickY,
|
RightStickY,
|
||||||
|
/// The value of the right `Z` button.
|
||||||
RightZ,
|
RightZ,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An axis of a [`Gamepad`].
|
||||||
|
///
|
||||||
|
/// ## Usage
|
||||||
|
///
|
||||||
|
/// It is used as the generic `T` value of an [`Axis`] to create a `bevy` resource. This resource
|
||||||
|
/// stores the data of the axes of a gamepad and can be accessed inside of a system.
|
||||||
|
///
|
||||||
|
/// ## Updating
|
||||||
|
///
|
||||||
|
/// The resource is updated inside of the [`gamepad_event_system`].
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
|
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
|
||||||
pub struct GamepadAxis {
|
pub struct GamepadAxis {
|
||||||
|
/// The gamepad on which the axis is located on.
|
||||||
pub gamepad: Gamepad,
|
pub gamepad: Gamepad,
|
||||||
|
/// The type of the axis.
|
||||||
pub axis_type: GamepadAxisType,
|
pub axis_type: GamepadAxisType,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GamepadAxis {
|
impl GamepadAxis {
|
||||||
|
/// Creates a new [`GamepadAxis`].
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use bevy_input::gamepad::{GamepadAxis, GamepadAxisType, Gamepad};
|
||||||
|
/// #
|
||||||
|
/// let gamepad_axis = GamepadAxis::new(
|
||||||
|
/// Gamepad::new(1),
|
||||||
|
/// GamepadAxisType::LeftStickX,
|
||||||
|
/// );
|
||||||
|
/// ```
|
||||||
pub fn new(gamepad: Gamepad, axis_type: GamepadAxisType) -> Self {
|
pub fn new(gamepad: Gamepad, axis_type: GamepadAxisType) -> Self {
|
||||||
Self { gamepad, axis_type }
|
Self { gamepad, axis_type }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Settings for all [`Gamepad`]s.
|
||||||
|
///
|
||||||
|
/// ## Usage
|
||||||
|
///
|
||||||
|
/// It is used to create a `bevy` resource that stores the settings of every [`GamepadButton`] and
|
||||||
|
/// [`GamepadAxis`]. If no user defined [`ButtonSettings`], [`AxisSettings`], or [`ButtonAxisSettings`]
|
||||||
|
/// are defined, the default settings of each are used as a fallback accordingly.
|
||||||
|
///
|
||||||
|
/// ## Note
|
||||||
|
///
|
||||||
|
/// The [`GamepadSettings`] are used inside of the [`gamepad_event_system`], but are never written to
|
||||||
|
/// inside of `bevy`. To modify these settings, mutate the corresponding resource.
|
||||||
#[derive(Default, Debug)]
|
#[derive(Default, Debug)]
|
||||||
pub struct GamepadSettings {
|
pub struct GamepadSettings {
|
||||||
|
/// The default button settings.
|
||||||
pub default_button_settings: ButtonSettings,
|
pub default_button_settings: ButtonSettings,
|
||||||
|
/// The default axis settings.
|
||||||
pub default_axis_settings: AxisSettings,
|
pub default_axis_settings: AxisSettings,
|
||||||
|
/// The default button axis settings.
|
||||||
pub default_button_axis_settings: ButtonAxisSettings,
|
pub default_button_axis_settings: ButtonAxisSettings,
|
||||||
|
/// The user defined button settings.
|
||||||
pub button_settings: HashMap<GamepadButton, ButtonSettings>,
|
pub button_settings: HashMap<GamepadButton, ButtonSettings>,
|
||||||
|
/// The user defined axis settings.
|
||||||
pub axis_settings: HashMap<GamepadAxis, AxisSettings>,
|
pub axis_settings: HashMap<GamepadAxis, AxisSettings>,
|
||||||
|
/// The user defined button axis settings.
|
||||||
pub button_axis_settings: HashMap<GamepadButton, ButtonAxisSettings>,
|
pub button_axis_settings: HashMap<GamepadButton, ButtonAxisSettings>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GamepadSettings {
|
impl GamepadSettings {
|
||||||
|
/// Returns the [`ButtonSettings`] of the `button`.
|
||||||
|
///
|
||||||
|
/// If no user defined [`ButtonSettings`] are specified the default [`ButtonSettings`] get returned.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use bevy_input::gamepad::{GamepadSettings, GamepadButton, Gamepad, GamepadButtonType};
|
||||||
|
/// #
|
||||||
|
/// # let settings = GamepadSettings::default();
|
||||||
|
/// let button = GamepadButton::new(Gamepad::new(1), GamepadButtonType::South);
|
||||||
|
/// let button_settings = settings.get_button_settings(button);
|
||||||
|
/// ```
|
||||||
pub fn get_button_settings(&self, button: GamepadButton) -> &ButtonSettings {
|
pub fn get_button_settings(&self, button: GamepadButton) -> &ButtonSettings {
|
||||||
self.button_settings
|
self.button_settings
|
||||||
.get(&button)
|
.get(&button)
|
||||||
.unwrap_or(&self.default_button_settings)
|
.unwrap_or(&self.default_button_settings)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the [`AxisSettings`] of the `axis`.
|
||||||
|
///
|
||||||
|
/// If no user defined [`AxisSettings`] are specified the default [`AxisSettings`] get returned.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use bevy_input::gamepad::{GamepadSettings, GamepadAxis, Gamepad, GamepadAxisType};
|
||||||
|
/// #
|
||||||
|
/// # let settings = GamepadSettings::default();
|
||||||
|
/// let axis = GamepadAxis::new(Gamepad::new(1), GamepadAxisType::LeftStickX);
|
||||||
|
/// let axis_settings = settings.get_axis_settings(axis);
|
||||||
|
/// ```
|
||||||
pub fn get_axis_settings(&self, axis: GamepadAxis) -> &AxisSettings {
|
pub fn get_axis_settings(&self, axis: GamepadAxis) -> &AxisSettings {
|
||||||
self.axis_settings
|
self.axis_settings
|
||||||
.get(&axis)
|
.get(&axis)
|
||||||
.unwrap_or(&self.default_axis_settings)
|
.unwrap_or(&self.default_axis_settings)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the [`ButtonAxisSettings`] of the `button`.
|
||||||
|
///
|
||||||
|
/// If no user defined [`ButtonAxisSettings`] are specified the default [`ButtonAxisSettings`] get returned.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use bevy_input::gamepad::{GamepadSettings, GamepadButton, Gamepad, GamepadButtonType};
|
||||||
|
/// #
|
||||||
|
/// # let settings = GamepadSettings::default();
|
||||||
|
/// let button = GamepadButton::new(Gamepad::new(1), GamepadButtonType::South);
|
||||||
|
/// let button_axis_settings = settings.get_button_axis_settings(button);
|
||||||
|
/// ```
|
||||||
pub fn get_button_axis_settings(&self, button: GamepadButton) -> &ButtonAxisSettings {
|
pub fn get_button_axis_settings(&self, button: GamepadButton) -> &ButtonAxisSettings {
|
||||||
self.button_axis_settings
|
self.button_axis_settings
|
||||||
.get(&button)
|
.get(&button)
|
||||||
@ -180,9 +466,22 @@ impl GamepadSettings {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Settings for a [`GamepadButton`].
|
||||||
|
///
|
||||||
|
/// ## Usage
|
||||||
|
///
|
||||||
|
/// It is used inside of the [`GamepadSettings`] to define the threshold for a gamepad button
|
||||||
|
/// to be considered pressed or released. A button is considered pressed if the `press`
|
||||||
|
/// value is surpassed and released if the `release` value is undercut.
|
||||||
|
///
|
||||||
|
/// ## Updating
|
||||||
|
///
|
||||||
|
/// The current value of a button is received through the [`GamepadEvent`]s or [`GamepadEventRaw`]s.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct ButtonSettings {
|
pub struct ButtonSettings {
|
||||||
|
/// The threshold for the button to be considered as pressed.
|
||||||
pub press: f32,
|
pub press: f32,
|
||||||
|
/// The threshold for the button to be considered as released.
|
||||||
pub release: f32,
|
pub release: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -196,30 +495,49 @@ impl Default for ButtonSettings {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ButtonSettings {
|
impl ButtonSettings {
|
||||||
|
/// Returns `true` if the button is pressed.
|
||||||
|
///
|
||||||
|
/// A button is considered pressed if the `value` passed is greater than or equal to the `press` threshold.
|
||||||
fn is_pressed(&self, value: f32) -> bool {
|
fn is_pressed(&self, value: f32) -> bool {
|
||||||
value >= self.press
|
value >= self.press
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns `true` if the button is released.
|
||||||
|
///
|
||||||
|
/// A button is considered released if the `value` passed is lower than or equal to the `release` threshold.
|
||||||
fn is_released(&self, value: f32) -> bool {
|
fn is_released(&self, value: f32) -> bool {
|
||||||
value <= self.release
|
value <= self.release
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Defines the sensitivity range and threshold for an axis.
|
/// Settings for a [`GamepadAxis`].
|
||||||
///
|
///
|
||||||
/// Values that are lower than `negative_high` will be rounded to -1.0.
|
/// It is used inside of the [`GamepadSettings`] to define the sensitivity range and
|
||||||
/// Values that are higher than `positive_high` will be rounded to 1.0.
|
/// threshold for an axis.
|
||||||
/// Values that are in-between `negative_low` and `positive_low` will be rounded to 0.0.
|
///
|
||||||
/// Otherwise, values will not be rounded.
|
/// ## Logic
|
||||||
|
///
|
||||||
|
/// - Values that are in-between `negative_low` and `positive_low` will be rounded to 0.0.
|
||||||
|
/// - Values that are higher than or equal to `positive_high` will be rounded to 1.0.
|
||||||
|
/// - Values that are lower than or equal to `negative_high` will be rounded to -1.0.
|
||||||
|
/// - Otherwise, values will not be rounded.
|
||||||
///
|
///
|
||||||
/// The valid range is from -1.0 to 1.0, inclusive.
|
/// The valid range is from -1.0 to 1.0, inclusive.
|
||||||
|
///
|
||||||
|
/// ## Updating
|
||||||
|
///
|
||||||
|
/// The current value of an axis is received through the [`GamepadEvent`]s or [`GamepadEventRaw`]s.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct AxisSettings {
|
pub struct AxisSettings {
|
||||||
|
/// The positive high value at which to apply rounding.
|
||||||
pub positive_high: f32,
|
pub positive_high: f32,
|
||||||
|
/// The positive low value at which to apply rounding.
|
||||||
pub positive_low: f32,
|
pub positive_low: f32,
|
||||||
|
/// The negative high value at which to apply rounding.
|
||||||
pub negative_high: f32,
|
pub negative_high: f32,
|
||||||
|
/// The negative low value at which to apply rounding.
|
||||||
pub negative_low: f32,
|
pub negative_low: f32,
|
||||||
///`threshold` defines the minimum difference between old and new values to apply the changes.
|
/// The threshold defining the minimum difference between the old and new values to apply the changes.
|
||||||
pub threshold: f32,
|
pub threshold: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -236,6 +554,16 @@ impl Default for AxisSettings {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AxisSettings {
|
impl AxisSettings {
|
||||||
|
/// Filters the `new_value` according to the specified settings.
|
||||||
|
///
|
||||||
|
/// If the `new_value` is:
|
||||||
|
/// - in-between `negative_low` and `positive_low` it will be rounded to 0.0.
|
||||||
|
/// - higher than or equal to `positive_high` it will be rounded to 1.0.
|
||||||
|
/// - lower than or equal to `negative_high` it will be rounded to -1.0.
|
||||||
|
/// - Otherwise it will not be rounded.
|
||||||
|
///
|
||||||
|
/// If the difference between the calculated value and the `old_value` is lower or
|
||||||
|
/// equal to the `threshold`, [`None`] will be returned.
|
||||||
fn filter(&self, new_value: f32, old_value: Option<f32>) -> Option<f32> {
|
fn filter(&self, new_value: f32, old_value: Option<f32>) -> Option<f32> {
|
||||||
let new_value = if new_value <= self.positive_low && new_value >= self.negative_low {
|
let new_value = if new_value <= self.positive_low && new_value >= self.negative_low {
|
||||||
0.0
|
0.0
|
||||||
@ -257,10 +585,29 @@ impl AxisSettings {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Settings for a [`GamepadButton`].
|
||||||
|
///
|
||||||
|
/// It is used inside of the [`GamepadSettings`] to define the sensitivity range and
|
||||||
|
/// threshold for a button axis.
|
||||||
|
///
|
||||||
|
/// ## Logic
|
||||||
|
///
|
||||||
|
/// - Values that are higher than or equal to `high` will be rounded to 1.0.
|
||||||
|
/// - Values that are lower than or equal to `low` will be rounded to 0.0.
|
||||||
|
/// - Otherwise, values will not be rounded.
|
||||||
|
///
|
||||||
|
/// The valid range is from 0.0 to 1.0, inclusive.
|
||||||
|
///
|
||||||
|
/// ## Updating
|
||||||
|
///
|
||||||
|
/// The current value of a button is received through the [`GamepadEvent`]s or [`GamepadEventRaw`]s.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct ButtonAxisSettings {
|
pub struct ButtonAxisSettings {
|
||||||
|
/// The high value at which to apply rounding.
|
||||||
pub high: f32,
|
pub high: f32,
|
||||||
|
/// The low value at which to apply rounding.
|
||||||
pub low: f32,
|
pub low: f32,
|
||||||
|
/// The threshold to apply rounding.
|
||||||
pub threshold: f32,
|
pub threshold: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -275,6 +622,15 @@ impl Default for ButtonAxisSettings {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ButtonAxisSettings {
|
impl ButtonAxisSettings {
|
||||||
|
/// Filters the `new_value` according to the specified settings.
|
||||||
|
///
|
||||||
|
/// If the `new_value` is:
|
||||||
|
/// - lower than or equal to `low` it will be rounded to 0.0.
|
||||||
|
/// - higher than or equal to `high` it will be rounded to 1.0.
|
||||||
|
/// - Otherwise it will not be rounded.
|
||||||
|
///
|
||||||
|
/// If the difference between the calculated value and the `old_value` is lower or
|
||||||
|
/// equal to the `threshold`, [`None`] will be returned.
|
||||||
fn filter(&self, new_value: f32, old_value: Option<f32>) -> Option<f32> {
|
fn filter(&self, new_value: f32, old_value: Option<f32>) -> Option<f32> {
|
||||||
let new_value = if new_value <= self.low {
|
let new_value = if new_value <= self.low {
|
||||||
0.0
|
0.0
|
||||||
@ -294,9 +650,11 @@ impl ButtonAxisSettings {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Monitors gamepad connection and disconnection events, updating the [`Gamepads`] resource accordingly
|
/// Monitors gamepad connection and disconnection events and updates the [`Gamepads`] resource accordingly.
|
||||||
///
|
///
|
||||||
/// By default, runs during `CoreStage::PreUpdate` when added via [`InputPlugin`](crate::InputPlugin).
|
/// ## Note
|
||||||
|
///
|
||||||
|
/// Whenever a [`Gamepad`] connects or disconnects, an information gets printed to the console using the [`info!`] macro.
|
||||||
pub fn gamepad_connection_system(
|
pub fn gamepad_connection_system(
|
||||||
mut gamepads: ResMut<Gamepads>,
|
mut gamepads: ResMut<Gamepads>,
|
||||||
mut gamepad_event: EventReader<GamepadEvent>,
|
mut gamepad_event: EventReader<GamepadEvent>,
|
||||||
@ -316,6 +674,16 @@ pub fn gamepad_connection_system(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Modifies the gamepad resources and sends out gamepad events.
|
||||||
|
///
|
||||||
|
/// The resources [`Input<GamepadButton>`], [`Axis<GamepadAxis>`], and [`Axis<GamepadButton>`] are updated
|
||||||
|
/// and the [`GamepadEvent`]s are sent according to the received [`GamepadEventRaw`]s respecting the [`GamepadSettings`].
|
||||||
|
///
|
||||||
|
/// ## Differences
|
||||||
|
///
|
||||||
|
/// The main difference between the events and the resources is that the latter allows you to check specific
|
||||||
|
/// buttons or axes, rather than reading the events one at a time. This is done through convenient functions
|
||||||
|
/// like [`Input::pressed`], [`Input::just_pressed`], [`Input::just_released`], and [`Axis::get`].
|
||||||
pub fn gamepad_event_system(
|
pub fn gamepad_event_system(
|
||||||
mut button_input: ResMut<Input<GamepadButton>>,
|
mut button_input: ResMut<Input<GamepadButton>>,
|
||||||
mut axis: ResMut<Axis<GamepadAxis>>,
|
mut axis: ResMut<Axis<GamepadAxis>>,
|
||||||
@ -388,6 +756,7 @@ pub fn gamepad_event_system(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An array of every [`GamepadButtonType`] variant.
|
||||||
const ALL_BUTTON_TYPES: [GamepadButtonType; 19] = [
|
const ALL_BUTTON_TYPES: [GamepadButtonType; 19] = [
|
||||||
GamepadButtonType::South,
|
GamepadButtonType::South,
|
||||||
GamepadButtonType::East,
|
GamepadButtonType::East,
|
||||||
@ -410,6 +779,7 @@ const ALL_BUTTON_TYPES: [GamepadButtonType; 19] = [
|
|||||||
GamepadButtonType::DPadRight,
|
GamepadButtonType::DPadRight,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
/// An array of every [`GamepadAxisType`] variant.
|
||||||
const ALL_AXIS_TYPES: [GamepadAxisType; 6] = [
|
const ALL_AXIS_TYPES: [GamepadAxisType; 6] = [
|
||||||
GamepadAxisType::LeftStickX,
|
GamepadAxisType::LeftStickX,
|
||||||
GamepadAxisType::LeftStickY,
|
GamepadAxisType::LeftStickY,
|
||||||
|
Loading…
Reference in New Issue
Block a user