From 20fbe83ec2cf6377afcb08022bcf85ca2a155cdd Mon Sep 17 00:00:00 2001 From: Utkarsh Date: Sun, 18 Oct 2020 13:31:18 +0530 Subject: [PATCH 1/3] Separated gamepad event and gamepad state code and made gamepad input more customizable --- Cargo.toml | 4 + crates/bevy_gilrs/src/gilrs_system.rs | 171 +++--------------- crates/bevy_gilrs/src/lib.rs | 19 +- crates/bevy_input/src/gamepad.rs | 238 +++++++++++++++++++++++++- crates/bevy_input/src/lib.rs | 9 +- examples/input/gamepad_input.rs | 57 +++--- examples/input/gamepad_input_event.rs | 34 ++++ 7 files changed, 355 insertions(+), 177 deletions(-) create mode 100644 examples/input/gamepad_input_event.rs diff --git a/Cargo.toml b/Cargo.toml index a38db3beae0c0..c36940d77fda8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -230,6 +230,10 @@ path = "examples/input/keyboard_input_events.rs" name = "gamepad_input" path = "examples/input/gamepad_input.rs" +[[example]] +name = "gamepad_input_event" +path = "examples/input/gamepad_input_event.rs" + [[example]] name = "touch_input" path = "examples/input/touch_input.rs" diff --git a/crates/bevy_gilrs/src/gilrs_system.rs b/crates/bevy_gilrs/src/gilrs_system.rs index 22bb3b527583e..f448fdeb2aee8 100644 --- a/crates/bevy_gilrs/src/gilrs_system.rs +++ b/crates/bevy_gilrs/src/gilrs_system.rs @@ -2,88 +2,52 @@ use crate::converter::{convert_axis, convert_button, convert_gamepad_id}; use bevy_app::Events; use bevy_ecs::{Resources, World}; use bevy_input::prelude::*; -use gilrs::{Button, EventType, Gilrs}; +use gilrs::{EventType, Gilrs}; -pub fn gilrs_startup_system(_world: &mut World, resources: &mut Resources) { +pub fn gilrs_event_startup_system(_world: &mut World, resources: &mut Resources) { let gilrs = resources.get_thread_local::().unwrap(); - let mut gamepad_event = resources.get_mut::>().unwrap(); - let mut inputs = resources.get_mut::>().unwrap(); - let mut axes = resources.get_mut::>().unwrap(); - let mut button_axes = resources.get_mut::>().unwrap(); - gamepad_event.update(); - inputs.update(); - for (gilrs_id, gilrs_gamepad) in gilrs.gamepads() { - connect_gamepad( - gilrs_gamepad, - convert_gamepad_id(gilrs_id), - &mut gamepad_event, - &mut inputs, - &mut axes, - &mut button_axes, - ); + let mut event = resources.get_mut::>().unwrap(); + event.update(); + for (id, _) in gilrs.gamepads() { + event.send(GamepadEvent( + convert_gamepad_id(id), + GamepadEventType::Connected, + )); } } -pub fn gilrs_update_system(_world: &mut World, resources: &mut Resources) { +pub fn girls_event_system(_world: &mut World, resources: &mut Resources) { let mut gilrs = resources.get_thread_local_mut::().unwrap(); - let mut gamepad_event = resources.get_mut::>().unwrap(); - let mut inputs = resources.get_mut::>().unwrap(); - let mut axes = resources.get_mut::>().unwrap(); - let mut button_axes = resources.get_mut::>().unwrap(); - - gamepad_event.update(); - inputs.update(); + let mut event = resources.get_mut::>().unwrap(); + event.update(); while let Some(gilrs_event) = gilrs.next_event() { match gilrs_event.event { EventType::Connected => { - connect_gamepad( - gilrs.gamepad(gilrs_event.id), + event.send(GamepadEvent( convert_gamepad_id(gilrs_event.id), - &mut gamepad_event, - &mut inputs, - &mut axes, - &mut button_axes, - ); + GamepadEventType::Connected, + )); } EventType::Disconnected => { - disconnect_gamepad( + event.send(GamepadEvent( convert_gamepad_id(gilrs_event.id), - &mut gamepad_event, - &mut inputs, - &mut axes, - &mut button_axes, - ); + GamepadEventType::Disconnected, + )); } - EventType::ButtonPressed(gilrs_button, _) => { - if let Some(button_type) = convert_button(gilrs_button) { - inputs.press(GamepadButton( - convert_gamepad_id(gilrs_event.id), - button_type, - )); - } - } - EventType::ButtonReleased(gilrs_button, _) => { + EventType::ButtonChanged(gilrs_button, value, _) => { if let Some(button_type) = convert_button(gilrs_button) { - inputs.release(GamepadButton( + event.send(GamepadEvent( convert_gamepad_id(gilrs_event.id), - button_type, + GamepadEventType::ButtonChanged(button_type, value), )); } } - EventType::ButtonChanged(gilrs_button, value, _) => { - if let Some(button_type) = convert_button(gilrs_button) { - button_axes.set( - GamepadButton(convert_gamepad_id(gilrs_event.id), button_type), - value, - ); - } - } EventType::AxisChanged(gilrs_axis, value, _) => { if let Some(axis_type) = convert_axis(gilrs_axis) { - axes.set( - GamepadAxis(convert_gamepad_id(gilrs_event.id), axis_type), - value, - ); + event.send(GamepadEvent( + convert_gamepad_id(gilrs_event.id), + GamepadEventType::AxisChanged(axis_type, value), + )); } } _ => (), @@ -91,88 +55,3 @@ pub fn gilrs_update_system(_world: &mut World, resources: &mut Resources) { } gilrs.inc(); } - -const ALL_GILRS_BUTTONS: [Button; 19] = [ - Button::South, - Button::East, - Button::North, - Button::West, - Button::C, - Button::Z, - Button::LeftTrigger, - Button::LeftTrigger2, - Button::RightTrigger, - Button::RightTrigger2, - Button::Select, - Button::Start, - Button::Mode, - Button::LeftThumb, - Button::RightThumb, - Button::DPadUp, - Button::DPadDown, - Button::DPadLeft, - Button::DPadRight, -]; - -const ALL_GILRS_AXES: [gilrs::Axis; 8] = [ - gilrs::Axis::LeftStickX, - gilrs::Axis::LeftStickY, - gilrs::Axis::LeftZ, - gilrs::Axis::RightStickX, - gilrs::Axis::RightStickY, - gilrs::Axis::RightZ, - gilrs::Axis::DPadX, - gilrs::Axis::DPadY, -]; - -fn connect_gamepad( - gilrs_gamepad: gilrs::Gamepad, - gamepad: Gamepad, - events: &mut Events, - inputs: &mut Input, - axes: &mut Axis, - button_axes: &mut Axis, -) { - for gilrs_button in ALL_GILRS_BUTTONS.iter() { - if let Some(button_type) = convert_button(*gilrs_button) { - if let Some(button_data) = gilrs_gamepad.button_data(*gilrs_button) { - let gamepad_button = GamepadButton(gamepad, button_type); - inputs.reset(gamepad_button); - if button_data.is_pressed() { - inputs.press(gamepad_button); - } - button_axes.set(gamepad_button, button_data.value()); - } - } - } - for gilrs_axis in ALL_GILRS_AXES.iter() { - if let Some(axis_type) = convert_axis(*gilrs_axis) { - let gamepad_axis = GamepadAxis(gamepad, axis_type); - axes.set(gamepad_axis, gilrs_gamepad.value(*gilrs_axis)); - } - } - events.send(GamepadEvent(gamepad, GamepadEventType::Connected)); -} - -fn disconnect_gamepad( - gamepad: Gamepad, - events: &mut Events, - inputs: &mut Input, - axes: &mut Axis, - button_axes: &mut Axis, -) { - for gilrs_button in ALL_GILRS_BUTTONS.iter() { - if let Some(button_type) = convert_button(*gilrs_button) { - let gamepad_button = GamepadButton(gamepad, button_type); - inputs.reset(gamepad_button); - button_axes.remove(&gamepad_button); - } - } - for gilrs_axis in ALL_GILRS_AXES.iter() { - if let Some(axis_type) = convert_axis(*gilrs_axis) { - let gamepad_axis = GamepadAxis(gamepad, axis_type); - axes.remove(&gamepad_axis); - } - } - events.send(GamepadEvent(gamepad, GamepadEventType::Disconnected)); -} diff --git a/crates/bevy_gilrs/src/lib.rs b/crates/bevy_gilrs/src/lib.rs index 8edce92f7956f..475b156908a58 100644 --- a/crates/bevy_gilrs/src/lib.rs +++ b/crates/bevy_gilrs/src/lib.rs @@ -3,21 +3,26 @@ mod gilrs_system; use bevy_app::prelude::*; use bevy_ecs::prelude::*; -use gilrs_system::{gilrs_startup_system, gilrs_update_system}; +use gilrs::GilrsBuilder; +use gilrs_system::{gilrs_event_startup_system, girls_event_system}; #[derive(Default)] pub struct GilrsPlugin; impl Plugin for GilrsPlugin { fn build(&self, app: &mut AppBuilder) { - match gilrs::Gilrs::new() { + match GilrsBuilder::new() + .with_default_filters(false) + .set_update_state(false) + .build() + { Ok(gilrs) => { app.add_thread_local_resource(gilrs) - .add_startup_system(gilrs_startup_system.thread_local_system()) - .add_system_to_stage( - stage::EVENT_UPDATE, - gilrs_update_system.thread_local_system(), - ); + .add_startup_system_to_stage( + bevy_app::startup_stage::STARTUP, + gilrs_event_startup_system.thread_local_system(), + ) + .add_system_to_stage(stage::FIRST, girls_event_system.thread_local_system()); } Err(err) => log::error!("Failed to start Gilrs. {}", err), } diff --git a/crates/bevy_input/src/gamepad.rs b/crates/bevy_input/src/gamepad.rs index 48aa5e22831f9..b00e5cad21d0a 100644 --- a/crates/bevy_input/src/gamepad.rs +++ b/crates/bevy_input/src/gamepad.rs @@ -1,15 +1,22 @@ +use crate::{Axis, Input}; +use bevy_app::{EventReader, Events}; +use bevy_ecs::{Local, Res, ResMut}; +use bevy_utils::HashMap; + #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] pub struct Gamepad(pub usize); -#[derive(Debug, Copy, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq)] #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] pub enum GamepadEventType { Connected, Disconnected, + ButtonChanged(GamepadButtonType, f32), + AxisChanged(GamepadAxisType, f32), } -#[derive(Debug, Copy, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq)] #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] pub struct GamepadEvent(pub Gamepad, pub GamepadEventType); @@ -57,3 +64,230 @@ pub enum GamepadAxisType { #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] pub struct GamepadAxis(pub Gamepad, pub GamepadAxisType); + +#[derive(Default, Debug)] +pub struct GamepadProperty { + pub default_button_property: ButtonProperty, + pub default_axis_property: AxisProperty, + pub default_button_axis_property: ButtonAxisProperty, + pub button_properties: HashMap, + pub axis_properties: HashMap, + pub button_axis_properties: HashMap, +} + +impl GamepadProperty { + pub fn get_button_properties(&self, button: GamepadButton) -> &ButtonProperty { + self.button_properties + .get(&button) + .unwrap_or(&self.default_button_property) + } + + pub fn get_axis_properties(&self, axis: GamepadAxis) -> &AxisProperty { + self.axis_properties + .get(&axis) + .unwrap_or(&self.default_axis_property) + } + + pub fn get_button_axis_properties(&self, button: GamepadButton) -> &ButtonAxisProperty { + self.button_axis_properties + .get(&button) + .unwrap_or(&self.default_button_axis_property) + } +} + +#[derive(Debug, Clone)] +pub struct ButtonProperty { + pub press: f32, + pub release: f32, +} + +impl Default for ButtonProperty { + fn default() -> Self { + ButtonProperty { + press: 0.75, + release: 0.65, + } + } +} + +impl ButtonProperty { + fn is_pressed(&self, value: f32) -> bool { + value >= self.press + } + + fn is_released(&self, value: f32) -> bool { + value <= self.release + } +} + +#[derive(Debug, Clone)] +pub struct AxisProperty { + pub positive_high: f32, + pub positive_low: f32, + pub negative_high: f32, + pub negative_low: f32, + pub threshold: f32, +} + +impl Default for AxisProperty { + fn default() -> Self { + AxisProperty { + positive_high: 0.95, + positive_low: 0.05, + negative_high: -0.95, + negative_low: -0.05, + threshold: 0.01, + } + } +} + +impl AxisProperty { + fn filter(&self, new_value: f32, old_value: Option) -> f32 { + if let Some(old_value) = old_value { + if (new_value - old_value).abs() <= self.threshold { + return old_value; + } + } + if new_value <= self.positive_low && new_value >= self.negative_low { + return 0.0; + } + if new_value >= self.positive_high { + return 1.0; + } + if new_value <= self.negative_high { + return -1.0; + } + new_value + } +} + +#[derive(Debug, Clone)] +pub struct ButtonAxisProperty { + pub high: f32, + pub low: f32, + pub threshold: f32, +} + +impl Default for ButtonAxisProperty { + fn default() -> Self { + ButtonAxisProperty { + high: 0.95, + low: 0.05, + threshold: 0.01, + } + } +} + +impl ButtonAxisProperty { + fn filter(&self, new_value: f32, old_value: Option) -> f32 { + if let Some(old_value) = old_value { + if (new_value - old_value).abs() <= self.threshold { + return old_value; + } + } + if new_value <= self.low { + return 0.0; + } + if new_value >= self.high { + return 1.0; + } + new_value + } +} + +#[derive(Default)] +pub struct GamepadEventState { + gamepad_event_reader: EventReader, +} + +pub fn gamepad_event_system( + mut state: Local, + mut button: ResMut>, + mut axis: ResMut>, + mut button_axis: ResMut>, + event: Res>, + properties: Res, +) { + button.update(); + for event in state.gamepad_event_reader.iter(&event) { + let (gamepad, event) = (&event.0, &event.1); + match event { + GamepadEventType::Connected => { + for button_type in ALL_BUTTON_TYPES.iter() { + let gamepad_button = GamepadButton(*gamepad, *button_type); + button.reset(gamepad_button); + button_axis.set(gamepad_button, 0.0); + } + for axis_type in ALL_AXIS_TYPES.iter() { + axis.set(GamepadAxis(*gamepad, *axis_type), 0.0); + } + } + GamepadEventType::Disconnected => { + for button_type in ALL_BUTTON_TYPES.iter() { + let gamepad_button = GamepadButton(*gamepad, *button_type); + button.reset(gamepad_button); + button_axis.remove(&gamepad_button); + } + for axis_type in ALL_AXIS_TYPES.iter() { + axis.remove(&GamepadAxis(*gamepad, *axis_type)); + } + } + GamepadEventType::AxisChanged(axis_type, value) => { + let gamepad_axis = GamepadAxis(*gamepad, *axis_type); + let value = properties + .get_axis_properties(gamepad_axis) + .filter(*value, axis.get(&gamepad_axis)); + axis.set(gamepad_axis, value); + } + GamepadEventType::ButtonChanged(button_type, value) => { + let gamepad_button = GamepadButton(*gamepad, *button_type); + let filtered_value = properties + .get_button_axis_properties(gamepad_button) + .filter(*value, button_axis.get(&gamepad_button)); + button_axis.set(gamepad_button, filtered_value); + + let button_property = properties.get_button_properties(gamepad_button); + if button.pressed(gamepad_button) { + if button_property.is_released(*value) { + button.release(gamepad_button); + } + } else if button_property.is_pressed(*value) { + button.press(gamepad_button); + } + } + } + } +} + +const ALL_BUTTON_TYPES: [GamepadButtonType; 19] = [ + GamepadButtonType::South, + GamepadButtonType::East, + GamepadButtonType::North, + GamepadButtonType::West, + GamepadButtonType::C, + GamepadButtonType::Z, + GamepadButtonType::LeftTrigger, + GamepadButtonType::LeftTrigger2, + GamepadButtonType::RightTrigger, + GamepadButtonType::RightTrigger2, + GamepadButtonType::Select, + GamepadButtonType::Start, + GamepadButtonType::Mode, + GamepadButtonType::LeftThumb, + GamepadButtonType::RightThumb, + GamepadButtonType::DPadUp, + GamepadButtonType::DPadDown, + GamepadButtonType::DPadLeft, + GamepadButtonType::DPadRight, +]; + +const ALL_AXIS_TYPES: [GamepadAxisType; 8] = [ + GamepadAxisType::LeftStickX, + GamepadAxisType::LeftStickY, + GamepadAxisType::LeftZ, + GamepadAxisType::RightStickX, + GamepadAxisType::RightStickY, + GamepadAxisType::RightZ, + GamepadAxisType::DPadX, + GamepadAxisType::DPadY, +]; diff --git a/crates/bevy_input/src/lib.rs b/crates/bevy_input/src/lib.rs index 7520779651a21..cd215ac8fc737 100644 --- a/crates/bevy_input/src/lib.rs +++ b/crates/bevy_input/src/lib.rs @@ -27,7 +27,7 @@ use mouse::{mouse_button_input_system, MouseButton, MouseButtonInput, MouseMotio use touch::{touch_screen_input_system, TouchInput, Touches}; use bevy_ecs::IntoQuerySystem; -use gamepad::{GamepadAxis, GamepadButton, GamepadEvent}; +use gamepad::{gamepad_event_system, GamepadAxis, GamepadButton, GamepadEvent, GamepadProperty}; /// Adds keyboard and mouse input to an App #[derive(Default)] @@ -50,9 +50,16 @@ impl Plugin for InputPlugin { mouse_button_input_system.system(), ) .add_event::() + .init_resource::() .init_resource::>() .init_resource::>() .init_resource::>() + .add_startup_system_to_stage( + bevy_app::startup_stage::POST_STARTUP, + gamepad_event_system.system(), + ) + .add_system_to_stage(bevy_app::stage::EVENT_UPDATE, gamepad_event_system.system()) + .init_resource::>() .add_event::() .init_resource::() .add_system_to_stage( diff --git a/examples/input/gamepad_input.rs b/examples/input/gamepad_input.rs index 5ddd40b2f86a8..639a358410627 100644 --- a/examples/input/gamepad_input.rs +++ b/examples/input/gamepad_input.rs @@ -1,15 +1,16 @@ use bevy::prelude::*; use bevy_input::gamepad::{Gamepad, GamepadButton, GamepadEvent, GamepadEventType}; -use std::collections::HashSet; +use bevy_utils::{HashMap, HashSet}; fn main() { App::build() .add_default_plugins() + .init_resource::() + .init_resource::() .add_startup_system(connection_system.system()) .add_system(connection_system.system()) .add_system(button_system.system()) .add_system(axis_system.system()) - .init_resource::() .run(); } @@ -19,17 +20,24 @@ struct GamepadLobby { gamepad_event_reader: EventReader, } +#[derive(Default)] +struct GamepadData { + axis: HashMap, + button: HashMap, +} + fn connection_system(mut lobby: ResMut, gamepad_event: Res>) { for event in lobby.gamepad_event_reader.iter(&gamepad_event) { match &event { GamepadEvent(gamepad, GamepadEventType::Connected) => { lobby.gamepads.insert(*gamepad); - println!("Connected {:?}", gamepad); + println!("{:?} Connected", gamepad); } GamepadEvent(gamepad, GamepadEventType::Disconnected) => { lobby.gamepads.remove(gamepad); - println!("Disconnected {:?}", gamepad); + println!("{:?} Disconnected", gamepad); } + _ => (), } } } @@ -38,6 +46,7 @@ fn button_system( lobby: Res, inputs: Res>, button_axes: Res>, + mut data: ResMut, ) { let button_types = [ GamepadButtonType::South, @@ -62,25 +71,30 @@ fn button_system( ]; for gamepad in lobby.gamepads.iter() { for button_type in button_types.iter() { - if inputs.just_pressed(GamepadButton(*gamepad, *button_type)) { - println!("Pressed {:?}", GamepadButton(*gamepad, *button_type)); + let gamepad_button = GamepadButton(*gamepad, *button_type); + if inputs.just_pressed(gamepad_button) { + println!("{:?} Pressed", gamepad_button); } else if inputs.just_released(GamepadButton(*gamepad, *button_type)) { - println!("Released {:?}", GamepadButton(*gamepad, *button_type)); + println!("{:?} Released", gamepad_button); } - if let Some(value) = button_axes.get(&GamepadButton(*gamepad, *button_type)) { - if value_check(value) { - println!( - "Button as Axis {:?} is {}", - GamepadButton(*gamepad, *button_type), - value - ); + if let Some(value) = button_axes.get(&gamepad_button) { + if !approx_eq( + data.button.get(&gamepad_button).copied().unwrap_or(0.0), + value, + ) { + data.button.insert(gamepad_button, value); + println!("{:?} is {}", gamepad_button, value); } } } } } -fn axis_system(lobby: Res, axes: Res>) { +fn axis_system( + lobby: Res, + axes: Res>, + mut data: ResMut, +) { let axis_types = [ GamepadAxisType::LeftStickX, GamepadAxisType::LeftStickY, @@ -93,16 +107,17 @@ fn axis_system(lobby: Res, axes: Res>) { ]; for gamepad in lobby.gamepads.iter() { for axis_type in axis_types.iter() { - if let Some(value) = axes.get(&GamepadAxis(*gamepad, *axis_type)) { - if value_check(value) { - println!("Axis {:?} is {}", GamepadAxis(*gamepad, *axis_type), value); + let gamepad_axis = GamepadAxis(*gamepad, *axis_type); + if let Some(value) = axes.get(&gamepad_axis) { + if !approx_eq(data.axis.get(&gamepad_axis).copied().unwrap_or(0.0), value) { + data.axis.insert(gamepad_axis, value); + println!("{:?} is {}", gamepad_axis, value); } } } } } -fn value_check(value: f32) -> bool { - let value = value.abs(); - value > 0.1f32 && value < 0.9f32 +fn approx_eq(a: f32, b: f32) -> bool { + (a - b).abs() < f32::EPSILON } diff --git a/examples/input/gamepad_input_event.rs b/examples/input/gamepad_input_event.rs new file mode 100644 index 0000000000000..4052bd62fe55b --- /dev/null +++ b/examples/input/gamepad_input_event.rs @@ -0,0 +1,34 @@ +use bevy::prelude::*; +use bevy_input::gamepad::{GamepadEvent, GamepadEventType}; + +fn main() { + App::build() + .add_default_plugins() + .add_startup_system(gamepad_raw_events.system()) + .add_system(gamepad_raw_events.system()) + .run(); +} + +#[derive(Default)] +struct State { + gamepad_event_reader: EventReader, +} + +fn gamepad_raw_events(mut state: Local, gamepad_event: Res>) { + for event in state.gamepad_event_reader.iter(&gamepad_event) { + match &event { + GamepadEvent(gamepad, GamepadEventType::Connected) => { + println!("{:?} Connected", gamepad); + } + GamepadEvent(gamepad, GamepadEventType::Disconnected) => { + println!("{:?} Disconnected", gamepad); + } + GamepadEvent(gamepad, GamepadEventType::ButtonChanged(button_type, value)) => { + println!("{:?} of {:?} is changed to {}", button_type, gamepad, value); + } + GamepadEvent(gamepad, GamepadEventType::AxisChanged(axis_type, value)) => { + println!("{:?} of {:?} is changed to {}", axis_type, gamepad, value); + } + } + } +} From 5363b0993122da3e9cfcd25df855edbcf1d0d420 Mon Sep 17 00:00:00 2001 From: Utkarsh Date: Mon, 19 Oct 2020 02:08:14 +0530 Subject: [PATCH 2/3] Changed parameter of get and remove of Axis from &T to T --- crates/bevy_input/src/axis.rs | 8 ++++---- crates/bevy_input/src/gamepad.rs | 8 ++++---- examples/input/gamepad_input.rs | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/crates/bevy_input/src/axis.rs b/crates/bevy_input/src/axis.rs index df1ff289d62c1..e1863969e8926 100644 --- a/crates/bevy_input/src/axis.rs +++ b/crates/bevy_input/src/axis.rs @@ -24,11 +24,11 @@ where self.axis_data.insert(axis, value) } - pub fn get(&self, axis: &T) -> Option { - self.axis_data.get(axis).copied() + pub fn get(&self, axis: T) -> Option { + self.axis_data.get(&axis).copied() } - pub fn remove(&mut self, axis: &T) -> Option { - self.axis_data.remove(axis) + pub fn remove(&mut self, axis: T) -> Option { + self.axis_data.remove(&axis) } } diff --git a/crates/bevy_input/src/gamepad.rs b/crates/bevy_input/src/gamepad.rs index b00e5cad21d0a..8bfa00a973509 100644 --- a/crates/bevy_input/src/gamepad.rs +++ b/crates/bevy_input/src/gamepad.rs @@ -226,24 +226,24 @@ pub fn gamepad_event_system( for button_type in ALL_BUTTON_TYPES.iter() { let gamepad_button = GamepadButton(*gamepad, *button_type); button.reset(gamepad_button); - button_axis.remove(&gamepad_button); + button_axis.remove(gamepad_button); } for axis_type in ALL_AXIS_TYPES.iter() { - axis.remove(&GamepadAxis(*gamepad, *axis_type)); + axis.remove(GamepadAxis(*gamepad, *axis_type)); } } GamepadEventType::AxisChanged(axis_type, value) => { let gamepad_axis = GamepadAxis(*gamepad, *axis_type); let value = properties .get_axis_properties(gamepad_axis) - .filter(*value, axis.get(&gamepad_axis)); + .filter(*value, axis.get(gamepad_axis)); axis.set(gamepad_axis, value); } GamepadEventType::ButtonChanged(button_type, value) => { let gamepad_button = GamepadButton(*gamepad, *button_type); let filtered_value = properties .get_button_axis_properties(gamepad_button) - .filter(*value, button_axis.get(&gamepad_button)); + .filter(*value, button_axis.get(gamepad_button)); button_axis.set(gamepad_button, filtered_value); let button_property = properties.get_button_properties(gamepad_button); diff --git a/examples/input/gamepad_input.rs b/examples/input/gamepad_input.rs index 639a358410627..c1fd62c378503 100644 --- a/examples/input/gamepad_input.rs +++ b/examples/input/gamepad_input.rs @@ -77,7 +77,7 @@ fn button_system( } else if inputs.just_released(GamepadButton(*gamepad, *button_type)) { println!("{:?} Released", gamepad_button); } - if let Some(value) = button_axes.get(&gamepad_button) { + if let Some(value) = button_axes.get(gamepad_button) { if !approx_eq( data.button.get(&gamepad_button).copied().unwrap_or(0.0), value, @@ -108,7 +108,7 @@ fn axis_system( for gamepad in lobby.gamepads.iter() { for axis_type in axis_types.iter() { let gamepad_axis = GamepadAxis(*gamepad, *axis_type); - if let Some(value) = axes.get(&gamepad_axis) { + if let Some(value) = axes.get(gamepad_axis) { if !approx_eq(data.axis.get(&gamepad_axis).copied().unwrap_or(0.0), value) { data.axis.insert(gamepad_axis, value); println!("{:?} is {}", gamepad_axis, value); From 853af821e04920ad36fc787a2735dc9c36ef2992 Mon Sep 17 00:00:00 2001 From: Utkarsh Date: Wed, 21 Oct 2020 07:06:09 +0530 Subject: [PATCH 3/3] Simplify gamepad_input example and refactor bevy_input::gamepad --- crates/bevy_gilrs/src/lib.rs | 5 +- crates/bevy_input/src/gamepad.rs | 88 ++++++++++++------------- crates/bevy_input/src/lib.rs | 5 +- examples/input/gamepad_input.rs | 110 ++++++++----------------------- 4 files changed, 76 insertions(+), 132 deletions(-) diff --git a/crates/bevy_gilrs/src/lib.rs b/crates/bevy_gilrs/src/lib.rs index 475b156908a58..99f803f50fa3f 100644 --- a/crates/bevy_gilrs/src/lib.rs +++ b/crates/bevy_gilrs/src/lib.rs @@ -18,10 +18,7 @@ impl Plugin for GilrsPlugin { { Ok(gilrs) => { app.add_thread_local_resource(gilrs) - .add_startup_system_to_stage( - bevy_app::startup_stage::STARTUP, - gilrs_event_startup_system.thread_local_system(), - ) + .add_startup_system(gilrs_event_startup_system.thread_local_system()) .add_system_to_stage(stage::FIRST, girls_event_system.thread_local_system()); } Err(err) => log::error!("Failed to start Gilrs. {}", err), diff --git a/crates/bevy_input/src/gamepad.rs b/crates/bevy_input/src/gamepad.rs index 8bfa00a973509..bd416935987c5 100644 --- a/crates/bevy_input/src/gamepad.rs +++ b/crates/bevy_input/src/gamepad.rs @@ -66,51 +66,51 @@ pub enum GamepadAxisType { pub struct GamepadAxis(pub Gamepad, pub GamepadAxisType); #[derive(Default, Debug)] -pub struct GamepadProperty { - pub default_button_property: ButtonProperty, - pub default_axis_property: AxisProperty, - pub default_button_axis_property: ButtonAxisProperty, - pub button_properties: HashMap, - pub axis_properties: HashMap, - pub button_axis_properties: HashMap, +pub struct GamepadSetting { + pub default_button_setting: ButtonSetting, + pub default_axis_setting: AxisSetting, + pub default_button_axis_setting: ButtonAxisSetting, + pub button_settings: HashMap, + pub axis_settings: HashMap, + pub button_axis_settings: HashMap, } -impl GamepadProperty { - pub fn get_button_properties(&self, button: GamepadButton) -> &ButtonProperty { - self.button_properties +impl GamepadSetting { + pub fn get_button_setting(&self, button: GamepadButton) -> &ButtonSetting { + self.button_settings .get(&button) - .unwrap_or(&self.default_button_property) + .unwrap_or(&self.default_button_setting) } - pub fn get_axis_properties(&self, axis: GamepadAxis) -> &AxisProperty { - self.axis_properties + pub fn get_axis_setting(&self, axis: GamepadAxis) -> &AxisSetting { + self.axis_settings .get(&axis) - .unwrap_or(&self.default_axis_property) + .unwrap_or(&self.default_axis_setting) } - pub fn get_button_axis_properties(&self, button: GamepadButton) -> &ButtonAxisProperty { - self.button_axis_properties + pub fn get_button_axis_setting(&self, button: GamepadButton) -> &ButtonAxisSetting { + self.button_axis_settings .get(&button) - .unwrap_or(&self.default_button_axis_property) + .unwrap_or(&self.default_button_axis_setting) } } #[derive(Debug, Clone)] -pub struct ButtonProperty { +pub struct ButtonSetting { pub press: f32, pub release: f32, } -impl Default for ButtonProperty { +impl Default for ButtonSetting { fn default() -> Self { - ButtonProperty { + ButtonSetting { press: 0.75, release: 0.65, } } } -impl ButtonProperty { +impl ButtonSetting { fn is_pressed(&self, value: f32) -> bool { value >= self.press } @@ -121,7 +121,7 @@ impl ButtonProperty { } #[derive(Debug, Clone)] -pub struct AxisProperty { +pub struct AxisSetting { pub positive_high: f32, pub positive_low: f32, pub negative_high: f32, @@ -129,9 +129,9 @@ pub struct AxisProperty { pub threshold: f32, } -impl Default for AxisProperty { +impl Default for AxisSetting { fn default() -> Self { - AxisProperty { + AxisSetting { positive_high: 0.95, positive_low: 0.05, negative_high: -0.95, @@ -141,7 +141,7 @@ impl Default for AxisProperty { } } -impl AxisProperty { +impl AxisSetting { fn filter(&self, new_value: f32, old_value: Option) -> f32 { if let Some(old_value) = old_value { if (new_value - old_value).abs() <= self.threshold { @@ -162,15 +162,15 @@ impl AxisProperty { } #[derive(Debug, Clone)] -pub struct ButtonAxisProperty { +pub struct ButtonAxisSetting { pub high: f32, pub low: f32, pub threshold: f32, } -impl Default for ButtonAxisProperty { +impl Default for ButtonAxisSetting { fn default() -> Self { - ButtonAxisProperty { + ButtonAxisSetting { high: 0.95, low: 0.05, threshold: 0.01, @@ -178,7 +178,7 @@ impl Default for ButtonAxisProperty { } } -impl ButtonAxisProperty { +impl ButtonAxisSetting { fn filter(&self, new_value: f32, old_value: Option) -> f32 { if let Some(old_value) = old_value { if (new_value - old_value).abs() <= self.threshold { @@ -202,20 +202,20 @@ pub struct GamepadEventState { pub fn gamepad_event_system( mut state: Local, - mut button: ResMut>, + mut button_input: ResMut>, mut axis: ResMut>, mut button_axis: ResMut>, - event: Res>, - properties: Res, + events: Res>, + settings: Res, ) { - button.update(); - for event in state.gamepad_event_reader.iter(&event) { + button_input.update(); + for event in state.gamepad_event_reader.iter(&events) { let (gamepad, event) = (&event.0, &event.1); match event { GamepadEventType::Connected => { for button_type in ALL_BUTTON_TYPES.iter() { let gamepad_button = GamepadButton(*gamepad, *button_type); - button.reset(gamepad_button); + button_input.reset(gamepad_button); button_axis.set(gamepad_button, 0.0); } for axis_type in ALL_AXIS_TYPES.iter() { @@ -225,7 +225,7 @@ pub fn gamepad_event_system( GamepadEventType::Disconnected => { for button_type in ALL_BUTTON_TYPES.iter() { let gamepad_button = GamepadButton(*gamepad, *button_type); - button.reset(gamepad_button); + button_input.reset(gamepad_button); button_axis.remove(gamepad_button); } for axis_type in ALL_AXIS_TYPES.iter() { @@ -234,25 +234,25 @@ pub fn gamepad_event_system( } GamepadEventType::AxisChanged(axis_type, value) => { let gamepad_axis = GamepadAxis(*gamepad, *axis_type); - let value = properties - .get_axis_properties(gamepad_axis) + let value = settings + .get_axis_setting(gamepad_axis) .filter(*value, axis.get(gamepad_axis)); axis.set(gamepad_axis, value); } GamepadEventType::ButtonChanged(button_type, value) => { let gamepad_button = GamepadButton(*gamepad, *button_type); - let filtered_value = properties - .get_button_axis_properties(gamepad_button) + let filtered_value = settings + .get_button_axis_setting(gamepad_button) .filter(*value, button_axis.get(gamepad_button)); button_axis.set(gamepad_button, filtered_value); - let button_property = properties.get_button_properties(gamepad_button); - if button.pressed(gamepad_button) { + let button_property = settings.get_button_setting(gamepad_button); + if button_input.pressed(gamepad_button) { if button_property.is_released(*value) { - button.release(gamepad_button); + button_input.release(gamepad_button); } } else if button_property.is_pressed(*value) { - button.press(gamepad_button); + button_input.press(gamepad_button); } } } diff --git a/crates/bevy_input/src/lib.rs b/crates/bevy_input/src/lib.rs index cd215ac8fc737..6c528c2dda28c 100644 --- a/crates/bevy_input/src/lib.rs +++ b/crates/bevy_input/src/lib.rs @@ -27,7 +27,7 @@ use mouse::{mouse_button_input_system, MouseButton, MouseButtonInput, MouseMotio use touch::{touch_screen_input_system, TouchInput, Touches}; use bevy_ecs::IntoQuerySystem; -use gamepad::{gamepad_event_system, GamepadAxis, GamepadButton, GamepadEvent, GamepadProperty}; +use gamepad::{gamepad_event_system, GamepadAxis, GamepadButton, GamepadEvent, GamepadSetting}; /// Adds keyboard and mouse input to an App #[derive(Default)] @@ -50,7 +50,7 @@ impl Plugin for InputPlugin { mouse_button_input_system.system(), ) .add_event::() - .init_resource::() + .init_resource::() .init_resource::>() .init_resource::>() .init_resource::>() @@ -59,7 +59,6 @@ impl Plugin for InputPlugin { gamepad_event_system.system(), ) .add_system_to_stage(bevy_app::stage::EVENT_UPDATE, gamepad_event_system.system()) - .init_resource::>() .add_event::() .init_resource::() .add_system_to_stage( diff --git a/examples/input/gamepad_input.rs b/examples/input/gamepad_input.rs index c1fd62c378503..768f90b358211 100644 --- a/examples/input/gamepad_input.rs +++ b/examples/input/gamepad_input.rs @@ -1,16 +1,14 @@ use bevy::prelude::*; use bevy_input::gamepad::{Gamepad, GamepadButton, GamepadEvent, GamepadEventType}; -use bevy_utils::{HashMap, HashSet}; +use bevy_utils::HashSet; fn main() { App::build() .add_default_plugins() .init_resource::() - .init_resource::() .add_startup_system(connection_system.system()) .add_system(connection_system.system()) - .add_system(button_system.system()) - .add_system(axis_system.system()) + .add_system(gamepad_system.system()) .run(); } @@ -20,12 +18,6 @@ struct GamepadLobby { gamepad_event_reader: EventReader, } -#[derive(Default)] -struct GamepadData { - axis: HashMap, - button: HashMap, -} - fn connection_system(mut lobby: ResMut, gamepad_event: Res>) { for event in lobby.gamepad_event_reader.iter(&gamepad_event) { match &event { @@ -42,82 +34,38 @@ fn connection_system(mut lobby: ResMut, gamepad_event: Res, - inputs: Res>, + button_inputs: Res>, button_axes: Res>, - mut data: ResMut, -) { - let button_types = [ - GamepadButtonType::South, - GamepadButtonType::East, - GamepadButtonType::North, - GamepadButtonType::West, - GamepadButtonType::C, - GamepadButtonType::Z, - GamepadButtonType::LeftTrigger, - GamepadButtonType::LeftTrigger2, - GamepadButtonType::RightTrigger, - GamepadButtonType::RightTrigger2, - GamepadButtonType::Select, - GamepadButtonType::Start, - GamepadButtonType::Mode, - GamepadButtonType::LeftThumb, - GamepadButtonType::RightThumb, - GamepadButtonType::DPadUp, - GamepadButtonType::DPadDown, - GamepadButtonType::DPadLeft, - GamepadButtonType::DPadRight, - ]; - for gamepad in lobby.gamepads.iter() { - for button_type in button_types.iter() { - let gamepad_button = GamepadButton(*gamepad, *button_type); - if inputs.just_pressed(gamepad_button) { - println!("{:?} Pressed", gamepad_button); - } else if inputs.just_released(GamepadButton(*gamepad, *button_type)) { - println!("{:?} Released", gamepad_button); - } - if let Some(value) = button_axes.get(gamepad_button) { - if !approx_eq( - data.button.get(&gamepad_button).copied().unwrap_or(0.0), - value, - ) { - data.button.insert(gamepad_button, value); - println!("{:?} is {}", gamepad_button, value); - } - } - } - } -} - -fn axis_system( - lobby: Res, axes: Res>, - mut data: ResMut, ) { - let axis_types = [ - GamepadAxisType::LeftStickX, - GamepadAxisType::LeftStickY, - GamepadAxisType::LeftZ, - GamepadAxisType::RightStickX, - GamepadAxisType::RightStickY, - GamepadAxisType::RightZ, - GamepadAxisType::DPadX, - GamepadAxisType::DPadY, - ]; for gamepad in lobby.gamepads.iter() { - for axis_type in axis_types.iter() { - let gamepad_axis = GamepadAxis(*gamepad, *axis_type); - if let Some(value) = axes.get(gamepad_axis) { - if !approx_eq(data.axis.get(&gamepad_axis).copied().unwrap_or(0.0), value) { - data.axis.insert(gamepad_axis, value); - println!("{:?} is {}", gamepad_axis, value); - } - } + let south_button = GamepadButton(*gamepad, GamepadButtonType::South); + if button_inputs.just_pressed(south_button) { + println!( + "{:?} of {:?} is just pressed", + GamepadButtonType::South, + gamepad + ); + } else if button_inputs.just_released(south_button) { + println!( + "{:?} of {:?} is just released", + GamepadButtonType::South, + gamepad + ); } - } -} -fn approx_eq(a: f32, b: f32) -> bool { - (a - b).abs() < f32::EPSILON + println!( + "For {:?}: {:?} is {:.4}, {:?} is {:.4}", + gamepad, + GamepadButtonType::RightTrigger2, + button_axes + .get(GamepadButton(*gamepad, GamepadButtonType::RightTrigger2)) + .unwrap_or(0.0), + GamepadAxisType::LeftStickX, + axes.get(GamepadAxis(*gamepad, GamepadAxisType::LeftStickX)) + .unwrap_or(0.0) + ) + } }