use std::collections::HashMap;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum GamepadButton {
South, East, West, North, LeftBumper,
RightBumper,
LeftTrigger,
RightTrigger,
Select,
Start,
LeftStick,
RightStick,
DPadUp,
DPadDown,
DPadLeft,
DPadRight,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum GamepadAxis {
LeftStickX,
LeftStickY,
RightStickX,
RightStickY,
LeftTrigger,
RightTrigger,
}
#[derive(Debug, Clone)]
pub struct GamepadState {
pub id: usize,
pub connected: bool,
pub buttons: HashMap<GamepadButton, bool>,
pub axes: HashMap<GamepadAxis, f32>,
}
impl GamepadState {
pub fn new(id: usize) -> Self {
Self {
id,
connected: true,
buttons: HashMap::new(),
axes: HashMap::new(),
}
}
pub fn is_button_pressed(&self, button: GamepadButton) -> bool {
self.buttons.get(&button).copied().unwrap_or(false)
}
pub fn get_axis(&self, axis: GamepadAxis) -> f32 {
self.axes.get(&axis).copied().unwrap_or(0.0)
}
pub fn set_button(&mut self, button: GamepadButton, pressed: bool) {
self.buttons.insert(button, pressed);
}
pub fn set_axis(&mut self, axis: GamepadAxis, value: f32) {
self.axes.insert(axis, value);
}
}
pub struct GamepadManager {
gamepads: HashMap<usize, GamepadState>,
deadzone: f32,
}
impl GamepadManager {
pub fn new() -> Self {
Self {
gamepads: HashMap::new(),
deadzone: 0.15,
}
}
pub fn with_deadzone(mut self, deadzone: f32) -> Self {
self.deadzone = deadzone.clamp(0.0, 1.0);
self
}
pub fn connect_gamepad(&mut self, id: usize) {
self.gamepads.insert(id, GamepadState::new(id));
println!("🎮 Gamepad {} conectado", id);
}
pub fn disconnect_gamepad(&mut self, id: usize) {
if let Some(gamepad) = self.gamepads.get_mut(&id) {
gamepad.connected = false;
println!("🎮 Gamepad {} desconectado", id);
}
}
pub fn get_gamepad(&self, id: usize) -> Option<&GamepadState> {
self.gamepads.get(&id)
}
pub fn get_gamepad_mut(&mut self, id: usize) -> Option<&mut GamepadState> {
self.gamepads.get_mut(&id)
}
pub fn is_button_pressed(&self, button: GamepadButton) -> bool {
self.gamepads
.values()
.any(|g| g.connected && g.is_button_pressed(button))
}
pub fn get_axis(&self, axis: GamepadAxis) -> f32 {
self.gamepads
.values()
.find(|g| g.connected)
.map(|g| self.apply_deadzone(g.get_axis(axis)))
.unwrap_or(0.0)
}
fn apply_deadzone(&self, value: f32) -> f32 {
if value.abs() < self.deadzone {
0.0
} else {
let sign = value.signum();
let normalized = (value.abs() - self.deadzone) / (1.0 - self.deadzone);
sign * normalized
}
}
pub fn connected_count(&self) -> usize {
self.gamepads.values().filter(|g| g.connected).count()
}
pub fn connected_ids(&self) -> Vec<usize> {
self.gamepads
.values()
.filter(|g| g.connected)
.map(|g| g.id)
.collect()
}
}
impl Default for GamepadManager {
fn default() -> Self {
Self::new()
}
}