Integration of bevy gamepad support

Until the beginning of my game all controle where hard coded in the code that handle the logic.

I need to do two things with my controller code:

  • Split it inside the client code.

  • Send the client code action to the shared code.

  • Use abstraction to handle gamepad and input for each player

For now i will only two the second one for the gamepad and latter on i will split the input and the logic code. Also i need to prepare my code for local multiplayer and replace all the case that handle ressource considering that only one set can exists , of the player one, but it all need to loop on each player.

Starting gamepad support

I added issue at first to get things to work. I try to integrate the events but none where triggering. All because inside my Cargo.yaml i had default-features: false so the package that i needed for gamepad support bevy_gilrs was not compilling. I added it and now it’s working fine.

So what i did is a written a small struct with an implementation similar to Input<> of bevy that contains a reference to all input source needed and depending on the player configure and it’s input configuration to get the input event.

I then write a ugly as fuck typealias with an tuple to store the mapping for each type on controller and i use this.

pub type GameButton = (KeyCode, MouseButton, GamepadButtonType);

pub const CHANGE_WEAPON_BTN: GameButton = (KeyCode::Tab, MouseButton::Middle, GamepadButtonType::North);
pub const RELOAD_WEAPON_BTN: GameButton = (KeyCode::R, MouseButton::Right, GamepadButtonType::West);
pub const FIRED_WEAPON_BTN: GameButton = (KeyCode::Space, MouseButton::Left, GamepadButtonType::RightTrigger);
pub const INTERACTION_BTN: GameButton = (KeyCode::F, MouseButton::Other(0), GamepadButtonType::South);

pub struct PlayerInputs<'a> {
    pub keyboard_input: &'a Res<'a,Input<KeyCode>>,
    pub buttons_mouse: &'a Res<'a, Input<MouseButton>>,
    pub buttons_gamepad: &'a Res<'a, Input<GamepadButton>>,

    pub current_controller: &'a PlayerCurrentInput,
}

impl <'a> PlayerInputs <'a> {

    pub fn pressed(&self, button: &GameButton) -> bool {
        return if self.current_controller.input_source == SupportedController::Keyboard {
            return self.keyboard_input.pressed(button.0) || self.buttons_mouse.pressed(button.1);
        } else {
            let gamepad_button = GamepadButton(self.current_controller.gamepad.unwrap(), button.2);
            return self.buttons_gamepad.pressed(gamepad_button);
        }
    }

    pub fn just_pressed(&self, button: &GameButton) -> bool {
        return if self.current_controller.input_source == SupportedController::Keyboard {
            return self.keyboard_input.just_pressed(button.0) || self.buttons_mouse.just_pressed(button.1);
        } else {
            let gamepad_button = GamepadButton(self.current_controller.gamepad.unwrap(), button.2);
            return self.buttons_gamepad.just_pressed(gamepad_button);
        }
    }
}

What i need to do is have to only receive the Input source but it’s more complicated and i would have to deal with dynamic implementation so i did this simple solution instead for now. Very not clean but it does the job.

Also i modified my LookingAt component to have a mode with instead of receive a point where you look it’s only a direction of where you are looking at. Usefull for my gamepad support to translate the mouse point location to the right joystick.