如何防止Javascript中的多次按键

时间:2019-04-18 18:49:06

标签: javascript html5-canvas

我是JS的初学者,目前正在开发一个游戏(在我的情况下是Snake游戏)的项目。一切都进行得很好,除非我立即快速按下多个键,否则Snake会死掉,因为(我认为)这是碰撞。这就是为什么我想以某种方式禁用多个按键,以尝试解决问题的原因。 我的代码:

var Snake = function()
{
  //this is the direction table; UP, RIGHT, DOWN, LEFT
  this.directions = [[0, -1], [1, 0], [0, 1], [-1, 0]];
}

function onKeyDown(event)
{
  if (gameover)
    tryNewGame();
  else 
  {
    if (event.keyCode == 37 || event.keyCode == 65)
    {
      if (snake.direction != 1)  
        snake.direction = 3;
    } 
    else if (event.keyCode == 38 || event.keyCode == 87) 
    {
      if (snake.direction != 2) 
        snake.direction = 0;
    } 
    else if (event.keyCode == 39 || event.keyCode == 68) 
    {
      if (snake.direction != 3) 
        snake.direction = 1;
    } 
    else if (event.keyCode == 40 || event.keyCode == 83) 
    {
      if (snake.direction != 0)
        snake.direction = 2;
    }   
  }
}

4 个答案:

答案 0 :(得分:0)

您可以在按键功能上使用setTimeout函数,例如

编辑:2000ms只是示例时间。您可以将其设置为每1/2秒500ms,或者您想要的任何其他数量的ms

setTimeout(
function onKeyDown(event)
{
  if (gameover)
    tryNewGame();
  else 
  {
    if (event.keyCode == 37 || event.keyCode == 65)
    {
      if (snake.direction != 1)  
        snake.direction = 3;
    } 
    else if (event.keyCode == 38 || event.keyCode == 87) 
    {
      if (snake.direction != 2) 
        snake.direction = 0;
    } 
    else if (event.keyCode == 39 || event.keyCode == 68) 
    {
      if (snake.direction != 3) 
        snake.direction = 1;
    } 
    else if (event.keyCode == 40 || event.keyCode == 83) 
    {
      if (snake.direction != 0)
        snake.direction = 2;
    }   
  }
},
2000ms
);

答案 1 :(得分:0)

对于这种用例,我总是推荐去抖动节流函数。放手,那是最好的。

Lodash对_.debounce_.throttle都有不错的实现。另外,请确保您已阅读this article,以完全理解这些概念。

基本思路是在第一次调用后,在短时间内“冻结”事件处理程序。它仍然被调用并接收事件,只是没有任何作用。

答案 2 :(得分:0)

问题可能是蛇的形状更新之前方向改变了两次,因此实际上忽略了这两个方向改变中的第一个。

克服此问题的一种方法是将方向变化缓冲在队列中(实现为数组)。

因此,在关键事件处理程序中,您不会这样做:

if (snake.direction != 1)  
    snake.direction = 3;

但相反:

if ((snake.queue.length ? snake.queue[0] : snake.direction) != 1) 
    snake.queue.unshift(3);

此队列应在Snake构造函数中初始化:

this.queue = [];

然后,当您以一定的时间间隔更新蛇的位置时,如果其中有东西,您将消耗

if (snake.queue.length)
    snake.direction = snake.queue.pop();
// Now apply this direction:
//   ... this would be code you already have...

您可以为此队列设置一个最大值,因为如果用户持续按下按键的速度比蛇更新要快,它将变得很尴尬。

答案 3 :(得分:0)

如此处所述,限制事件将很好地进行。这是一个可以用作调节器的简单类:

class CooldownTimer {
  constructor(time) {
    this.cooldownTimeout = null
    this.cooldownTime = time
    this.startedAt = null
  }

  isReady = () => {
    return !this.cooldownTimeout
  }

  start = () => {
    if (!this.cooldownTimeout) {
      clearTimeout(this.cooldownTimeout)
    }

    this.startedAt = Date.now()
    this.cooldownTimeout = setTimeout(() => {
      this.cooldownTimeout = null
    }, this.cooldownTime)
  }
}

您必须在某个地方(可能是您绑定事件的地方)定义一个CooldownTimer:

let keyPressCooldown = new CooldownTimer(200)

然后您可以在事件代码中使用它:

function onKeyPress(event) {
  if (keyPressCooldown.isReady()) {
    console.log('key pressed')
    keyPressCooldown.start() // Do not forget to start the cooldown here
  }
}