4

使用 HTML5 画布和 javascript 开发一个小游戏。它工作得很好,除了键盘键偶尔会“卡住”,即。它会注册一个 keydown 事件,但有时它不会注册 keyup 事件。这通常发生在一次按下多个键时,因此部分是硬件或操作系统故障,但我希望有人对如何解决这个问题有想法。我的代码的相关部分(用咖啡脚本编写):

press = (direction) ->
    switch direction
        when 'W'
            game.keys.W = true
        when 'S'
            game.keys.S = true
        when 'A'
            game.keys.A = true
        when 'D'
            game.keys.D = true


release = (direction) ->
    switch direction
        when 'W'
            game.keys.W = false
        when 'S'
            game.keys.S = false
        when 'A'
            game.keys.A = false
        when 'D'
            game.keys.D = false

doKeyDown = (evt) ->
    switch evt.keyCode
        when 87 then press 'W'
        when 83 then press 'S'
        when 65 then press 'A'
        when 68 then press 'D'

doKeyUp = (evt) ->
    switch evt.keyCode
        when 87 then release 'W'
        when 83 then release 'S'
        when 65 then release 'A'
        when 68 then release 'D'

window.addEventListener('keydown', doKeyDown, false)

window.addEventListener('keyup', doKeyUp, false)

基本的东西。如果 javascript 不完全是事件驱动的,那将不是问题,但你能做什么。我目前关于如何规避该问题的想法是添加一个按键队列,可容纳 2 个或 3 个键,当超出限制时,删除第一个键并切换为“假” . 尽管如此,在应该可以避免的情况下添加这样的人为限制似乎很奇怪!

那么,问题是,是否有一种直接的方法可以确保准确保存关键状态,而无需求助于变通方法?最好是独立于游戏帧率工作的东西(无论它是以 1000 fps 还是 3 fps 运行,都应该同样好用)。

4

4 回答 4

3

由于keydown事件快速触发,您可以存储一个时间戳,记录您最后一次听到按键被按下的时间:

when 'A'
    game.keys.A = [true, +newDate()]

keydown然后,运行一个间隔函数来检查仍然注册为按下但在一段时间内(例如,1 秒)没有发送事件的键,并将它们设置为释放。

我上面的例子可能需要你重构很多代码(因为game.keys.A现在是一个数组而不是一个布尔值)。相反,您可以将时间戳保存在它们自己的对象中:

last_keydown_times = {};
...

when 'A'
    game.keys.A = true
    last_keydown_times['A'] = +new Date();

让间隔函数检查last_keydown_times(可能在for...in循环中)的成员并检查过期值:

setInterval(function() {
    var now = +new Date();
    for(key in last_keydown_times) {
        if(now - last_keydown_times[key] >= 1000) {
            // run the release code for this key
        }
    }
}, 1000);
于 2012-06-08T15:58:27.163 回答
2

如果在 OSX 上发生这种情况,请注意在按住键时您根本不会收到任何 keyup 事件。cmd

AFAICT没有解决这个问题。跟踪当前按下的键的唯一方法是通过 keyup/keydown 事件,而在 Mac 上,cmd 键会窃取您的这些信息。

于 2013-12-28T21:44:37.703 回答
1

值得指出的是,keydown事件多于keyup事件实际上是预期的行为:当您按住一个键时,操作系统将报告为keydown多个在 Mac OS 10.7 下,具有默认的按键行为)。keyup只有当钥匙被物理释放时,你才会得到一个。

当然,您的代码不应受到此问题的影响。因此,如果您确实处于释放密钥后很好的game.keys.A情况,您应该将其报告为您遇到问题的浏览器中的错误。我不相信解决方法是可能的。trueA

于 2012-06-08T14:57:30.343 回答
0

这是除了更昂贵的键盘之外的所有键盘的常见问题。

举个例子,试着玩一个游戏,你可以用箭头键移动,用空格键开火。您会发现按两个箭头可能会导致您无法射击。

不幸的是,您无法解决此问题,因为很多键盘都不同。您应该做的是允许用户在遇到问题时自定义他们的控件,以便他们可以更改为一组没有此问题的控件。

于 2012-06-08T15:00:14.280 回答