Question

So I have a little square moving around a grid, but when I execute the onkeydown event my square moves very fast. I only want it to execute once every 10th of a second so that my little square doesn't run into a pair of scissors. But when I try a setTimeout function it only times out for the very first keydown, and then continues to executes fast and when you release the key it's still executing to catch up. This is very unsafe for my little square. Any help would be much appreciated.

Here is the code without the setTimeout function, only because I feel it's not the right way to go:

function checkArrowKeys(e){
    var arrs= [], key= window.event? event.keyCode: e.keyCode;
    arrs[37]= 'left';
    arrs[38]= 'up';
    arrs[39]= 'right';
    arrs[40]= 'down';
    if(arrs[key]){
        transition(arrs[key]);
    }
}
document.onkeydown=checkArrowKeys;
Was it helpful?

Solution

You could stop the execution of your transition by exiting the function if your preset delay hasn't occurred.

var bWait=false;
function checkArrowKeys(e){
    if (bWait) return;
    var arrs= [], key= window.event? event.keyCode: e.keyCode;
    arrs[37]= 'left';
    arrs[38]= 'up';
    arrs[39]= 'right';
    arrs[40]= 'down';
    if(arrs[key]){
        transition(arrs[key]);
    }
    bWait=true; //wait for 10 milliseconds
    window.setTimeout("bWait=false;",10);
}
document.onkeydown=checkArrowKeys;

What do you think?

OTHER TIPS

Keyboard response can turn out to be surprisingly complicated. Usually you don't want to pay attention to every keydown event that gets fired, because that depends on the user's keyboard and settings; e.g. one event fires initially then after a pause, a rapid stream are fired. There's also an issue of what to do when users holding down two keys at once.

The following code separates the keyboard response from the animation by having a separate update function. Upon a new arrow key being pressed the square initially moves 1 step (set to 5px), then after 100ms moves continuously until the key is released.

(Fiddle)

var directions = [],
    lastPressTime, stepped, ti, frameRate = 30,
    squareSpeed = 5, stepTime = 100;

function update() {
    var x, y, d = directions[directions.length - 1],
        square = document.getElementById('square');
    if (!d) {
        return;
    }
    if (new Date().getTime() < lastPressTime + stepTime) {
        if (stepped) { // already stepped and <100ms has passed
            return;    // so do nothing
        }
        else {
            stepped = true;
        }
    }
    x = square.offsetLeft;
    y = square.offsetTop;
    if (d == 'left') {
        x -= squareSpeed;
    }
    else if (d == 'right') {
        x += squareSpeed;
    }
    else if (d == 'up') {
        y -= squareSpeed;
    }
    else if (d == 'down') {
        y += squareSpeed;
    }
    square.style.left = x + 'px';
    square.style.top = y + 'px';
}
function checkArrowKeys(e) {
    var arrs = [],
        key = window.event ? event.keyCode : e.keyCode;
    arrs[37] = 'left';
    arrs[38] = 'up';
    arrs[39] = 'right';
    arrs[40] = 'down';
    if (arrs[key]) {
        return arrs[key];
    }
}
document.onkeydown = function(e) {
    var d = checkArrowKeys(e);
    if (d) {
        // Key not already pressed; add it to array 
        // of directions and step forward
        if (directions.indexOf(d) === -1) {
            directions.push(d);
            lastPressTime = new Date().getTime();
            stepped = false;
        }
        if (!ti) {
            ti = setInterval(update, 1000 / frameRate);
        }
    }
};

document.onkeyup = function(e) {
    var d = checkArrowKeys(e),
        i;
    if (d) {
        i = directions.indexOf(d);
        // remove this direction from the array of directions
        if (i > -1) {
            directions = 
                directions.slice(0, i).concat(directions.slice(i + 1));
        }
        // if no keys are down then stop updating
        if (directions.length === 0) {
            clearInterval(ti);
            ti = null;
        }
    }
};
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top