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 common run conditions to bevy_input #7806

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
3 changes: 3 additions & 0 deletions crates/bevy_input/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,6 @@ bevy_reflect = { path = "../bevy_reflect", version = "0.9.0", features = ["glam"
# other
serde = { version = "1", features = ["derive"], optional = true }
thiserror = "1.0"

[dev-dependencies]
bevy = { path = "../../", version = "0.9.0" }
97 changes: 97 additions & 0 deletions crates/bevy_input/src/common_conditions.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
use crate::Input;
use bevy_ecs::system::Res;
use std::hash::Hash;

/// Stateful run condition that can be toggled via a input press using [`Input::just_pressed`].
///
/// ```rust,no_run
/// use bevy::prelude::*;
/// use bevy::input::common_conditions::input_toggle_active;
///
/// fn main() {
/// App::new()
/// .add_plugins(DefaultPlugins)
/// .add_system(pause_menu.run_if(input_toggle_active(false, KeyCode::Escape)))
/// .run();
/// }
///
/// fn pause_menu() {
/// println!("in pause menu");
/// }
/// ```
///
/// If you want other systems to be able to access whether the toggled state is active,
/// you should use a custom resource or a state for that:
/// ```rust,no_run
/// use bevy::prelude::*;
/// use bevy::input::common_conditions::input_toggle_active;
///
/// #[derive(Resource, Default)]
/// struct Paused(bool);
///
/// fn main() {
/// App::new()
/// .add_plugins(DefaultPlugins)
/// .init_resource::<Paused>()
/// .add_system(pause_menu.run_if(|paused: Res<Paused>| paused.0))
/// .run();
/// }
///
/// fn update_pause_state(mut paused: ResMut<Paused>, input: Input<KeyCode>) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Nitpick: I think I see what you are going for, but it's a little confusing because I don't think update_pause_state is ever getting called. Should that be in the schedule somewhere?

/// if input.just_pressed(KeyCode::Escape) {
/// paused.0 = !paused.0;
/// }
/// }
///
/// fn pause_menu() {
/// println!("in pause menu");
/// }
///
/// ```
pub fn input_toggle_active<T>(default: bool, input: T) -> impl FnMut(Res<Input<T>>) -> bool
Copy link
Contributor

Choose a reason for hiding this comment

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

❓ Where is this function getting called?

where
T: Copy + Eq + Hash + Send + Sync + 'static,
{
let mut active = default;
move |inputs: Res<Input<T>>| {
active ^= inputs.just_pressed(input);
Copy link
Contributor

Choose a reason for hiding this comment

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

Would you mind explaining what this symbol is ^= for my smooth brain pls lol. I think I understand but it'd be worth clarifying haha.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's xor assign. So basically if just_pressed { active = !active }.
Reading this I had to think for a minute to know why this works so I should probably just write the simpler clearer way lol

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It works because

inactive ^ not pressed -> inactive
inactive ^ pressed -> active
active ^ not pressed -> active
active ^ pressed -> inactive

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, okay I think that makes sense to me lol.

active
}
}

/// Run condition that is active if [`Input::pressed`] is true for the given input.
pub fn input_pressed<T>(input: T) -> impl FnMut(Res<Input<T>>) -> bool
where
T: Copy + Eq + Hash + Send + Sync + 'static,
{
move |inputs: Res<Input<T>>| inputs.pressed(input)
}

/// Run condition that is active if [`Input::just_pressed`] is true for the given input.
///
/// ```rust,no_run
/// use bevy::prelude::*;
/// use bevy::input::common_conditions::input_just_pressed;
/// fn main() {
/// App::new()
/// .add_plugins(DefaultPlugins)
/// .add_system(jump.run_if(input_just_pressed(KeyCode::Space)))
/// .run();
/// }
///
/// # fn jump() {}
/// ```
pub fn input_just_pressed<T>(input: T) -> impl FnMut(Res<Input<T>>) -> bool
where
T: Copy + Eq + Hash + Send + Sync + 'static,
{
move |inputs: Res<Input<T>>| inputs.just_pressed(input)
}

/// Run condition that is active if [`Input::just_released`] is true for the given input.
pub fn input_just_released<T>(input: T) -> impl FnMut(Res<Input<T>>) -> bool
where
T: Copy + Eq + Hash + Send + Sync + 'static,
{
move |inputs: Res<Input<T>>| inputs.just_released(input)
}
2 changes: 2 additions & 0 deletions crates/bevy_input/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
mod axis;
/// Common run conditions
pub mod common_conditions;
pub mod gamepad;
mod input;
pub mod keyboard;
Expand Down