0

The example for this question is http://jsfiddle.net/4ac5u/

var x = 0;
var y = 0;
$(document).keydown(function(e){
    if (e.keyCode == 37) { 
       $("#left").css( "background-color", "red" );
       x = x-1;
       $("#ball").css( "margin-left", x*10 );
       return false;
    }
});
$(document).keyup(function(e){
    if (e.keyCode == 37) { 
       $("#left").css( "background-color", "#fff" );
       return false;
    }
});
$(document).keydown(function(e){
    if (e.keyCode == 38) { 
       $("#up").css( "background-color", "red" );
       y = y-1;
       $("#ball").css( "margin-top", y*10 );
       return false;
    }
});
$(document).keyup(function(e){
    if (e.keyCode == 38) { 
       $("#up").css( "background-color", "#fff" );
       return false;
    }
});
$(document).keydown(function(e){
    if (e.keyCode == 39) { 
       $("#right").css( "background-color", "red" );
       x = x+1;
       $("#ball").css( "margin-left", x*10 );
       return false;
    }
});
$(document).keyup(function(e){
    if (e.keyCode == 39) { 
       $("#right").css( "background-color", "#fff" );
       return false;
    }
});
$(document).keydown(function(e){
    if (e.keyCode == 40) { 
       $("#down").css( "background-color", "red" );
       y = y+1;
       $("#ball").css( "margin-top", y*10 );
       return false;
    }
});
$(document).keyup(function(e){
    if (e.keyCode == 40) { 
       $("#down").css( "background-color", "#fff" );
       return false;
    }
});

In this example I have different Jquery keydown listeners waiting for a specific key press, and on that keypress I want to move a ball in a certain direction (in this example using the css function to change the margin).

The issue is that you can only move in one direction at a time. Is it possible to have it so that if I have the down arrow and the right arrow down at the same time I move towards the bottom left part of the screen, not just right or down?

I have thought about possibly finding a way to alternate between them if both are pressed, but I'm not sure how that would work. Or if there is some way to do threading.

Also I'm not sure if there is a way to also make it not cancel out on pressing a new button while you are still holding the other down.

4 Answers4

1

Combine all of your keydowns and keyups into one function with multiple if statements. Check for combinations first, and then check for single arrow presses. That should resolve the issue.

If you want to support users being able to move the ball around fluidly, I'd look into the example given here: http://jsfiddle.net/kzXek/. This example includes handling pressed down arrow keys to provide fluid movement.

// Made by RobseRob.dk
// Please give credit.
// Vars which contains key state
var movLeft = 0;
var movRight = 0;
var movUp = 0;
var movDown = 0;

var score = 0;
$(function() {
    // Keydown listener
    $("body").keydown(function(e) {
        ek = e.keyCode;
        if (ek==37) movLeft=1;
        if (ek==39) movRight=1;
        if (ek==38) movUp=1;
        if (ek==40) movDown=1;
    });
    // Keyuo listener
    $("body").keyup(function(e) {
        ek = e.keyCode;
        if (ek==37) movLeft=0;
        if (ek==39) movRight=0;
        if (ek==38) movUp=0;
        if (ek==40) movDown=0;
    });
});
Ivan
  • 10,052
  • 12
  • 47
  • 78
1

Please take a look at this code:

var x = 0;
var y = 0;
var dirs = {
    left: false,
    top: false,
    right: false,
    bottom: false
};
$(document).keydown(function(e){
  switch (e.keyCode) {
    case 37: dirs.left = true; return false;
    case 38: dirs.top = true; return false;
    case 39: dirs.right = true; return false;
    case 40: dirs.bottom = true; return false;
  }
});
$(document).keyup(function(e){
  switch (e.keyCode) {
    case 37: dirs.left = false; return false;
    case 38: dirs.top = false; return false;
    case 39: dirs.right = false; return false;
    case 40: dirs.bottom = false; return false;
  } 
});

