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

[Merged by Bors] - add documentation on Input #1781

Closed
wants to merge 3 commits into from
Closed
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
2 changes: 1 addition & 1 deletion crates/bevy_input/src/gamepad.rs
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ pub fn gamepad_event_system(
mut events: EventWriter<GamepadEvent>,
settings: Res<GamepadSettings>,
) {
button_input.update();
button_input.clear();
for event in raw_events.iter() {
let (gamepad, event) = (event.0, &event.1);
match event {
Expand Down
63 changes: 56 additions & 7 deletions crates/bevy_input/src/input.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,33 @@
use bevy_utils::HashSet;
use std::hash::Hash;

/// A "press-able" input of type `T`
// unused import, but needed for intra doc link to work
#[allow(unused_imports)]
use bevy_ecs::schedule::State;

/// A "press-able" input of type `T`.
///
/// This type can be used as a resource to keep the current state of an input, by reacting to
/// events from the input. For a given input value:
///
/// * [`Input::pressed`] will return `true` between a press and a release event.
/// * [`Input::just_pressed`] will return `true` for one frame after a press event.
/// * [`Input::just_released`] will return `true` for one frame after a release event.
///
/// In case multiple systems are checking for [`Input::just_pressed`] or [`Input::just_released`]
/// but only one should react, for example in the case of triggering
/// [`State`] change, you should consider clearing the input state, either by:
///
/// * Using [`Input::just_pressed_and_clear`] or [`Input::just_released_and_clear`] instead.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wanted to note that these no longer exist with the changes that @cart pushed to this PR (just_pressed_and_clear -> clear_just_pressed).

It might be a good idea to enable rustdoc linting on the CI to catch issues like there?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed those two and another one in #2007

I checked on how to enable rustdoc linting cleanly for our CI, cargo is missing a feature for that, will try to get it. We're also trying to get global dead links check with #1590 but too many errors for now

/// * Calling [`Input::clear`] or [`Input::reset`] immediately after the state change.
///
/// ## Notes when adding this resource for a new input type
///
/// When adding this resource for a new input type, you should:
///
/// * Call the [`Input::press`] method for each press event.
/// * Call the [`Input::release`] method for each release event.
/// * Call the [`Input::clear`] method at each frame start, before processing events.
#[derive(Debug)]
pub struct Input<T> {
pressed: HashSet<T>,
Expand All @@ -23,6 +49,7 @@ impl<T> Input<T>
where
T: Copy + Eq + Hash,
{
/// Register a press for input `input`.
pub fn press(&mut self, input: T) {
if !self.pressed(input) {
self.just_pressed.insert(input);
Expand All @@ -31,42 +58,65 @@ where
self.pressed.insert(input);
}

/// Check if `input` has been pressed.
pub fn pressed(&self, input: T) -> bool {
self.pressed.contains(&input)
}

/// Register a release for input `input`.
pub fn release(&mut self, input: T) {
self.pressed.remove(&input);
self.just_released.insert(input);
}

/// Check if `input` has been just pressed.
pub fn just_pressed(&self, input: T) -> bool {
self.just_pressed.contains(&input)
}

/// Clear the "just pressed" state of `input`. Future calls to [`Input::just_pressed`] for the given
/// input will return false until a new press event occurs.
/// Returns true if `input` is currently "just pressed"
pub fn clear_just_pressed(&mut self, input: T) -> bool {
self.just_pressed.remove(&input)
}

/// Check if `input` has been just released.
pub fn just_released(&self, input: T) -> bool {
self.just_released.contains(&input)
}

/// Clear the "just released" state of `input`. Future calls to [`Input::just_released`] for the given
/// input will return false until a new release event occurs.
/// Returns true if `input` is currently "just released"
pub fn clear_just_released(&mut self, input: T) -> bool {
self.just_released.remove(&input)
}

/// Reset all status for input `input`.
pub fn reset(&mut self, input: T) {
self.pressed.remove(&input);
self.just_pressed.remove(&input);
self.just_released.remove(&input);
}

pub fn update(&mut self) {
/// Clear just pressed and just released information.
pub fn clear(&mut self) {
self.just_pressed.clear();
self.just_released.clear();
}

/// List all inputs that are pressed.
pub fn get_pressed(&self) -> impl ExactSizeIterator<Item = &T> {
self.pressed.iter()
}

/// List all inputs that are just pressed.
pub fn get_just_pressed(&self) -> impl ExactSizeIterator<Item = &T> {
self.just_pressed.iter()
}

/// List all inputs that are just released.
pub fn get_just_released(&self) -> impl ExactSizeIterator<Item = &T> {
self.just_released.iter()
}
Expand Down Expand Up @@ -100,8 +150,8 @@ mod test {
assert!(input.pressed(DummyInput::Input1));
assert!(input.pressed(DummyInput::Input2));

// Update the `Input` and check press state
input.update();
// Clear the `input`, removing just pressed and just released
input.clear();

// Check if they're marked "just pressed"
assert!(!input.just_pressed(DummyInput::Input1));
Expand All @@ -124,9 +174,8 @@ mod test {
assert!(!input.pressed(DummyInput::Input1));
assert!(!input.pressed(DummyInput::Input2));

// Update the `Input` and check for removal from `just_released`

input.update();
// Clear the `Input` and check for removal from `just_released`
input.clear();

// Check that they're not incorrectly marked as just released
assert!(!input.just_released(DummyInput::Input1));
Expand Down
2 changes: 1 addition & 1 deletion crates/bevy_input/src/keyboard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ pub fn keyboard_input_system(
mut keyboard_input: ResMut<Input<KeyCode>>,
mut keyboard_input_events: EventReader<KeyboardInput>,
) {
keyboard_input.update();
keyboard_input.clear();
for event in keyboard_input_events.iter() {
if let KeyboardInput {
key_code: Some(key_code),
Expand Down
2 changes: 1 addition & 1 deletion crates/bevy_input/src/mouse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ pub fn mouse_button_input_system(
mut mouse_button_input: ResMut<Input<MouseButton>>,
mut mouse_button_input_events: EventReader<MouseButtonInput>,
) {
mouse_button_input.update();
mouse_button_input.clear();
for event in mouse_button_input_events.iter() {
match event.state {
ElementState::Pressed => mouse_button_input.press(event.button),
Expand Down