4

我正在使用 250 毫秒计时器在 js 中轮询 Gamepad,以在 4 个不同的视点之间切换。然而,这个值仍然太高,无法保证看到每个按钮按下。我注意到如果一个按钮被按下和释放太快(即,< 250ms),那么它就会被错过。

除了控制器连接和断开连接外,我看不到任何与游戏手柄相关的事件触发器,并且我被轮询和增加频率所困。

任何人都可以提出一种保证检测到按钮按下而不增加轮询频率的方法吗?如果增加轮询频率是唯一的选择,那么什么是最佳选择?

4

2 回答 2

2

您应该以(至少)60 Hz 的频率进行轮询,以确保每个动画帧至少捕获一次新的按钮/轴状态。大多数应用程序在 requestAnimationFrame 循环中进行轮询,但这并不总是最好的解决方案,因为您仍然可能会错过按钮按下。

最佳轮询率由浏览器的内部行为决定。例如,在 Chrome 中,浏览器仅每 16 毫秒(62.5 Hz)获取新的游戏手柄状态,因此如果您以 ~100 Hz 的频率进行轮询,那么您一定会看到每次更新。如果在轮询迭代之间发生按钮按下,仍然可能会错过按钮按下,但您对此无能为力。(几乎没有:Chrome Dev 和 Canary 版本有一个 chrome://flags#gamepad-polling-rate 选项,您可以使用它来测试不同的内部轮询率。)

内部轮询率未由规范定义,不直接暴露给页面,并且可能会发生变化。例如,浏览器可以选择合并游戏手柄输入更新并将它们与 requestAnimationFrame 循环对齐,这将抵消更频繁轮询带来的任何好处。在依赖特定于实现的行为并测试您的假设时要小心。

在 Firefox 上,您可以启用非标准按钮和轴事件,这可以让您检测输入更新何时发生在正常轮询循环之外。AFAIK 这些事件仅在 FF 上实现,默认情况下被禁用,但可能对测试有用。

于 2018-07-23T16:34:38.617 回答
1

Gamepad API 确实只支持轮询,而且你的轮询频率确实太低了。

假设您正在尝试构建游戏,理想情况下,游戏手柄的响应速度应与游戏的帧速率一样高。这将确保始终捕捉到按钮按下。

JavascriptrequestAnimationFrame就是为此目的而设计的。

如果您查看neogeek 的 gamepad.js,您会看到它使用 API 在每一帧轮询游戏手柄:

Gamepad.prototype._loop = function () {

    ...

    self._events.gamepad.forEach(function (gamepad, player) {    
        if (gamepad) { 
            Object.keys(gamepad).forEach(function (key) {   
                self._handleEvent(key, gamepad, player);   
            });    
        }    
    });

    ...

    self._requestAnimation = _requestAnimationFrame(self._loop.bind(self));
}
于 2018-07-23T06:05:51.693 回答