bevyengine / bevy

A refreshingly simple data-driven game engine built in Rust
https://bevyengine.org
Apache License 2.0
36.25k stars 3.57k forks source link

Document how to configure gamepads #3246

Open alice-i-cecile opened 2 years ago

alice-i-cecile commented 2 years ago

How can Bevy's documentation be improved?

GamepadInputSettings is somewhat challenging to figure out how to use. A simple example system would go a long way.

fn configure_gamepad(mut settings: ResMut<GamepadSettings>, gamepads: Res<Gamepads>) {
    if !settings.is_changed() | gamepads.is_changed() {
        return;
    }
    const DEADZONE: f32 = 0.1;

    // The joystick should not register inputs when near the center
    for &gamepad in gamepad_lobby.iter() {
        let left_stick_x = GamepadAxis(gamepad, GamepadAxisType::LeftStickX);
        let left_stick_y = GamepadAxis(gamepad, GamepadAxisType::LeftStickY);

        let mut left_x_settings = settings.axis_settings.get_mut(&left_stick_x).unwrap();
        left_x_settings.threshold = DEADZONE;

        let mut left_y_settings = settings.axis_settings.get_mut(&left_stick_y).unwrap();
        left_y_settings.threshold = DEADZONE;
    }
}
vabka commented 2 years ago

I want to take this issue but this example dont working with my xbox one controller: https://github.com/vabka/bevy/blob/add1818a05ad4b8d4672197afd477ab29f8446b5/examples/input/gamepad_input.rs

What i should look?

alice-i-cecile commented 2 years ago

I want to take this issue but this example dont working with my xbox one controller:

@vabka, I would start by filing an issue that your gamepad support isn't working :) That's another serious problem that we should investigate separately, in one form or another.

Then, I would start by opening a PR to add a new example. Feel free to skim https://github.com/bevyengine/bevy/blob/main/CONTRIBUTING.md if you need guidance.

You can test your example without a gamepad by mocking the inputs:

  1. Add a new fake gamepad to the GamePads resource using the register method.
  2. Manually set the value of the Axis<GamepadAxis> resource using the Axis::set method for that fake gamepad.

Once you're ready, put up your PR and we can verify that it works on physical controllers.

cart commented 2 years ago

I believe #3339 (just kicked off a merge) should fix @vabka's problem.

vabka commented 2 years ago

@cart Yeah.

vabka commented 2 years ago

I have a question about ButtonSettings.

  1. Buttons can be analogue?
  2. Value of button always between 0.0 and 1.0?
  3. Is this true?
    0 ... release ... press ... 1
               ^
               |_ Value
                  Button is not pressed and not released
    0 ... press ... release ... 1
             ^
             |_ Value
                Button is pressed and released at same time 
alice-i-cecile commented 2 years ago

These are very good questions, and the answers should be documented on ButtonSettings as part of a fix to this issue.

However, I don't immediately know the answers! My initial testing on an XBox controller suggested that the inputs were either 0.0 or 1.0: in which case exposing a f32 is silly. However, that is not consistent with the existence of ButtonSettings. I'm going to dig into the source, and that of our dependency, and come back with an answer.

alice-i-cecile commented 2 years ago

For 3: the logic is very simple:

impl ButtonSettings {
    fn is_pressed(&self, value: f32) -> bool {
        value >= self.press
    }

    fn is_released(&self, value: f32) -> bool {
        value <= self.release
    }
}
alice-i-cecile commented 2 years ago

We appear to be getting these values from

https://github.com/bevyengine/bevy/blob/e48f9d8cd4562d5ea6b483764ae9288feb13cc72/crates/bevy_input/src/gamepad.rs#L42

These are generated from the gilrs library here: https://github.com/bevyengine/bevy/blob/e48f9d8cd4562d5ea6b483764ae9288feb13cc72/crates/bevy_gilrs/src/gilrs_system.rs#L19

and then converted from GamepadEventRaw into GamepadEvent in https://github.com/bevyengine/bevy/blob/e48f9d8cd4562d5ea6b483764ae9288feb13cc72/crates/bevy_input/src/gamepad.rs#L268

So, why is gilrs giving us f32 for our buttons in its Gilrs::Event type?

The data is stored in the Gilrs::EventType enum:

pub enum EventType {
    ButtonPressed(EvCode),
    ButtonReleased(EvCode),
    AxisValueChanged(i32, EvCode),
    Connected,
    Disconnected,
}

That's very suspicious: there's no f32s to be found there... And from their docs, an EvCode is just a "Platform specific representation of axis or button."

Doing a quick search, I can see: https://github.com/Arvamer/gilrs/blob/952d22ce3bef4e11f594fa64b7309ce79d9a9a79/gilrs/src/ev/state.rs#L44, which returns a f32 for all of the Gamepad values, like we see exposed in our APIs. And aha, here we are! https://github.com/Arvamer/gilrs/blob/952d22ce3bef4e11f594fa64b7309ce79d9a9a79/gilrs/src/ev/state.rs#L81

Here we go:

                if pressed { 1.0 } else { 0.0 },

However, that isn't used for analogue buttons (generally, triggers are the only analogue buttons). I've found this very useful standards doc: https://w3c.github.io/gamepad/#dom-gamepadbutton-value

So ultimately our answers are:

  1. Yes, a button can be analogue. But for digital buttons, the value is either exactly 0.0 or 1.0.
  2. Yes, we're bounded between [0.0, 1.0].
  3. Whether or not a button is pressed or not depends strictly on its value. Buttons can be neither pressed nor released, but cannot be both pressed and released.
ghost commented 2 years ago

3692 might be relevant to take into consideration.

I extended the documentation for the bevy_input crate including the GamepadSettings, ButtonSettings, AxisSettings, and ButtonAxisSettings. I didn't create a separate example though.

richchurcher commented 1 month ago

Ooo. I could get my controller out of the box. I'll pick this up :joystick:

richchurcher commented 1 month ago

Oh, except https://github.com/bevyengine/bevy/pull/12770. Hrm. Hit pause on that one I guess.