DEV Community

Discussion on: Adding Game Controller Input to React

Collapse
 
ekeijl profile image
Edwin • Edited

Hey man, awesome in depth article! I tried to do the same thing for some side project. I used the gamepads library as an abstraction layer for the Gamepad API and used that in my React app.

Instead of storing all gamepad buttons in state, I passed a mapping to my custom hook that allows you to handle button events. This way, you can handle button presses just like onClick events. I also use a React Context to store the registered gamepads.

This is the custom hook for registering listeners on a gamepad:

const useGamepad = (gamepad, mapping) => {
  useEffect(() => {
    if (!gamepad) return;

    const handleButton = e => {
      if (mapping[e.index]) {
        mapping[e.index]();
      }
    };
    gamepad.addEventListener("buttonpress", handleButton);

    return () => {
      gamepad.removeEventListener("buttonpress", handleButton);
    };
  }, [gamepad, mapping]);
};
Enter fullscreen mode Exit fullscreen mode

And in your component, you use it like this (BUTTONS is a standard mapping provided by the gamepads library):

    useGamepad(gamepad, {
        [BUTTONS.BUTTON_LEFT]: (e) => doSomething(e),
        [BUTTONS.D_PAD_UP]: (e) => doSomethingElse(e),
    });
Enter fullscreen mode Exit fullscreen mode

I never really finished this and I remember it being a little buggy, but I like how declarative this approach is. It allows you to keep the event handling in one place, away from the logic of your component. I'm wondering if this would be better for performance, compared to rendering the app with the gamepad state all the time?

On a side note, the guy from the gamepads library also published gamepad-icons, which makes it easy to display gamepad button icons in your UI. It's also possible to detect the type of controller and show the matching icons.