Как я могу получать события нажатия клавиш только один раз при каждом нажатии клавиши, даже если она нажата, с JavaScript? - PullRequest
0 голосов
/ 30 апреля 2020

Я делаю копию лягушки и хочу, чтобы лягушка двигалась только один раз, когда я нажимаю клавишу, в основном, чтобы предотвратить ее многократное перемещение, если удерживать клавишу нажатой.

Это соответствующая часть моего кода, которая обрабатывает событие keydown:

document.onkeydown = function(e) {
  var key = e.which || e.keyCode;

  if (key == 37){ frog.x = frog.x - 50; }
  if (key == 38){ frog.y = frog.y - 50; }
  if (key == 39){ frog.x = frog.x + 50; }
  if (key == 40){ frog.y = frog.y + 50; }
};

Обновление:

Я понял, что нет двигаться, удерживая клавиши, но теперь он не позволит мне двигаться сразу после того, как я перешел вправо, но сбросится, если я нажму другую кнопку, затем снова сделает то же самое:

const canvas = document.getElementById('canvas');
const c = canvas.getContext('2d');

canvas.height = window.innerHeight;
canvas.width = window.innerWidth;

let frog = {
  x: 0,
  y: 0,
  fw: 50,
  fh: 50,
  fmx: 0,
  fmy: 0,
};

let counter = 0;

function animate() {
    requestAnimationFrame(animate);
    
    // Clear previous scene:
    c.clearRect(0, 0, window.innerWidth, window.innerHeight);
    
    // Draw frog:
    c.fillStyle = '#000'
    c.fillRect(frog.x, frog.y, frog.fw, frog.fh);

    // Movement of the frog with keys:    
    document.onkeydown = function(e) {
      e = e || window.event;

      var key = e.which || e.keyCode;

      if (key == 65 && counter === 0) { frog.x = frog.x - 50, counter = 1 }
      if (key == 87 && counter === 0) { frog.y = frog.y - 50, counter = 1 }
      if (key == 68 && counter === 0) { frog.x = frog.x + 50, counter = 1 }
      if (key == 83 && counter === 0) { frog.y = frog.y + 50, counter = 1 }
    };

    document.onkeyup = function(e) {
      e = e || window.event;
      
      var key = e.which || e.keyCode;
      
      if (key == 65) { counter = 0 }
      if (key == 87) { counter = 0 }
      if (key == 68) { coutner = 0 } 
      if (key == 83) { counter = 0 }
    };
}

animate();
body {
  margin: 0;
}

#canvas {
  width: 100%;
  height: 100%;
}
<canvas id="canvas" />

Ответы [ 3 ]

0 голосов
/ 30 апреля 2020

Драйвер клавиатуры обычно запускает повторные нажатия клавиш, которые превращаются в отдельные события нажатия клавиш. Однако использование этой возможности, как правило, не то, что вам нужно для игр, поскольку задержка повторения раздражает, и как задержка повторения, так и начальная задержка являются пользовательскими настройками для всей ОС.

Вместо этого вы должны перехватить нажатие клавиши и события keyup. Когда клавиша нажимается, используйте setInterval или setTimeout для запуска таймера повторения и события. Когда клавиша поднимется, отмените таймер.

Я бы предпочел использовать setTimeout, если вы пропустите событие keyup из-за чего-то вроде того, что пользователь свернул свое окно с помощью мыши, удерживая клавишу нажатой.

0 голосов
/ 01 мая 2020

Я сделал то, что сказал один парень (кстати, отличный совет, я рад, что вы сказали мне), но когда я нажимаю стрелку, форма исчезает.


canvas.height = window.innerHeight;
canvas.width = window.innerWidth;

//variables

let frog = {
    x: 500,
    y: 500,
    fw: 50,
    fh: 50,
    fmx: 0,
    fmy: 0
}

//running it all