var checkLeft = function() {
  if (dirs.left) {
    $("#left").css( "background-color", "red" );
    x--;
  } else {
    $("#left").css( "background-color", "#fff" );
  }
}

var checkRight = function() {
  if (dirs.right) {
    $("#right").css( "background-color", "red" );
    x++;
  } else {
    $("#right").css( "background-color", "#fff" );
  }
}

var checkTop = function() {
  if (dirs.top) {
    $("#up").css( "background-color", "red" );
    y--;
  } else {
    $("#up").css( "background-color", "#fff" );
  }
}

var checkBottom = function() {
  if (dirs.bottom) {
    $("#down").css( "background-color", "red" );
    y++;
  } else {
    $("#down").css( "background-color", "#fff" );
  }
}

var moveBall = function() {
  $("#ball").css({
    "margin-left": x*10,
    "margin-top": y*10
  });
}

setInterval(function() {
  checkLeft();
  checkRight();
  checkTop();
  checkBottom();

  moveBall()
}, 50);

http://jsfiddle.net/26XWw/

Oleg
  • 22,300
  • 9
  • 68
  • 84
0

Create an Array of Booleans (left, right, up, down) and on a setInterval check which ones are set to true

Here would be your updated code:

var x = 0;
var y = 0;
var keysDown = [false, false, false, false];
$(document).keydown(function (e) {
    switch (e.keyCode) {
        case 37:
            keysDown[0] = true;
            break;
        case 38:
            keysDown[2] = true;
            break;
        case 39:
            keysDown[1] = true;
            break;
        case 40:
            keysDown[3] = true;
            break;
    }
});
$(document).keyup(function (e) {
    switch (e.keyCode) {
        case 37:
            keysDown[0] = false;
            $("#left").css("background-color", "#fff");
            break;

        case 38:
            keysDown[2] = false;
            $("#up").css("background-color", "#fff");
            break;

        case 39:
            keysDown[1] = false;
            $("#right").css("background-color", "#fff");
            break;

        case 40:
            keysDown[3] = false;
            $("#down").css("background-color", "#fff");
            break;

    }
});

function checkBallMoving()
{
    if (keysDown[0] === true) {
        $("#left").css("background-color", "red");
        x = x - 1;
        $("#ball").css("margin-left", x * 10);
    }
    if (keysDown[1] === true) {
        $("#right").css("background-color", "red");
        x = x + 1;
        $("#ball").css("margin-left", x * 10);
    }
    if (keysDown[2] === true) {
        $("#up").css("background-color", "red");
        y = y - 1;
        $("#ball").css("margin-top", y * 10);
    }
    if (keysDown[3] === true) {
        $("#down").css("background-color", "red");
        y = y + 1;
        $("#ball").css("margin-top", y * 10);
    }
}
setInterval(function () {
    checkBallMoving();
}, 100);

DEMO

Cilan
  • 13,101
  • 3
  • 34
  • 51
  • Interesting, I tried that out and it didn't seem to work. `$(document).keyup(function(e){ if (e.keyCode == 39 && e.keyCode == 40) { y = y+1; x = x+1; $("#ball").css( "margin-top", y*10 ); $("#ball").css( "margin-left", x*10 ); } });` – user2928768 Jan 06 '14 at 19:56
  • Put it on the `keydown` not just the `keyup` – Cilan Jan 06 '14 at 19:57
  • This is example is wrong on so many levels (no caching variables, no delegated events, using setInterval) and doesn't solve the problem at hand (I can press multiple keys in 500ms without a problem). Instead it makes it even more difficult to read, understand and debug! – nietonfir Jan 06 '14 at 20:35
  • Reducing the `setInterval` duration doesn't improve anything. Please look at the other answers for better solutions. – nietonfir Jan 07 '14 at 05:56
0

You can handle the keydowns in an array or object and then check for all the ones that were pressed:

Here you have:

Detect multiple keys on single keypress event in jQuery

Cheers

Community
  • 1
  • 1
Edgar Villegas Alvarado
  • 18,204
  • 2
  • 42
  • 61