bevyengine / bevy

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

Button data is typically binary, but is treated as if it were continuous #3398

Open alice-i-cecile opened 2 years ago

alice-i-cecile commented 2 years ago

What problem does this solve or what need does it fill?

Button data often cannot be analogue, it is etiher exactly 0.0 or 1.0 (at least, when returned by gilrs). See the investigation in https://github.com/bevyengine/bevy/issues/3246#issuecomment-997977629.

However, we return a f32, which is always (at least, when using gilrs) either exactly 0.0 or 1.0.

Moreover, we have an often useless ButtonSettings struct, which thresholds these returned values in a configurable way, and converts them back into a bool.

Finally, our official example demonstrates that we should be using Axis for gamepad triggers, which is semantically wrong.

What solution would you like?

  1. Clearly document that we follow https://w3c.github.io/gamepad/#dom-gamepadbutton-value
  2. Do not allow triggers to be used as an Axis: see https://github.com/bevyengine/bevy/blob/340957994dc2c85f7a3ebc5ea6a5ad1b161e0041/examples/input/gamepad_input.rs#L23 for a confusing example.
  3. (PERF): Specialize buttons based on them being analogue / digital, and skip the repeated conversions and confusion.

What alternative(s) have you considered?

  1. Eliminate ButtonSettings completely.
  2. Only expose a binary value to end-users.
  3. Store the received button input value as a bool as soon as we receive it from gilrs.

I would probably prefer a

enum ButtonState {
  Pressed,
  NotPressed
}

as our representation oif this data, but even a bool would be significantly better than our current f32.

This solution is not as good as the above, as it is not standards compliant and doesn't handle triggers nicely (they're clearly buttons, not axes).

Additional context

Identified in #3246.

alice-i-cecile commented 2 years ago

Interestingly, the web standard uses a [0.0, 1.0] range as well, and seems to suggest that analogue inputs could exist: https://developer.mozilla.org/en-US/docs/Web/API/GamepadButton/value

See https://doc.stride3d.net/4.0/en/manual/input/gamepads.html.

I think I see the distinction here:

cart commented 2 years ago

Given that for a given input name, it might be analog or binary depending on the controller, I think it makes sense for us to allow inputs to be treated as either an axis or a button, depending on the needs of the game.

Analog axes can be treated as binary buttons by defining a "pressed range". Binary buttons can be treated as axes by mapping "not pressed" to 0.0 and "pressed" to 1.0.

alice-i-cecile commented 2 years ago

Given that for a given input name, it might be analog or binary depending on the controller, I think it makes sense for us to allow inputs to be treated as either an axis or a button, depending on the needs of the game.

I agree: different controllers and different games might want to treat the same button as either binary or analog.

IMO the correct way to do this is to expose a value method on the button, that specific games can access. This allows us to follow the specific, and clearly differentiate between Axes ([-1.0, 1.0]) and Buttons ([0.0, 1.0]) in a principled way.