5

私は2D Javascriptゲームの始まりを持っています - 現時点では、プレイヤーは矢印キーを使って画面の周りに三角形を動かすことができます.

onkeyup問題は、対応するコントロール キーが再度押されてイベントが再度発生するまで、三角形が一方向に回転したり、前方に移動したりしてスタックする場合があることです。これは通常、複数のコントロール キーを同時に押したときに発生します。

onkeyupなんらかの理由でイベントが発生しない限り、そもそもなぜ動かなくなっているのかわかりません。どんな助けでも大歓迎です、ありがとう。

コードの一部を次に示します。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;
    }
}

...
4

2 に答える 2

12

問題の説明

keyupイベント発生しますが、最終イベントが の直後に発生することがありkeydownますkeyup。変?はい。

問題は、keydown保持されたキーのイベントの繰り返しがどのように実装されるかです。最後に保持されたキー
keydownイベントが繰り返し発生します。最適化された JavaScript コード実行の非同期のシングルスレッドの性質により、対応するイベントが発生した後にkeydown、そのような繰り返しイベントが発生することがあります。keyup

JSFiddle の例でキー [UP] と [RIGHT] を同時に押したままにするとどうなるかを確認してください。

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

このコンソール出力の例では、次の 3 つのことがわかります。

  1. keydown[RIGHT] (38)のイベントのみが繰り返し発生します。
  2. keyup[RIGHT] (38)のイベント、キーを放すと発生します。
  3. が実行された後、最後にスケジュールされたkeydownイベントが発生します。keyup

これが、キーが押されていなくてもrotation状態が値で「スタック」する理由です。1


解決

これを避けるために、キーが離されたときのマイクロ秒を追跡できます。キーダウン イベントが数マイクロ秒先に発生すると、黙って無視します。

Keyコードにヘルパー オブジェクトを導入しました。この JSFiddle の例で動作を確認してください。

コンソール出力は次のようになります。

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 キー イベントを使用するときに発生する、だらしのなさや「一方向のみ」の問題を回避する方法について説明しています。間違いなく読む価値があります。

遅延keydownイベントを無視する回避策は、基本的に次のようになります。

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 でコードの更新された (修正された) バージョンを見つけます。

于 2012-06-27T13:50:17.023 に答える