function animate(){
    requestAnimationFrame(animate)
    c.clearRect(0,0,innerWidth,innerHeight)

    //frog
    c.fillStyle = '#000'
    c.fillRect(frog.x,frog.y,frog.fw,frog.fh)


document.addEventListener('keydown', (e) => {
  e.preventDefault();

  if (e.repeat) return; // Do nothing

  const { key } = e;

  switch(key) {
    case 'ArrowUp':
      frog.y = frog.y - 50;
      break;

    case 'ArrowRight':
      frog.x = frog.x + 50;
      break;

    case 'ArrowDown':
      frog.y = frog.y + 50;
      break;

    case 'ArrowLeft':
      frog.x = frog.x - 50;
      break;  
  }
  if (key.startsWith('Arrow')) console.log(frog);
});

}

animate();
0 голосов
/ 30 апреля 2020

Вы можете использовать свойство KeyboardEvent.repeat (e.repeat), чтобы проверить, просто ли пользователь удерживает клавишу и ничего не делать в этом случае.

По сути, ваш код должно выглядеть так:

if (e.repeat) return; // Do nothing

const key = e.which || e.keyCode;

if (key === 37) frog.x = frog.x - 50;
else if (key === 38) frog.y = frog.y - 50;
else if (key === 39) frog.x = frog.x + 50;
else if (key === 40) frog.y = frog.y + 50;

Кроме того, KeyboardEvent.which и KeyboardEvent.keyCode устарели, как указано в документах:

устарел

Эта функция больше не рекомендуется. Хотя некоторые браузеры могут по-прежнему поддерживать его, он, возможно, уже удален из соответствующих веб-стандартов, может быть в процессе удаления или может храниться только в целях совместимости. Избегайте его использования и обновляйте существующий код, если это возможно; см. таблицу совместимости внизу этой страницы, чтобы принять решение. Имейте в виду, что эта функция может перестать работать в любой момент.

Вместо этого следует использовать KeyboardEvent.key:

const frog = { x: 500, y: 500 };

document.addEventListener('keydown', (e) => {
  e.preventDefault();
  
  if (e.repeat) return; // Do nothing

  const { key } = e;
  
  switch(key) {
    case 'ArrowUp':
      frog.y = frog.y - 50;
      break;
      
    case 'ArrowRight':
      frog.x = frog.x + 50;
      break;
      
    case 'ArrowDown':
      frog.y = frog.y + 50;
      break;
      
    case 'ArrowLeft':
      frog.x = frog.x - 50;
      break;  
  }
  
  if (key.startsWith('Arrow')) console.log(frog);
});
.as-console-wrapper {
  max-height: 100% !important;
}

Обратите внимание, что в обновленном коде вы не проверяете, что лягушка находится внутри холста, и вы определяете прослушиватель onkeydown внутри функции рендеринга. Вы должны проверить это и определить четного слушателя только один раз, снаружи:

const frog = {
  x: 0,
  y: 0,
  fw: 50,
  fh: 50,
};

const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
const MAX_X = window.innerWidth - frog.fw;
const MAX_Y = window.innerHeight - frog.fh;

canvas.width = window.innerWidth;
canvas.height = window.innerHeight;

function animate() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);

  ctx.fillStyle = '#000';
  ctx.fillRect(frog.x, frog.y, frog.fw, frog.fh);

  requestAnimationFrame(animate);
}

// This should be declared outside the rendering function:

document.onkeydown = (e) => {
  e.preventDefault();
  
  if (e.repeat) return; // Do nothing

  const { key } = e;
  
  switch(key) {
    case 'ArrowUp':
      frog.y = Math.max(0, frog.y - 50);
      break;
      
    case 'ArrowRight':
      frog.x = Math.min(frog.x + 50, MAX_X);
      break;
      
    case 'ArrowDown':
      frog.y = Math.min(frog.y + 50, MAX_Y);
      break;
      
    case 'ArrowLeft':
      frog.x = Math.max(0, frog.x - 50);
      break;  
  }
};
    
requestAnimationFrame(animate);
body {
  margin: 0;
}

#canvas {
  width: 100%;
  height: 100%;
}
<canvas id="canvas" />
...