From ba6da1ed0bfde26af47d82dbaa0ceb7bc96e999f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois?= Date: Tue, 13 Apr 2021 03:13:48 +0000 Subject: [PATCH] add documentation on `Input` (#1781) related to #1700 This PR: * documents all methods on `Input` * adds documentation on the struct about how to use it, and how to implement it for a new input type * renames method `update` to a easier to understand `clear` * adds two methods to check for state and clear it after, allowing easier use in the case of #1700 Co-authored-by: Carter Anderson --- crates/bevy_input/src/gamepad.rs | 2 +- crates/bevy_input/src/input.rs | 63 +++++++++++++++++++++++++++---- crates/bevy_input/src/keyboard.rs | 2 +- crates/bevy_input/src/mouse.rs | 2 +- 4 files changed, 59 insertions(+), 10 deletions(-) diff --git a/crates/bevy_input/src/gamepad.rs b/crates/bevy_input/src/gamepad.rs index d16c6acef1e8e..9ba8e018e27bc 100644 --- a/crates/bevy_input/src/gamepad.rs +++ b/crates/bevy_input/src/gamepad.rs @@ -209,7 +209,7 @@ pub fn gamepad_event_system( mut events: EventWriter, settings: Res, ) { - button_input.update(); + button_input.clear(); for event in raw_events.iter() { let (gamepad, event) = (event.0, &event.1); match event { diff --git a/crates/bevy_input/src/input.rs b/crates/bevy_input/src/input.rs index 31e0b9980c4b0..927b37b098668 100644 --- a/crates/bevy_input/src/input.rs +++ b/crates/bevy_input/src/input.rs @@ -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. +/// * 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 { pressed: HashSet, @@ -23,6 +49,7 @@ impl Input 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); @@ -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 { self.pressed.iter() } + /// List all inputs that are just pressed. pub fn get_just_pressed(&self) -> impl ExactSizeIterator { self.just_pressed.iter() } + /// List all inputs that are just released. pub fn get_just_released(&self) -> impl ExactSizeIterator { self.just_released.iter() } @@ -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)); @@ -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)); diff --git a/crates/bevy_input/src/keyboard.rs b/crates/bevy_input/src/keyboard.rs index 7120699c8f578..0d5bdb89f3903 100644 --- a/crates/bevy_input/src/keyboard.rs +++ b/crates/bevy_input/src/keyboard.rs @@ -15,7 +15,7 @@ pub fn keyboard_input_system( mut keyboard_input: ResMut>, mut keyboard_input_events: EventReader, ) { - keyboard_input.update(); + keyboard_input.clear(); for event in keyboard_input_events.iter() { if let KeyboardInput { key_code: Some(key_code), diff --git a/crates/bevy_input/src/mouse.rs b/crates/bevy_input/src/mouse.rs index 7b89e5c101b2c..0c1ed071da6b6 100644 --- a/crates/bevy_input/src/mouse.rs +++ b/crates/bevy_input/src/mouse.rs @@ -47,7 +47,7 @@ pub fn mouse_button_input_system( mut mouse_button_input: ResMut>, mut mouse_button_input_events: EventReader, ) { - 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),