Gamepad Support
Nightshade provides cross-platform gamepad support through the gilrs library.
Enabling Gamepad
Gamepad requires the gamepad feature:
[dependencies]
nightshade = { git = "...", features = ["engine", "gamepad"] }
Gamepad Resource
The gamepad state lives in world.resources.input.gamepad, which wraps the gilrs library:
#![allow(unused)] fn main() { pub struct Gamepad { pub gilrs: Option<gilrs::Gilrs>, pub gamepad: Option<gilrs::GamepadId>, pub events: Vec<gilrs::Event>, } }
The engine automatically initializes gilrs and tracks the active gamepad.
Querying the Active Gamepad
Use query_active_gamepad to get a gilrs gamepad handle for polling input:
#![allow(unused)] fn main() { use nightshade::ecs::input::queries::query_active_gamepad; fn run_systems(&mut self, world: &mut World) { if let Some(gamepad) = query_active_gamepad(world) { let left_x = gamepad.value(gilrs::Axis::LeftStickX); let left_y = gamepad.value(gilrs::Axis::LeftStickY); if gamepad.is_pressed(gilrs::Button::South) { self.jump(); } } } }
Button Input
Button States
#![allow(unused)] fn main() { use nightshade::ecs::input::queries::query_active_gamepad; fn run_systems(&mut self, world: &mut World) { if let Some(gamepad) = query_active_gamepad(world) { if gamepad.is_pressed(gilrs::Button::South) { jump(); } if gamepad.is_pressed(gilrs::Button::West) { attack(); } } } }
Button Mapping
| gilrs::Button | Xbox | PlayStation | Nintendo |
|---|---|---|---|
South | A | Cross | B |
East | B | Circle | A |
West | X | Square | Y |
North | Y | Triangle | X |
LeftTrigger | LB | L1 | L |
RightTrigger | RB | R1 | R |
Select | View | Share | - |
Start | Menu | Options | + |
DPadUp/Down/Left/Right | D-Pad | D-Pad | D-Pad |
Analog Sticks
#![allow(unused)] fn main() { if let Some(gamepad) = query_active_gamepad(world) { let move_x = gamepad.value(gilrs::Axis::LeftStickX); let move_y = gamepad.value(gilrs::Axis::LeftStickY); let look_x = gamepad.value(gilrs::Axis::RightStickX); let look_y = gamepad.value(gilrs::Axis::RightStickY); } }
Axis values range from -1.0 to 1.0.
Triggers
#![allow(unused)] fn main() { if let Some(gamepad) = query_active_gamepad(world) { let left = gamepad.value(gilrs::Axis::LeftZ); let right = gamepad.value(gilrs::Axis::RightZ); let acceleration = right * max_acceleration; } }
Event-Based Input
Handle gamepad events in the State trait using raw gilrs events:
#![allow(unused)] fn main() { fn on_gamepad_event(&mut self, world: &mut World, event: gilrs::Event) { if let gilrs::EventType::ButtonPressed(button, _) = event.event { match button { gilrs::Button::Start => self.paused = !self.paused, gilrs::Button::South => self.player_jump(), _ => {} } } } }
Combining Keyboard and Gamepad
#![allow(unused)] fn main() { use nightshade::ecs::input::queries::query_active_gamepad; struct PlayerInput { movement: Vec2, jump: bool, attack: bool, } fn gather_input(world: &mut World) -> PlayerInput { let mut input = PlayerInput { movement: Vec2::zeros(), jump: false, attack: false, }; let keyboard = &world.resources.input.keyboard; if keyboard.is_key_pressed(KeyCode::KeyW) { input.movement.y -= 1.0; } if keyboard.is_key_pressed(KeyCode::KeyS) { input.movement.y += 1.0; } if keyboard.is_key_pressed(KeyCode::KeyA) { input.movement.x -= 1.0; } if keyboard.is_key_pressed(KeyCode::KeyD) { input.movement.x += 1.0; } input.jump |= keyboard.is_key_pressed(KeyCode::Space); if let Some(gamepad) = query_active_gamepad(world) { let stick_x = gamepad.value(gilrs::Axis::LeftStickX); let stick_y = gamepad.value(gilrs::Axis::LeftStickY); if stick_x.abs() > 0.15 || stick_y.abs() > 0.15 { input.movement = Vec2::new(stick_x, stick_y); } input.jump |= gamepad.is_pressed(gilrs::Button::South); input.attack |= gamepad.is_pressed(gilrs::Button::West); } input } }