web-dev-qa-db-ja.com

javascriptのキー押下遅延を削除します

次の問題があります。JavaScriptゲームを作成しようとしていますが、文字が矢印キーで制御されています。
問題は、キーを押し続けたときに、最初のキーを押してから繰り返しキーを押すまでに短い遅延があることです。
また、「右矢印キー」を押し続けてから「上矢印キー」を押すと、キャラクターは右上隅に移動せず、正しい方向への移動を停止します。そして上昇し始めます。
これは私が使用しているコードです:

<body onLoad="Load()" onKeyDown="Pressed(event)">
 function Pressed(e){
 cxc = e.keyCode; 
 if(cxc == 37)
 Move(-1,0); 
 if(cxc == 38)
 Move(0、-1); 
 if(cxc == 39)
 Move(1,0); 
 if(cxc == 40)
 Move(0,1); 
} 

誰かアイデアがありますか?

25
alex

キーを制御可能な方法で繰り返す必要がある場合は、キーを繰り返す方法に関するOSの考え方に応じてキー押下イベントが発生するため、自分で実装する必要があります。つまり、初期遅延と後続遅延が変動する可能性があり、2つのキーを同時に押し続けると、そのうちの1つだけが繰り返されます。

各キーが現在押されているかどうかを記録し、キーがすでに押されている場合はkeydownイベントを無視する必要があります。これは、多くのブラウザが自動リピートが発生したときにkeydownイベントとkeypressイベントを発生させるためです。キーリピートを自分で再現する場合は、それを抑制する必要があります。

例えば:

// Keyboard input with customisable repeat (set to 0 for no key repeat)
//
function KeyboardController(keys, repeat) {
    // Lookup of key codes to timer ID, or null for no repeat
    //
    var timers= {};

    // When key is pressed and we don't already think it's pressed, call the
    // key action callback and set a timer to generate another one after a delay
    //
    document.onkeydown= function(event) {
        var key= (event || window.event).keyCode;
        if (!(key in keys))
            return true;
        if (!(key in timers)) {
            timers[key]= null;
            keys[key]();
            if (repeat!==0)
                timers[key]= setInterval(keys[key], repeat);
        }
        return false;
    };

    // Cancel timeout and mark key as released on keyup
    //
    document.onkeyup= function(event) {
        var key= (event || window.event).keyCode;
        if (key in timers) {
            if (timers[key]!==null)
                clearInterval(timers[key]);
            delete timers[key];
        }
    };

    // When window is unfocused we may not get key events. To prevent this
    // causing a key to 'get stuck down', cancel all held keys
    //
    window.onblur= function() {
        for (key in timers)
            if (timers[key]!==null)
                clearInterval(timers[key]);
        timers= {};
    };
};

その後:

// Arrow key movement. Repeat key five times a second
//
KeyboardController({
    37: function() { Move(-1, 0); },
    38: function() { Move(0, -1); },
    39: function() { Move(1, 0); },
    40: function() { Move(0, 1); }
}, 200);

ただし、ほとんどのアクションベースのゲームには固定時間のメインフレームループがあり、キーのアップ/ダウン処理を結び付けることができます。

32
bobince

私はそれを次のように解決しました:

 varpressedl = 0; 
 varpressedu = 0; 
 varpressedr = 0; 
 varpressed = 0; 
 
 function Down(e){
 cxc = e.keyCode; 
 if(cxc == 37)
 Pressedl = 1; 
 if(cxc == 38) 
 pressedu = 1; 
 if(cxc == 39)
 Pressedr = 1; 
 if(cxc == 40)
 Pressed = 1 ; 
 // alert(cxc); 
} 
 function Up(e){
 cxc = e.keyCode; 
 if(cxc = = 37)
 Pressedl = 0; 
 if(cxc == 38)
 Pressedu = 0; 
 if(cxc == 39)
 Pressedr = 0; 
 if(cxc == 40)
 Pressed = 0; 
 // alert(cxc); 
} 

<body onLoad="Load()" onKeyDown="Down(event)" onKeyUp="Up(event)">

5
alex

キーダウンで移動を開始し、キーアップでのみ終了することができますか?

3
supakeen

これは、より抽象的なバージョンでのルーカスのソリューションです。

http://jsfiddle.net/V2JeN/4/

驚いたことに、一度に3つのキーしか押すことができないようです。

1
dirkk0

私はこれはまったくの初心者ですが、KeyDownとKeyUpを組み合わせてみませんか?私は現在同様のプロジェクトに取り組んでおり、チェックアウトした後 quirksmode ダウンとアップの間のすべての時間が目的を実現するように2つのイベントを組み合わせる方法を理解することに着手します影響します。

1
jtmengel

これは@bobinceからの優れた回答とほぼ同じです

間隔の個々の値を許可するように少し修正しました

// Keyboard input with customisable repeat (set to 0 for no key repeat)
// usage
/**
KeyboardController({
    32: {interval:0, callback: startGame },
    37: {interval:10, callback: function() { padSpeed -= 5; } },
    39: {interval:10, callback: function() { padSpeed += 5; } }
});
*/

function KeyboardController(keyset) {
    // Lookup of key codes to timer ID, or null for no repeat
    //
    var timers= {};

    // When key is pressed and we don't already think it's pressed, call the
    // key action callback and set a timer to generate another one after a delay
    //
    document.onkeydown= function(event) {
        var key= (event || window.event).keyCode;
        if (!(key in keyset))
            return true;
        if (!(key in timers)) {
            timers[key]= null;
            keyset[key].callback();
            if (keyset[key].interval !== 0)
                timers[key]= setInterval(keyset[key].callback, keyset[key].interval);
        }
        return false;
    };

    // Cancel timeout and mark key as released on keyup
    //
    document.onkeyup= function(event) {
        var key= (event || window.event).keyCode;
        if (key in timers) {
            if (timers[key]!==null)
                clearInterval(timers[key]);
            delete timers[key];
        }
    };

    // When window is unfocused we may not get key events. To prevent this
    // causing a key to 'get stuck down', cancel all held keys
    //
    window.onblur= function() {
        for (key in timers)
            if (timers[key]!==null)
                clearInterval(timers[key]);
        timers= {};
    };
};

この質問で与えられた理由のために、setIntervalの代わりにsetTimeoutを使用する計画もあります: setTimeoutまたはsetInterval?

修正してテストしたら、この回答を更新します。

1
chim

このイベントはwhateverを1つの位置から1つの位置に移動することなので、onkeypressイベントを使用してみませんか。そうすれば、ユーザーキーがupキーを押すと、whateverPressed(e)は、ユーザーがキーを離すまで何度も呼び出されます。

<body onLoad="Load()" onkeypress="Pressed(event)">
1
Garis M Suero