简体   繁体   中英

How to detect a button press with Gamepad API?

I am trying to write a web page where I can detect button presses on a Xbox controller and show a user a boolean value based on the button pressed. Right now, I can detect a controller being connected and show that as a string. The documentation says to use this code to detect a button press here:

var isPressed = navigator.getGamepads()[0].pressed;

but Chrome shows this error when using it:

Uncaught TypeError: Cannot read property 'pressed' of null

The error is linked to the .pressed part of the above line of code. All the documentation is on the Mozilla site , so I'm assuming they used FireFox when writing the tutorials.

What I ideally want to end up with is this:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<h id="button"></h>
<h id="gpInfo"></h>
<script>
var i = 1; 
window.addEventListener("gamepadconnected", function(e) {
  var gp = navigator.getGamepads()[e.gamepad.index];
  document.getElementById("gpInfo").innerHTML = ("A " + gp.id + " was successfully detected! There are a total of " + gp.buttons.length + " buttons.")
  //alert("A " + gp.id + " was successfully detected!")
});
var isPressed = navigator.getGamepads()[0].pressed;
document.getElementById("button").innerHTML = isPressed;
</script>
<!-- <script type="text/javascript" src="gamepadtest.js"></script> -->
</head>
</html>

The code would print a boolean value on the screen for users to see when they press a button. This is my first time working with JavaScript and HTML. If you could make your answer noob-friendly that would be great! Documentation for Gamepad API and for GamepadButton

You shouldn't reference the Gamepad object until the gamepadconnected event has been thrown. Also, you'll need a loop to poll the button value. Here's some revised code:

var i = 1; 
window.addEventListener("gamepadconnected", function(e) {
  var gp = navigator.getGamepads()[e.gamepad.index];
  document.getElementById("gpInfo").innerHTML = ("A " + gp.id + " was successfully detected! There are a total of " + gp.buttons.length + " buttons.")
  //alert("A " + gp.id + " was successfully detected!")

  setInterval(function(){
    isPressed = gp.buttons[0].pressed;
    document.getElementById("button").innerHTML = isPressed;
  }, 100)
});

I don't have enough reputation to just add a comment to Caleb Denio's answer , but regarding Nathan's comment on that answer:

I have used your example to listen for 20 buttons and i can detect each button, but once i have pressed one, it will not change another result for a different button.

I see the same behaviour on Chrome 90. Specifically, a new GamepadList instance, containing new Gamepad instances, all seem to be created each time the state of any gamepad changes (eg which of its buttons are pressed).

You can test it with this:

var gamepads = null;

function callback() {
    var new_gamepads = navigator.getGamepads();
    if(new_gamepads !== gamepads) {
        console.log('New GamepadList!', new_gamepads);
        gamepads = new_gamepads;
    }
}

var interval = setInterval(callback, 100);

...for me, that logs 'New GamepadList!' each time I press/release a button.

Long story short, you need to poll navigator.getGamepads() each frame in order to detect changes in gamepad state. A minimalist fix for Caleb Denio's answer would therefore be:

var i = 1; 
window.addEventListener("gamepadconnected", function(e) {
  var gp = navigator.getGamepads()[e.gamepad.index];
  document.getElementById("gpInfo").innerHTML = ("A " + gp.id + " was successfully detected! There are a total of " + gp.buttons.length + " buttons.")
  //alert("A " + gp.id + " was successfully detected!")

  setInterval(function(){

    // ===> Get a fresh GamepadList! <===
    var gp = navigator.getGamepads()[e.gamepad.index];

    isPressed = gp.buttons[0].pressed;
    document.getElementById("button").innerHTML = isPressed;
  }, 100)
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM