即使按下其他按钮,也会继续进行keydown事件

时间:2013-12-27 18:29:04

标签: javascript canvas javascript-events keyboard-events

让我们说我们有一个可以在屏幕左右移动的球。当你点击空格时,球应该跳跃。

我让球在画布上左右移动。然而,当球向左移动(例如)并且我在任何东西之前击中空格键时,球停止向左移动。

到目前为止查看my example

我使用KeyboardJS库来处理我的关键事件:

KeyboardJS.on("left", function () {
    cc();
    x -= xv;
    if (x < r) {
        circle(x + width, y, r);
        if (x + width <= width - r) {
            x = x + width;
        }
    }
    circle(x, y, r);
});

KeyboardJS.on("space", null, function () {
    console.log("space!");
});

我怎么能让这种行为停止,这样当空格键被击中时,球会跳起来,但同时仍然向左移动?

4 个答案:

答案 0 :(得分:2)

问题是,如果在按下第一个键后按另一个键,它将触发该事件,并停止触发另一个keydown事件。这可以在这个简化的例子中看到:

addEventListener('keydown',function(e) {console.log(e.keyCode, e.keyIdentifier)});

如果您运行该脚本,然后按向左然后向上,它将首先显示37 Left一次,然后它将显示32 U+0020一次并停止记录左侧键盘。

这就是浏览器(以及大多数其他基本程序)的工作原理。您可以尝试在例如记事本中执行相同的操作,如果先按A键,然后按空格键,它将停止添加更多的As。这也意味着您不能依赖关键事件(或关键事件库)来为您执行此操作。

你可以做的是制作一个包含所有按键的全局对象。例如:

window.KeysDown = {
    37: false, //Left
    39: false, //Right
    38: false, //Up
    40: false, //Down
    32: false, //Space
};

addEventListener('keydown', function(e) {
     var keyCode = e.keyCode||e.charCode||e.which;
     if (keyCode == 32 && !window.KeysDown[keyCode])
         onSpace();//This will only run when the spacebar is first pressed down.
     if (window.KeysDown.hasOwnProperty(keyCode))
         window.KeysDown[keyCode] = true;
});
addEventListener('keyup', function(e) {
     var keyCode = e.keyCode||e.charCode||e.which;
     if (window.KeysDown.hasOwnProperty(keyCode)) window.KeysDown[keyCode] = false;
});

var interval = setInterval(function() {
    for (var i in window.KeysDown) {
        if (window.KeysDown[i]) switch (i+'') {
            case '37': onLeft(); break;
            //case '38': window.KeysDown[i] && onUp(); break;
            case '39': onRight(); break;
            //case '40': window.KeysDown[i] && onDown(); break;
        }
    }
}, 50);

语法window.KeysDown[i] && onLeft()只会导致onLeft函数在window.KeysDown[i]为真时运行。我希望这个解决方案适合你。

编辑:我已将代码更改为工作代码。我也做了a JSFiddle that demonstrates this。我之前的代码中的问题是显然交换机不能很好地处理整数值,所以我需要将i转换为字符串。

编辑:我还在脚本中添加了一个额外的部分,使onSpace函数仅在首次按下空格键时运行,并且不会运行再次,直到空格键被释放并再次按下。我还updated my JSFiddle要包含这些更改。

答案 1 :(得分:2)

一个想法增加了其他人的好主意:

将用户输入与绘图分开。

<强>键盘输入:

如果您遇到KeyboardJS问题,请查看Keydrown:http://jeremyckahn.github.io/keydrown/

捕捉关键时不要做任何绘图......只需捕捉用户输入他们希望圆圈移动的方向。

设置“方向”变量以保存用户按[左]或[右]的次数:

var direction=0;  

按[左]时:

direction--; 

按[右]时:

direction++;

方向是净数。因此,如果用户按住左键20次,右键按下15次,方向将为-5(-20 + 15)。

设置“高度”变量以保存用户按[空格]的次数:

var altitude=0;

