即使按下附加按钮也继续按下键事件

问题描述 投票:2回答:4

假设我们有一个可以在屏幕周围左右移动的球。当您单击空格时,球应该跳。

我让球在画布上左右移动。但是,当球向左移动(例如)并且我在碰到空格键之前,球就停止向左移动。

迄今签出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!");
});

我如何才能停止这种行为,以便在按下空格键时,球跳起来,但同时仍然向左移动?

javascript canvas dom-events keyboard-events
4个回答
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,而是使用经过改进的新方法来创建模仿循环-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
投票

问题是,如果在按第一个键后再按另一个键,它将触发该事件,并停止触发另一个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为true时才使window.KeysDown[i]函数运行。我希望这个解决方案对您有用。

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

EDIT:我还向脚本添加了一个额外的部分,使onSpace函数仅在首次按下空格键时运行,因此直到释放空格键后它才再次运行然后再按一次我也updated my JSFiddle包含了这些更改。


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个像素。


1
投票

[jsFiddle Demo] >>

您将必须为此手动创建一个框架。 KeyboardJS只是没有削减它。我想我在这里设置了。它使用Action“类”以及关键事件触发器。

动作“类”

jsFiddle Demo

关键事件触发器

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);
};
© www.soinside.com 2019 - 2024. All rights reserved.