PurpleKingdomGames / indigo

An FP game engine for Scala.
https://indigoengine.io/
MIT License
611 stars 56 forks source link

Examples crashing with Xbox One S controller #707

Closed bilki closed 3 months ago

bilki commented 3 months ago

Possible bug when using an Xbox One S controller in example games like The Cursed Pirate, Snake or Roguelike Tutorials. Basically pressing any button makes the whole game crash, and if we check the console we can see they are not recognized by GamepadInputCaptureImpl. In my case I was using the controller connected to a USB port, but I imagine this could happen too using the BT connection. I'm going to check both Indigo code and the examples code to find out what is the problem.

imagen

bilki commented 3 months ago

Layout seems to be the same, with the only differences being button names and Xbox controller not featuring the touchpad:

/* Xbox One S layout
    Axis Array:
    0 left stick X (double 1 is right -1 is left)
    1 left stick Y (double 1 is down -1 is up)
    2 right stick X (double 1 is right -1 is left)
    3 right stick Y (double 1 is down -1 is up)

    Buttons Array:
    0   A
    1   B
    2   X
    3   Y
    4   LB
    5   RB
    6   LT (Firefox detects this trigger as analog whereas Chrome as button)
    7   RT (Same as LT)
    8   View
    9   Menu
    10  Left Stick Press
    11  Right Stick Press
    12  D Up
    13  D Down
    14  D Left
    15  D Right
    16  Xbox Button
*/
bilki commented 3 months ago

Since this button does not exist in Xbox One S controller, GamepadButtons evaluation crashes. A workaround I've tried successfully is fixing this value to false, maybe we can read the gamepad number of buttons or infer them from the gamepad id.

https://github.com/PurpleKingdomGames/indigo/blob/adf1b13b511b0ac8c5db8a6caf46baadf8b5b4d9/indigo/indigo/src/main/scala/indigo/platform/input/GamepadInputCaptureImpl.scala#L78

bilki commented 3 months ago

As per Chromium, the getGamepads call returns an array of four elements in my case, the first one being the actual gamepad and the others null :thinking: That means that when trying to evaluate those three null gamepads in the filter(_.connected) we get a Uncaught TypeError: Cannot read properties of null (reading 'connected'), which makes sense since there's nothing there.

A sensible workaround for this line: https://github.com/PurpleKingdomGames/indigo/blob/adf1b13b511b0ac8c5db8a6caf46baadf8b5b4d9/indigo/indigo/src/main/scala/indigo/platform/input/GamepadInputCaptureImpl.scala#L52

Could be:

gamepads.find(Option(_).exists(_.connected)) match {

And now I get into an even more intriguing issue, since it seems that pressing one button makes the game think it's never released, and I can't press any other to get it out of this stuck state (this only happens in Chromium, Firefox is working just fine).

bilki commented 3 months ago

Ok so apparently in Chromium/Chrome it's a common practice to call getGamepads inside the game loop (check out MDN tutorials), somehow it doesn't update the gamepad state internally as Firefox does. Could be interesting to try with other browsers but since right now all of them are effectively FF or Webkit-based I think it is fair to assume this will work exactly the same in Safari and others.

So I'll open a PR including all these changes and resolve the issue.