убрать задержку нажатия клавиш в javascript - PullRequest
24 голосов
/ 11 сентября 2010

У меня следующая проблема: я пытаюсь написать игру на 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);
    }

У кого-нибудь есть идеи ??

Ответы [ 7 ]

29 голосов
/ 11 сентября 2010

Если вы хотите, чтобы клавиша повторялась контролируемым образом, вам придется реализовать ее самостоятельно, так как события нажатия клавиши запускаются в зависимости от представления ОС о том, как клавиши должны повторяться.Это означает, что могут быть переменные начальные и последующие задержки, и удерживание двух клавиш одновременно приведет к повторению только одной из них.

Вам придется вести учет того, нажата ли каждая клавиша в данный момент, и игнорировать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);

Хотя большинство игр на основе экшена имеют фиксированный цикл основного кадра, с которым вы можете связать обработку клавиш вверх / вниз.

4 голосов
/ 11 сентября 2010

Я решил это так:

var pressedl = 0;
var pressedu = 0;
var pressedr = 0;
var pressedd = 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)
            pressedd = 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)
            pressedd = 0;
        //alert(cxc);
    }

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

2 голосов
/ 11 сентября 2010

Вы могли бы начать движение по улицам и только закончить его по ключу?

1 голос
/ 28 ноября 2012

Это почти то же самое, что отличный ответ от @ 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= {};
    };
};

У меня также есть план использовать setTimeout вместо setInterval по причинам, указанным в этом вопросе: setTimeout или setInterval?

Я обновлю этот ответ, как только исправлюсь и протестирую.

1 голос
/ 20 июня 2011

Я новичок в этом деле, но почему бы не объединить KeyDown с KeyUp?Я сейчас работаю над похожим проектом и, после проверки quirksmode , я собираюсь выяснить, как объединить два события так, чтобы все время между «Вниз» и «Вверх» реализовало желаемый эффект.

1 голос
/ 12 января 2011

Это решение Лукаса в более абстрактной версии:

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

Кажется, вы можете нажимать только 3 клавиши одновременно, к моему удивлению.

1 голос
/ 11 сентября 2010

Поскольку это событие должно переместить whatever из одной позиции в одну, почему бы вам не использовать событие onkeypress, поэтому, если пользовательская клавиша нажала клавишу up, whatever будетпродолжайте движение вверх, так как Pressed(e) будет вызываться много раз, пока пользователь не отпустит ключ.

<body onLoad="Load()" onkeypress="Pressed(event)">
...