mirror of
https://github.com/bevyengine/bevy
synced 2024-11-22 04:33:37 +00:00
Added gamepad support using Gilrs (#280)
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
This commit is contained in:
parent
d4c8436457
commit
19d4694d24
12 changed files with 479 additions and 2 deletions
7
.github/workflows/ci.yml
vendored
7
.github/workflows/ci.yml
vendored
|
@ -38,6 +38,10 @@ jobs:
|
||||||
run: sudo apt-get update; sudo apt-get install --no-install-recommends libasound2-dev
|
run: sudo apt-get update; sudo apt-get install --no-install-recommends libasound2-dev
|
||||||
if: ${{ runner.os == 'Linux' }}
|
if: ${{ runner.os == 'Linux' }}
|
||||||
|
|
||||||
|
- name: Install udev
|
||||||
|
run: sudo apt-get update; sudo apt-get install --no-install-recommends libudev-dev
|
||||||
|
if: ${{ runner.os == 'Linux' }}
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
run: cargo check
|
run: cargo check
|
||||||
env:
|
env:
|
||||||
|
@ -65,6 +69,9 @@ jobs:
|
||||||
- name: Install alsa
|
- name: Install alsa
|
||||||
run: sudo apt-get install --no-install-recommends libasound2-dev
|
run: sudo apt-get install --no-install-recommends libasound2-dev
|
||||||
|
|
||||||
|
- name: Install udev
|
||||||
|
run: sudo apt-get install --no-install-recommends libudev-dev
|
||||||
|
|
||||||
- name: Check the format
|
- name: Check the format
|
||||||
run: cargo +nightly fmt --all -- --check
|
run: cargo +nightly fmt --all -- --check
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@ exclude = ["assets/**/*", "tools/**/*", ".github/**/*", "crates/**/*"]
|
||||||
[features]
|
[features]
|
||||||
default = [
|
default = [
|
||||||
"bevy_audio",
|
"bevy_audio",
|
||||||
|
"bevy_gilrs",
|
||||||
"bevy_gltf",
|
"bevy_gltf",
|
||||||
"bevy_wgpu",
|
"bevy_wgpu",
|
||||||
"bevy_winit",
|
"bevy_winit",
|
||||||
|
@ -83,6 +84,7 @@ bevy_text = { path = "crates/bevy_text", optional = true, version = "0.1" }
|
||||||
bevy_ui = { path = "crates/bevy_ui", optional = true, version = "0.1" }
|
bevy_ui = { path = "crates/bevy_ui", optional = true, version = "0.1" }
|
||||||
bevy_wgpu = { path = "crates/bevy_wgpu", optional = true, version = "0.1" }
|
bevy_wgpu = { path = "crates/bevy_wgpu", optional = true, version = "0.1" }
|
||||||
bevy_winit = { path = "crates/bevy_winit", optional = true, version = "0.1" }
|
bevy_winit = { path = "crates/bevy_winit", optional = true, version = "0.1" }
|
||||||
|
bevy_gilrs = { path = "crates/bevy_gilrs", optional = true, version = "0.1" }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
rand = "0.7.3"
|
rand = "0.7.3"
|
||||||
|
@ -217,6 +219,10 @@ path = "examples/input/keyboard_input.rs"
|
||||||
name = "keyboard_input_events"
|
name = "keyboard_input_events"
|
||||||
path = "examples/input/keyboard_input_events.rs"
|
path = "examples/input/keyboard_input_events.rs"
|
||||||
|
|
||||||
|
[[example]]
|
||||||
|
name = "gamepad_input"
|
||||||
|
path = "examples/input/gamepad_input.rs"
|
||||||
|
|
||||||
[[example]]
|
[[example]]
|
||||||
name = "scene"
|
name = "scene"
|
||||||
path = "examples/scene/scene.rs"
|
path = "examples/scene/scene.rs"
|
||||||
|
|
20
crates/bevy_gilrs/Cargo.toml
Normal file
20
crates/bevy_gilrs/Cargo.toml
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
[package]
|
||||||
|
name = "bevy_gilrs"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2018"
|
||||||
|
authors = ["Bevy Contributors <bevyengine@gmail.com>", "Carter Anderson <mcanders1@gmail.com>"]
|
||||||
|
description = "Gamepad system made using Gilrs for Bevy Engine"
|
||||||
|
homepage = "https://bevyengine.org"
|
||||||
|
repository = "https://github.com/bevyengine/bevy"
|
||||||
|
license = "MIT"
|
||||||
|
keywords = ["bevy"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
# bevy
|
||||||
|
bevy_app = { path = "../bevy_app", version = "0.1" }
|
||||||
|
bevy_ecs = { path = "../bevy_ecs", version = "0.1" }
|
||||||
|
bevy_input = { path = "../bevy_input", version = "0.1" }
|
||||||
|
|
||||||
|
# other
|
||||||
|
gilrs = "0.7.4"
|
||||||
|
log = { version = "0.4", features = ["release_max_level_info"] }
|
44
crates/bevy_gilrs/src/converter.rs
Normal file
44
crates/bevy_gilrs/src/converter.rs
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
use bevy_input::gamepad::{Gamepad, GamepadAxisType, GamepadButtonType};
|
||||||
|
|
||||||
|
pub fn convert_gamepad_id(gamepad_id: gilrs::GamepadId) -> Gamepad {
|
||||||
|
Gamepad(gamepad_id.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn convert_button(button: gilrs::Button) -> Option<GamepadButtonType> {
|
||||||
|
match button {
|
||||||
|
gilrs::Button::South => Some(GamepadButtonType::South),
|
||||||
|
gilrs::Button::East => Some(GamepadButtonType::East),
|
||||||
|
gilrs::Button::North => Some(GamepadButtonType::North),
|
||||||
|
gilrs::Button::West => Some(GamepadButtonType::West),
|
||||||
|
gilrs::Button::C => Some(GamepadButtonType::C),
|
||||||
|
gilrs::Button::Z => Some(GamepadButtonType::Z),
|
||||||
|
gilrs::Button::LeftTrigger => Some(GamepadButtonType::LeftTrigger),
|
||||||
|
gilrs::Button::LeftTrigger2 => Some(GamepadButtonType::LeftTrigger2),
|
||||||
|
gilrs::Button::RightTrigger => Some(GamepadButtonType::RightTrigger),
|
||||||
|
gilrs::Button::RightTrigger2 => Some(GamepadButtonType::RightTrigger2),
|
||||||
|
gilrs::Button::Select => Some(GamepadButtonType::Select),
|
||||||
|
gilrs::Button::Start => Some(GamepadButtonType::Start),
|
||||||
|
gilrs::Button::Mode => Some(GamepadButtonType::Mode),
|
||||||
|
gilrs::Button::LeftThumb => Some(GamepadButtonType::LeftThumb),
|
||||||
|
gilrs::Button::RightThumb => Some(GamepadButtonType::RightThumb),
|
||||||
|
gilrs::Button::DPadUp => Some(GamepadButtonType::DPadUp),
|
||||||
|
gilrs::Button::DPadDown => Some(GamepadButtonType::DPadDown),
|
||||||
|
gilrs::Button::DPadLeft => Some(GamepadButtonType::DPadLeft),
|
||||||
|
gilrs::Button::DPadRight => Some(GamepadButtonType::DPadRight),
|
||||||
|
gilrs::Button::Unknown => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn convert_axis(axis: gilrs::Axis) -> Option<GamepadAxisType> {
|
||||||
|
match axis {
|
||||||
|
gilrs::Axis::LeftStickX => Some(GamepadAxisType::LeftStickX),
|
||||||
|
gilrs::Axis::LeftStickY => Some(GamepadAxisType::LeftStickY),
|
||||||
|
gilrs::Axis::LeftZ => Some(GamepadAxisType::LeftZ),
|
||||||
|
gilrs::Axis::RightStickX => Some(GamepadAxisType::RightStickX),
|
||||||
|
gilrs::Axis::RightStickY => Some(GamepadAxisType::RightStickY),
|
||||||
|
gilrs::Axis::RightZ => Some(GamepadAxisType::RightZ),
|
||||||
|
gilrs::Axis::DPadX => Some(GamepadAxisType::DPadX),
|
||||||
|
gilrs::Axis::DPadY => Some(GamepadAxisType::DPadY),
|
||||||
|
gilrs::Axis::Unknown => None,
|
||||||
|
}
|
||||||
|
}
|
176
crates/bevy_gilrs/src/gilrs_system.rs
Normal file
176
crates/bevy_gilrs/src/gilrs_system.rs
Normal file
|
@ -0,0 +1,176 @@
|
||||||
|
use crate::converter::{convert_axis, convert_button, convert_gamepad_id};
|
||||||
|
use bevy_app::Events;
|
||||||
|
use bevy_ecs::{Res, ResMut};
|
||||||
|
use bevy_input::prelude::*;
|
||||||
|
use gilrs::{Button, EventType, Gilrs};
|
||||||
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
|
// TODO: remove this if/when bevy_ecs supports thread local resources
|
||||||
|
struct GilrsSendWrapper(Gilrs);
|
||||||
|
|
||||||
|
unsafe impl Send for GilrsSendWrapper {}
|
||||||
|
|
||||||
|
pub struct GilrsArcMutexWrapper(Arc<Mutex<GilrsSendWrapper>>);
|
||||||
|
|
||||||
|
impl GilrsArcMutexWrapper {
|
||||||
|
pub fn new(gilrs: Gilrs) -> GilrsArcMutexWrapper {
|
||||||
|
GilrsArcMutexWrapper(Arc::new(Mutex::new(GilrsSendWrapper(gilrs))))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn gilrs_startup_system(
|
||||||
|
gilrs: Res<GilrsArcMutexWrapper>,
|
||||||
|
mut gamepad_event: ResMut<Events<GamepadEvent>>,
|
||||||
|
mut inputs: ResMut<Input<GamepadButton>>,
|
||||||
|
mut axes: ResMut<Axis<GamepadAxis>>,
|
||||||
|
) {
|
||||||
|
gamepad_event.update();
|
||||||
|
inputs.update();
|
||||||
|
let gilrs = &gilrs.0.lock().unwrap().0;
|
||||||
|
for (gilrs_id, gilrs_gamepad) in gilrs.gamepads() {
|
||||||
|
connect_gamepad(
|
||||||
|
gilrs_gamepad,
|
||||||
|
convert_gamepad_id(gilrs_id),
|
||||||
|
&mut gamepad_event,
|
||||||
|
&mut inputs,
|
||||||
|
&mut axes,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn gilrs_update_system(
|
||||||
|
gilrs: Res<GilrsArcMutexWrapper>,
|
||||||
|
mut gamepad_event: ResMut<Events<GamepadEvent>>,
|
||||||
|
mut inputs: ResMut<Input<GamepadButton>>,
|
||||||
|
mut axes: ResMut<Axis<GamepadAxis>>,
|
||||||
|
) {
|
||||||
|
gamepad_event.update();
|
||||||
|
inputs.update();
|
||||||
|
let gilrs = &mut gilrs.0.lock().unwrap().0;
|
||||||
|
while let Some(gilrs_event) = gilrs.next_event() {
|
||||||
|
match gilrs_event.event {
|
||||||
|
EventType::Connected => {
|
||||||
|
connect_gamepad(
|
||||||
|
gilrs.gamepad(gilrs_event.id),
|
||||||
|
convert_gamepad_id(gilrs_event.id),
|
||||||
|
&mut gamepad_event,
|
||||||
|
&mut inputs,
|
||||||
|
&mut axes,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
EventType::Disconnected => {
|
||||||
|
disconnect_gamepad(
|
||||||
|
convert_gamepad_id(gilrs_event.id),
|
||||||
|
&mut gamepad_event,
|
||||||
|
&mut inputs,
|
||||||
|
&mut axes,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
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, _) => {
|
||||||
|
if let Some(button_type) = convert_button(gilrs_button) {
|
||||||
|
inputs.release(GamepadButton(
|
||||||
|
convert_gamepad_id(gilrs_event.id),
|
||||||
|
button_type,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
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<GamepadEvent>,
|
||||||
|
inputs: &mut Input<GamepadButton>,
|
||||||
|
axes: &mut Axis<GamepadAxis>,
|
||||||
|
) {
|
||||||
|
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);
|
||||||
|
if gilrs_gamepad.is_pressed(*gilrs_button) {
|
||||||
|
inputs.press(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.set(gamepad_axis, gilrs_gamepad.value(*gilrs_axis));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
events.send(GamepadEvent(gamepad, GamepadEventType::Connected));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn disconnect_gamepad(
|
||||||
|
gamepad: Gamepad,
|
||||||
|
events: &mut Events<GamepadEvent>,
|
||||||
|
inputs: &mut Input<GamepadButton>,
|
||||||
|
axes: &mut Axis<GamepadAxis>,
|
||||||
|
) {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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));
|
||||||
|
}
|
22
crates/bevy_gilrs/src/lib.rs
Normal file
22
crates/bevy_gilrs/src/lib.rs
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
mod converter;
|
||||||
|
mod gilrs_system;
|
||||||
|
|
||||||
|
use bevy_app::prelude::*;
|
||||||
|
use bevy_ecs::IntoQuerySystem;
|
||||||
|
use gilrs_system::{gilrs_startup_system, gilrs_update_system, GilrsArcMutexWrapper};
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct GilrsPlugin;
|
||||||
|
|
||||||
|
impl Plugin for GilrsPlugin {
|
||||||
|
fn build(&self, app: &mut AppBuilder) {
|
||||||
|
match gilrs::Gilrs::new() {
|
||||||
|
Ok(gilrs) => {
|
||||||
|
app.add_resource(GilrsArcMutexWrapper::new(gilrs))
|
||||||
|
.add_startup_system(gilrs_startup_system.system())
|
||||||
|
.add_system_to_stage(stage::EVENT_UPDATE, gilrs_update_system.system());
|
||||||
|
}
|
||||||
|
Err(err) => log::error!("Failed to start Gilrs. {}", err),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
33
crates/bevy_input/src/axis.rs
Normal file
33
crates/bevy_input/src/axis.rs
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
use std::{collections::HashMap, hash::Hash};
|
||||||
|
|
||||||
|
pub struct Axis<T> {
|
||||||
|
axis_data: HashMap<T, f32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Default for Axis<T>
|
||||||
|
where
|
||||||
|
T: Copy + Eq + Hash,
|
||||||
|
{
|
||||||
|
fn default() -> Self {
|
||||||
|
Axis {
|
||||||
|
axis_data: HashMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Axis<T>
|
||||||
|
where
|
||||||
|
T: Copy + Eq + Hash,
|
||||||
|
{
|
||||||
|
pub fn set(&mut self, axis: T, value: f32) -> Option<f32> {
|
||||||
|
self.axis_data.insert(axis, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get(&self, axis: &T) -> Option<f32> {
|
||||||
|
self.axis_data.get(axis).copied()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn remove(&mut self, axis: &T) -> Option<f32> {
|
||||||
|
self.axis_data.remove(axis)
|
||||||
|
}
|
||||||
|
}
|
52
crates/bevy_input/src/gamepad.rs
Normal file
52
crates/bevy_input/src/gamepad.rs
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub struct Gamepad(pub usize);
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||||
|
pub enum GamepadEventType {
|
||||||
|
Connected,
|
||||||
|
Disconnected,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||||
|
pub struct GamepadEvent(pub Gamepad, pub GamepadEventType);
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub enum GamepadButtonType {
|
||||||
|
South,
|
||||||
|
East,
|
||||||
|
North,
|
||||||
|
West,
|
||||||
|
C,
|
||||||
|
Z,
|
||||||
|
LeftTrigger,
|
||||||
|
LeftTrigger2,
|
||||||
|
RightTrigger,
|
||||||
|
RightTrigger2,
|
||||||
|
Select,
|
||||||
|
Start,
|
||||||
|
Mode,
|
||||||
|
LeftThumb,
|
||||||
|
RightThumb,
|
||||||
|
DPadUp,
|
||||||
|
DPadDown,
|
||||||
|
DPadLeft,
|
||||||
|
DPadRight,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub struct GamepadButton(pub Gamepad, pub GamepadButtonType);
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub enum GamepadAxisType {
|
||||||
|
LeftStickX,
|
||||||
|
LeftStickY,
|
||||||
|
LeftZ,
|
||||||
|
RightStickX,
|
||||||
|
RightStickY,
|
||||||
|
RightZ,
|
||||||
|
DPadX,
|
||||||
|
DPadY,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub struct GamepadAxis(pub Gamepad, pub GamepadAxisType);
|
|
@ -47,6 +47,12 @@ where
|
||||||
self.just_released.contains(&input)
|
self.just_released.contains(&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) {
|
pub fn update(&mut self) {
|
||||||
self.just_pressed.clear();
|
self.just_pressed.clear();
|
||||||
self.just_released.clear();
|
self.just_released.clear();
|
||||||
|
|
|
@ -1,12 +1,23 @@
|
||||||
|
mod axis;
|
||||||
|
pub mod gamepad;
|
||||||
mod input;
|
mod input;
|
||||||
pub mod keyboard;
|
pub mod keyboard;
|
||||||
pub mod mouse;
|
pub mod mouse;
|
||||||
pub mod system;
|
pub mod system;
|
||||||
|
|
||||||
|
pub use axis::*;
|
||||||
pub use input::*;
|
pub use input::*;
|
||||||
|
|
||||||
pub mod prelude {
|
pub mod prelude {
|
||||||
pub use crate::{keyboard::KeyCode, mouse::MouseButton, Input};
|
pub use crate::{
|
||||||
|
gamepad::{
|
||||||
|
Gamepad, GamepadAxis, GamepadAxisType, GamepadButton, GamepadButtonType, GamepadEvent,
|
||||||
|
GamepadEventType,
|
||||||
|
},
|
||||||
|
keyboard::KeyCode,
|
||||||
|
mouse::MouseButton,
|
||||||
|
Axis, Input,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
use bevy_app::prelude::*;
|
use bevy_app::prelude::*;
|
||||||
|
@ -14,6 +25,7 @@ use keyboard::{keyboard_input_system, KeyCode, KeyboardInput};
|
||||||
use mouse::{mouse_button_input_system, MouseButton, MouseButtonInput, MouseMotion, MouseWheel};
|
use mouse::{mouse_button_input_system, MouseButton, MouseButtonInput, MouseMotion, MouseWheel};
|
||||||
|
|
||||||
use bevy_ecs::IntoQuerySystem;
|
use bevy_ecs::IntoQuerySystem;
|
||||||
|
use gamepad::{GamepadAxis, GamepadButton, GamepadEvent};
|
||||||
|
|
||||||
/// Adds keyboard and mouse input to an App
|
/// Adds keyboard and mouse input to an App
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
@ -34,6 +46,9 @@ impl Plugin for InputPlugin {
|
||||||
.add_system_to_stage(
|
.add_system_to_stage(
|
||||||
bevy_app::stage::EVENT_UPDATE,
|
bevy_app::stage::EVENT_UPDATE,
|
||||||
mouse_button_input_system.system(),
|
mouse_button_input_system.system(),
|
||||||
);
|
)
|
||||||
|
.add_event::<GamepadEvent>()
|
||||||
|
.init_resource::<Input<GamepadButton>>()
|
||||||
|
.init_resource::<Axis<GamepadAxis>>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
93
examples/input/gamepad_input.rs
Normal file
93
examples/input/gamepad_input.rs
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
use bevy::prelude::*;
|
||||||
|
use bevy_input::gamepad::{Gamepad, GamepadButton, GamepadEvent, GamepadEventType};
|
||||||
|
use std::collections::HashSet;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
App::build()
|
||||||
|
.add_default_plugins()
|
||||||
|
.add_startup_system(connection_system.system())
|
||||||
|
.add_system(connection_system.system())
|
||||||
|
.add_system(button_system.system())
|
||||||
|
.add_system(axis_system.system())
|
||||||
|
.add_resource(Lobby::default())
|
||||||
|
.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
struct Lobby {
|
||||||
|
gamepad: HashSet<Gamepad>,
|
||||||
|
gamepad_event_reader: EventReader<GamepadEvent>,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn connection_system(mut lobby: ResMut<Lobby>, gamepad_event: Res<Events<GamepadEvent>>) {
|
||||||
|
for event in lobby.gamepad_event_reader.iter(&gamepad_event) {
|
||||||
|
match &event {
|
||||||
|
GamepadEvent(gamepad, GamepadEventType::Connected) => {
|
||||||
|
lobby.gamepad.insert(*gamepad);
|
||||||
|
println!("Connected {:?}", gamepad);
|
||||||
|
}
|
||||||
|
GamepadEvent(gamepad, GamepadEventType::Disconnected) => {
|
||||||
|
lobby.gamepad.remove(gamepad);
|
||||||
|
println!("Disconnected {:?}", gamepad);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn button_system(manager: Res<Lobby>, inputs: Res<Input<GamepadButton>>) {
|
||||||
|
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 manager.gamepad.iter() {
|
||||||
|
for button_type in button_types.iter() {
|
||||||
|
if inputs.just_pressed(GamepadButton(*gamepad, *button_type)) {
|
||||||
|
println!("Pressed {:?}", GamepadButton(*gamepad, *button_type));
|
||||||
|
} else if inputs.just_released(GamepadButton(*gamepad, *button_type)) {
|
||||||
|
println!("Released {:?}", GamepadButton(*gamepad, *button_type));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn axis_system(manager: Res<Lobby>, axes: Res<Axis<GamepadAxis>>) {
|
||||||
|
let axis_types = [
|
||||||
|
GamepadAxisType::LeftStickX,
|
||||||
|
GamepadAxisType::LeftStickY,
|
||||||
|
GamepadAxisType::LeftZ,
|
||||||
|
GamepadAxisType::RightStickX,
|
||||||
|
GamepadAxisType::RightStickY,
|
||||||
|
GamepadAxisType::RightZ,
|
||||||
|
GamepadAxisType::DPadX,
|
||||||
|
GamepadAxisType::DPadY,
|
||||||
|
];
|
||||||
|
for gamepad in manager.gamepad.iter() {
|
||||||
|
for axis_type in axis_types.iter() {
|
||||||
|
if let Some(value) = axes.get(&GamepadAxis(*gamepad, *axis_type)) {
|
||||||
|
if value.abs() > 0.01f32
|
||||||
|
&& (value - 1.0f32).abs() > 0.01f32
|
||||||
|
&& (value + 1.0f32).abs() > 0.01f32
|
||||||
|
{
|
||||||
|
println!("Axis {:?} is {}", GamepadAxis(*gamepad, *axis_type), value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -33,6 +33,9 @@ impl AddDefaultPlugins for AppBuilder {
|
||||||
#[cfg(feature = "bevy_audio")]
|
#[cfg(feature = "bevy_audio")]
|
||||||
self.add_plugin(bevy_audio::AudioPlugin::default());
|
self.add_plugin(bevy_audio::AudioPlugin::default());
|
||||||
|
|
||||||
|
#[cfg(feature = "bevy_gilrs")]
|
||||||
|
self.add_plugin(bevy_gilrs::GilrsPlugin::default());
|
||||||
|
|
||||||
#[cfg(feature = "bevy_gltf")]
|
#[cfg(feature = "bevy_gltf")]
|
||||||
self.add_plugin(bevy_gltf::GltfPlugin::default());
|
self.add_plugin(bevy_gltf::GltfPlugin::default());
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue