sevenx_engine 0.2.11

Engine de jogos 2D/3D completa com suporte Android, física, áudio, partículas, tilemap, UI, eventos e sistema 3D avançado com PBR.
Documentation
use std::collections::HashMap;

/// Representa os botões de um gamepad.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum GamepadButton {
    South,      // A / Cross
    East,       // B / Circle
    West,       // X / Square
    North,      // Y / Triangle
    LeftBumper,
    RightBumper,
    LeftTrigger,
    RightTrigger,
    Select,
    Start,
    LeftStick,
    RightStick,
    DPadUp,
    DPadDown,
    DPadLeft,
    DPadRight,
}

/// Representa os eixos analógicos de um gamepad.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum GamepadAxis {
    LeftStickX,
    LeftStickY,
    RightStickX,
    RightStickY,
    LeftTrigger,
    RightTrigger,
}

/// Estado de um gamepad.
#[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);
    }
}

/// Gerenciador de gamepads.
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
    }

    /// Conecta um gamepad.
    pub fn connect_gamepad(&mut self, id: usize) {
        self.gamepads.insert(id, GamepadState::new(id));
        println!("🎮 Gamepad {} conectado", id);
    }

    /// Desconecta um gamepad.
    pub fn disconnect_gamepad(&mut self, id: usize) {
        if let Some(gamepad) = self.gamepads.get_mut(&id) {
            gamepad.connected = false;
            println!("🎮 Gamepad {} desconectado", id);
        }
    }

    /// Obtém o estado de um gamepad.
    pub fn get_gamepad(&self, id: usize) -> Option<&GamepadState> {
        self.gamepads.get(&id)
    }

    /// Obtém o estado mutável de um gamepad.
    pub fn get_gamepad_mut(&mut self, id: usize) -> Option<&mut GamepadState> {
        self.gamepads.get_mut(&id)
    }

    /// Verifica se um botão está pressionado em qualquer gamepad.
    pub fn is_button_pressed(&self, button: GamepadButton) -> bool {
        self.gamepads
            .values()
            .any(|g| g.connected && g.is_button_pressed(button))
    }

    /// Obtém o valor de um eixo do primeiro gamepad conectado.
    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)
    }

    /// Aplica deadzone a um valor de eixo.
    fn apply_deadzone(&self, value: f32) -> f32 {
        if value.abs() < self.deadzone {
            0.0
        } else {
            // Normaliza o valor após aplicar deadzone
            let sign = value.signum();
            let normalized = (value.abs() - self.deadzone) / (1.0 - self.deadzone);
            sign * normalized
        }
    }

    /// Retorna o número de gamepads conectados.
    pub fn connected_count(&self) -> usize {
        self.gamepads.values().filter(|g| g.connected).count()
    }

    /// Lista os IDs de todos os gamepads conectados.
    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()
    }
}

// Nota: Para implementação completa com gamepad real, adicione ao Cargo.toml:
// gilrs = "0.10" (para suporte a gamepad multiplataforma)