Сделайте так, чтобы события onkeydown происходили только один раз для определенных ключей - PullRequest
0 голосов
/ 17 января 2019

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

    var shouldHandleKeyDown = true;
    document.onkeydown = function(){
      if (!shouldHandleKeyDown) return;
      shouldHandleKeyDown = false;
      // HANDLE KEY DOWN HERE
    }
    document.onkeyup = function(){
      shouldHandleKeyDown = true;
    }
})();

То, что я пытаюсь сделать, это:

Пользователь нажимает? Функция перемещения вперед происходит ОДИН РАЗ (даже если удерживать клавишу «вверх»)

Пользователь нажимает слева? Поворот влево происходит один раз и т. Д ....

Спасибо всем за любую помощь в этом.

РЕДАКТИРОВАТЬ ДЛЯ УТОЧНЕНИЯ:

Я пытаюсь создать сканер от первого лица в стиле старых названий, таких как Wizardry для NES. По сути, я хочу, чтобы каждое нажатие кнопки «вперед» двигало игрока вперед на один кадр. Если они нажимают влево, то игрок поворачивается влево на один кадр и т. Д. Если вы знакомы с играми, вы поймете, что я имею в виду.

Ответы [ 3 ]

0 голосов
/ 17 января 2019

Измените function() на function(e), и нажатая клавиша находится в e.key

(после фрагмента запуска нажмите на белый прямоугольник под кнопкой запуска и нажмите клавиши)

var shouldHandleKeyDown = true;
document.onkeydown = function(e) {
  if (!shouldHandleKeyDown) return;
  shouldHandleKeyDown = false;
  console.log(e.key);
      // HANDLE KEY DOWN HERE
}

document.onkeyup = function(){
  shouldHandleKeyDown = true;
}
0 голосов
/ 17 января 2019

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

Например, если необходимо контролировать постоянно обновляемую анимацию, то простые семафоры в словаре с {left: bool, right: bool, up: bool, down: bool} устанавливаются на true в keydown и на false в keyup , и этого достаточно для каждого кадра.

const directions = {
  up: false,
  right: false,
  down: false,
  left: false
};
onkeydown = e => {
  const key = e.key.replace('Arrow', '').toLowerCase();
  if(key in directions) {
    e.preventDefault();
    directions[key] = true;
  }
};
onkeyup = e => {
  const key = e.key.replace('Arrow', '').toLowerCase();
  if(key in directions) {
    e.preventDefault();
    directions[key] = false;
  }
};
const w = canvas.width = innerWidth;
const h = canvas.height = innerHeight;
const ctx = canvas.getContext('2d');
const character = {
  x: w/2,
  y: h/2,
  update: function() {
    const speed = 2;
    // this is where we will check our keyboard's status
    // we do it every frame
    let dir_x = 0,
      dir_y = 0;
    dir_x += directions.left ? -1 : 0;
    dir_x += directions.right ? 1 : 0;
    dir_y += directions.up ? -1 : 0;
    dir_y += directions.down ? 1 : 0;
    this.x += dir_x * speed;
    this.y += dir_y * speed;
  },
  draw: function() {
    ctx.fillRect(this.x - 20, this.y-20, 40, 40);
  }
};

function anim() {
  character.update();
  ctx.clearRect(0,0,w, h);
  character.draw();
  requestAnimationFrame(anim);
}
anim();
:root,body{margin:0px}
<canvas id="canvas"></canvas>

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

...
if(key in directions) {
  e.preventDefault();
  const changed = directions[key] !== true;
  directions[key] = true;
  if(changed) {
    triggerChange(key);
  }
}

Где triggerChange(key) - функция, готовая запустить ваше одиночное действие.

const directions = {
  up: false,
  right: false,
  down: false,
  left: false
};

function triggerChange(dir) {
  character.update();
}

onkeydown = e => {
  const key = e.key.replace('Arrow', '').toLowerCase();
  if (key in directions) {
    e.preventDefault();
    const changed = directions[key] !== true;
    directions[key] = true;
    if (changed) {
      triggerChange(key);
    }
  }
};
onkeyup = e => {
  const key = e.key.replace('Arrow', '').toLowerCase();
  if (key in directions) {
    e.preventDefault();
    directions[key] = false;
  }
};

const w = canvas.width = innerWidth;
const h = canvas.height = innerHeight;
const ctx = canvas.getContext('2d');
const character = {
  x: w / 2,
  y: h / 2,
  update: function() {
    const speed = 5;
    // this is where we will check our keyboard's status
    // we do it every frame
    let dir_x = 0,
      dir_y = 0;
    dir_x += directions.left ? -1 : 0;
    dir_x += directions.right ? 1 : 0;
    dir_y += directions.up ? -1 : 0;
    dir_y += directions.down ? 1 : 0;
    this.x += dir_x * speed;
    this.y += dir_y * speed;
  },
  draw: function() {
    ctx.fillRect(this.x - 20, this.y - 20, 40, 40);
  }
};

function anim() {
  // it is now keydown that is responsible for character.update()
  ctx.clearRect(0, 0, w, h);
  character.draw();
  requestAnimationFrame(anim);
}
anim();
:root,body{margin:0}
<canvas id="canvas"></canvas>
0 голосов
/ 17 января 2019

Я бы игнорировал события onkeydown и просто использовал onkeyup. Таким образом, событие запускается только после того, как пользователь поднимает палец, обеспечивая только одно движение за нажатие клавиши.

Чтобы определить, какая клавиша была нажата в вашем обработчике событий, передайте событие в вашу функцию. Здесь - это ссылка на значения ключей, поэтому вы можете сделать что-то вроде:

document.onkeyup = function(event) {
    var keycode = event.keyCode;

    if (keycode === 38) {
        moveUp();
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...