按[空格]时:

altitude-=10;

海拔高度也是净值

<强>绘制:

在单独的动画循环中完成所有绘图。而不是使用javascript的setInterval,使用新的和改进的创建imation循环的方式 - requestAnimationFrame

// set the starting circle positions 

var currentX=canvas.width;
var currentY=canvas.height-r;

function animate(){

    // even as we're executing this current animation loop
    // request another loop for next time

    requestAnimationFrame(animate);

    // change the currentX position by the accumulated direction

    currentX+=direction;
    direction=0;

    // change the currentY position by the accumulated altitude

    currentY+=altitude;
    altitude=0;

    // draw the circle at its current position

    cc();

    circle(currentX,currentY,r);

    // apply gravity to the circle
    // to make it fall if its in the air

    if(currentY<canvas.height-r){
        currentY++;
    }

}

祝你的项目好运!

答案 2 :(得分:1)

我会创建一个主函数,它以固定的间隔运行,每次运行时,它会根据当前关键的内容更新圆的位置。

主要功能可以这样做:

var keyDown = {};

function mainLoop() {
    cc();

    //pseudo code
    if (keyDown["left"]) {
        x -= 5;
    }
    if(keyDown["space"]) {
        y -= 10;
    }

    // redraw circle at new location
    circle(x,y,r);
}

setInterval(mainLoop, 30) //sets the function to be called every 30 milliseconds

// key event handler, first function handles the keydown, second function handles keyup
KeyboardJS.on("left", function() {
    keyDown["left"] = true;
}, function() {
    keyDown["left"] = false;
});

使用此示例,如果用户在mainLoop函数运行时按下了左箭头键和空格键,则圆圈将向左移动5个像素,向上移动10个像素。

答案 3 :(得分:1)

jsFiddle Demo

您将不得不为此手动创建框架。 KeyboardJS只是没有削减它。我想我有点把它放在这里。它使用Action“类”和关键事件触发器。

行动“类”

function Actions(){
 this.count = 0;
 this.running = {};
 this.interval = undefined;
}

Actions.prototype.start = function(action){
  if( typeof(this.running[action]) == "undefined"){
     this[action]();
     this.running[action] = action;
     this.count++;
  }
  var me = this;
  if( typeof(this.interval) == "undefined"){
     this.interval = setInterval(function(){
      for( var act in me.running ){
       me[act]();
      }
     },50);
  }
};

Actions.prototype.stop = function(action){
  this.running[action] = void 0;
  delete this.running[action];
  this.count--;
  if( this.count == 0 ){
   clearInterval(this.interval);
   this.interval = void 0;
  };
};

Actions.prototype.left = function(){
 cc();
 x -= xv;
 if (x < r) {
    circle(x + width, y, r);
    if (x + width <= width - r) {
        x = x + width;
    }
 }
 circle(x, y, r);
};
Actions.prototype.right = function(){
 cc();
 x += xv;
 if (x >= width - r) {
    circle((x - r) - (width - r), y, r);
    if ((x - r) - (width - r) > r) {
        x = (x - r) - (width - r);
    }
 }
 circle(x, y, r);
};
Actions.prototype.space = function(){
 cc();
 y -= yv;
 circle(x, y, r);
};

关键事件触发器

document.onkeydown = checkKeyDown;
function checkKeyDown(e) {
 e = e || window.event;
 if (e.keyCode == '37') {
    // left arrow
    actions.start("left");
 }
 if (e.keyCode == '39') {
    // right arrow
    actions.start("right");
 }
 if (e.keyCode == '32') {
    // space bar
    actions.start("space");
 }
}
document.onkeyup = checkKeyUp;
function checkKeyUp(e) {
 e = e || window.event;

 if (e.keyCode == '37') {
    // left arrow
    actions.stop("left");
 }
 if (e.keyCode == '39') {
    // right arrow
    actions.stop("right");
 }
 if (e.keyCode == '32') {
    // space bar
    actions.stop("space");
 }
}