为什么onkeyup事件没有在javascript游戏中触发 [英] why are onkeyup events not firing in javascript game

查看:109
本文介绍了为什么onkeyup事件没有在javascript游戏中触发的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个2D游戏的开头 - 玩家可以使用箭头键在屏幕周围驱动一个三角形。

I have the beginnings of a 2d javascript game - at the moment the player can drive a triangle around the screen using the arrow keys.

问题是有时候三角形将在一个方向上旋转或向前移动,直到再次按下相应的控制键并再次触发onkeyup事件。当同时按下多个控制键时,通常会发生这种情况。

The problem is that sometimes the triangle will get stuck rotating in one direction or moving forward until the corresponding control key is pressed again and the onkeyup event is fired again. This usually happens when more than one control key is pressed at the same time.

我无法弄清楚为什么它会卡在第一位,除非onkeyup事件不是因某种原因被解雇了。任何帮助将不胜感激,谢谢。

I can't work out why it's getting stuck in the first place unless the onkeyup events aren't getting fired for some reason. Any help would be much appreciated, thank you.

这里有一些代码,你可以找到一个 JSFiddle上的完整工作示例

Here's some of the code, you can find a fully working example on JSFiddle:

...

function init(){
    var canvas = document.getElementById('canvas');
    if(canvas.getContext){
        setInterval(play, 50);
    }
}

function play(){
    printTriState();
    updateTriAcceleration();
    applyTriVelocity();
    updateTriRotation();
    draw();
}

document.onkeydown = function(event){

if(!event.keyCode){
    keycode = window.event.keyCode;
} else {
    keycode = event.keyCode;
}
console.log(event.keyCode);
switch(keycode){
    //left
    case 37:
    tri.rotation = -1;
    break;

    //up
    case 38:
    tri.throttle = true;
    break;

    //right
    case 39:
    tri.rotation = 1;
    break;

    //down
    case 40:
    tri.currentSpeed = 0;
    break;

    default:
    break;
}
};

document.onkeyup = function(event){

if(!event.keyCode){
    keycode = window.event.keyCode;
} else {
    keycode = event.keyCode;
}
console.log(event.keyCode);
switch(keycode){
    //left
    case 37:
    tri.rotation = 0;
    break;

    //up
    case 38:
    tri.throttle = false;
    break;

    //right
    case 39:
    tri.rotation = 0;
    break;

    //down
    case 40:

    break;

    default:
    break;
}
};

function updateTriRotation(){
    if(tri.rotation == 1){
        tri.orientation += tri.rotationSpeed;
    } else if (tri.rotation == -1){
        tri.orientation -= tri.rotationSpeed;
    } else {
        tri.orientation += 0;
    }
}

...


推荐答案

问题描述



keyup 事件已解雇但有时最终 keydown 事件在 keyup 之后直接触发。奇怪的?是。

Problem description

The keyup events are fired, but sometimes a final keydown event fires directly after the keyup. Weird? Yes.

问题在于如何实现重复保持密钥的 keydown 事件:
重复触发最后一次保持键的 keydown 事件。由于优化的JavaScript代码执行的异步,单线程特性,有时会发生这样的重复 keydown 事件之后 keyup 事件被解雇。

The problem is the way how the repetition of the keydown event for a held key is implemented:
the keydown event for the last held key is fired repeatedly. Due to the asynchronous, single-threaded nature of optimized JavaScript code execution, it can happen sometimes that such a repeated keydown event is fired after the corresponding keyup event was fired.

看看当我按住并释放按键[UP]和[RIGHT]时会发生什么同时在我的JSFiddle示例中

See what happens when i hold and release the keys [UP] and [RIGHT] simultaneously in my JSFiddle example.

在Windows 7上使用Firefox 13.0.1观察

rotation: 1 key down: 39
rotation: 1 key down: 38
rotation: 1 key down: 38
rotation: 1 key down: 38
rotation: 1 key up: 38
rotation: 0 key up: 39
rotation: 1 key down: 38

您可以在此示例控制台输出中看到三件事:

You can see three things in this example console output:


  1. 仅重复触发[RIGHT](38)的 keydown 事件。

  2. 当我发布密钥时,[RIGHT](38) keyup 事件被触发。

  3. 最后一次安排的 keydown 事件被触发, keyup 之后执行。

  1. only the keydown event for [RIGHT] (38) is fired repeatedly.
  2. The keyup event for [RIGHT] (38) is fired when i release the key.
  3. A last scheduled keydown event is fired, after the keyup was executed.

这就是你的轮换状态被卡住的原因值 1 即使没有按下任何键。

Thats the reason why your rotation state is "stuck" with value 1 even if no key is pressed.

为避免这种情况,您可以跟踪释放密钥时的微秒。当一个keydown事件发生只需几微秒时,我们就会默默地忽略它。

To avoid this, you can keep track of the microseconds when a key is released. When a keydown event occurs just a few microseconds ahead, then we silently ignore it.

我介绍了一个帮助对象键入到您的代码中。 在此JSFiddle示例中查看它。

I introduced a helper object Key into your code. See it working in this JSFiddle example.

现在控制台输出如下:

rotation: 1 key down: 40 time: 1340805132040
rotation: 1 key down: 40 time: 1340805132071
rotation: 1 key down: 40 time: 1340805132109
rotation: 1 key up: 40 time: 1340805132138
rotation: 0 key up: 39 time: 1340805132153
key down: 40 release time: 1340804109335
keydown fired after keyup .. nothing to do.
rotation: 0 key down: 39 time: 1340805132191

我的解决方案的灵感来自于这篇博客文章,更进一步并解释了如何避免使用JavaScript密钥事件进行游戏开发时的草率和单向问题。这绝对值得一读。

My solution is inspired by this blog article, which goes a bit further and explains how to avoid the sloppyness and "one-direction-only" issues you have when using JavaScript key events for game development. It's definitely worth reading.

忽略延迟的 keydown 事件的解决方法基本上如下:

The workaround to ignore the delayed keydown event basically looks like this:

var Key = {
    _pressed: {},
    _release_time: {},

    MAX_KEY_DELAY: 100,

    onKeydown: function(event) {

        // avoid firing of the keydown event when a keyup occured
        // just +/- 100ms before or after a the keydown event.
        // due to the asynchronous nature of JS it may happen that the
        // timestamp of keydown is before the timestamp of keyup, but 
        // the actual execution of the keydown event happens *after* 
        // the keyup.   Weird? Yes. Confusing!

        var time = new Date().getTime();
        if ( this._release_time[event.keyCode] &&
             time < this._release_time[event.keyCode] + this.MAX_KEY_DELAY ) {
            console.log('keydown fired after keyup .. nothing to do.');
            return false;
        }

        this._pressed[event.keyCode] = true;

        // LOGIC FOR ACTUAL KEY CODE HANDLING GOES HERE
    },

    onKeyup: function(event) {
        delete this._pressed[event.keyCode];
        this._release_time[event.keyCode] = new Date().getTime();

        // LOGIC FOR ACTUAL KEY CODE HANDLING GOES HERE
    }
};

document.onkeydown = function(event) { return Key.onKeydown(event); };
document.onkeyup = function(event) { return Key.onKeyup(event); };






更新#1 在JSFiddle上查找代码的更新(固定)版本

这篇关于为什么onkeyup事件没有在javascript游戏中触发的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