Перекрывающиеся ключевые события

Я работаю над небольшим проектом HTML/JavaScript/CSS3 для развлечения. Я в основном пытаюсь сделать колесо, которое катится в окне браузера. Для управления колесом я использую события keyup и keydown для клавиш курсора (влево и вправо поворачивают колесо, а вверх и вниз катят его вперед или назад).

У меня это работает довольно хорошо до сих пор, но есть два серьезных сбоя. Скажем, я хочу повернуть колесо вперед и, не останавливаясь, повернуть его немного вправо, тогда я буду держать нажатой клавишу «вверх» и нажимать клавишу курсора «вправо». Когда я это делаю, в движении возникает пауза, прежде чем оно регистрирует оба события и продолжает движение.

Это одна из проблем, основная проблема в том, что после того, как я выполнил предыдущее действие, а затем колесо находится под желаемым углом, если я отпущу правую клавишу курсора, браузер зарегистрирует обе клавиши как отпущенные, и колесо вернется к стоять на месте. Вот как это выглядит на jsFiddle: http://jsfiddle.net/UKqwu/1/ . Я знаю, что код беспорядок, но это незавершенная работа / опыт обучения, и я программирую всего месяц или около того.

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


person jrl589    schedule 29.07.2012    source источник
comment
Но в jQuery вы можете использовать функцию привязки, я думаю, но не уверен, как это реализовать.   -  person Shawn31313    schedule 29.07.2012
comment
@ Shawn31313: я не думаю, что это что-то решит; это было бы просто ненужной оболочкой здесь. @ jrl589: Вы пробовали setInterval с move? Поскольку у вас есть объект ключевых флагов, простой его непрерывный запуск должен работать, хотя это может быть не очень эффективно.   -  person pimvdb    schedule 29.07.2012
comment
@ pimvdb setInterval? извините, если я немного туговат, но сегодня моя первая попытка использовать js, поэтому я еще не совсем знаком с библиотеками и функциями.   -  person jrl589    schedule 29.07.2012
comment
@ jrl589: Вот так: jsfiddle.net/UKqwu/2. По сути, вы выполняете move каждые 100 мс для обновления объекта в соответствии с текущим состоянием клавиш. Выполнение не зависит от нажатия клавиш; это всегда делается (поэтому он не блокируется, когда возникает проблема с перекрытием).   -  person pimvdb    schedule 29.07.2012
comment
@ pimvdb Я пытался использовать функцию setTimeout(), но либо она не сработала, либо я использовал ее не в надлежащем контексте.   -  person jrl589    schedule 29.07.2012
comment
@pimbdb: огромное спасибо за помощь, теперь мне просто нужно найти способ, как заставить его работать без сбоев с помощью функции setInterval.   -  person jrl589    schedule 29.07.2012
comment
Вы можете попробовать ускорить setInterval. 50 мс, казалось, работали довольно хорошо.   -  person Shawn31313    schedule 30.07.2012
comment
Мертвый код: for (var key in keys) {if (key == 1) {key = 1;}}   -  person Victor    schedule 01.08.2012


Ответы (3)


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

Если бы вы (в текстовом поле) удерживали нажатой кнопку «j», сначала появилась бы одна «j», а затем, после небольшой задержки, появилось бы много «j» «jjjjjjjjjjjjjjjjjjjj».

Это та же проблема, с которой вы столкнулись. Событие срабатывает один раз, ждет некоторое время, а затем срабатывает еще много раз.

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

Обработчик ключей будет выглядеть примерно так...

function KeyHandler() {
  this.left = false;
  this.right= false;
  ...
  function onKeyDown(e) {
    if (e.keyCode == 37) {
      this.left = true;
    }
    ...
  }
  function onKeyUp(e) {
    if (e.keyCode == 37) {
      this.left = false;
    }
    ...
  }
}

(вы бы прикрепили обработчик ключа к телу или любому элементу, который пожелаете)

У вашего руля будет функция обновления, которая выглядит как...

wheel.update = function() {
  // the wheel is turning left
  if (wheel.keyhandler.left) {
    // make the appropriate adjustments
  }
}

и тогда в игре было бы что-то вроде этого...

wheel = new Wheel;
setInterval(function() {
  wheel.update();
},100);

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

person zconnelly13    schedule 02.08.2012
comment
К вашему сведению: setInterval(func, interval) выполняет func каждые interval миллисекунды. Эта реализация должна быть намного более гладкой. - person Jesse Hallett; 07.08.2012

Вот фрагмент простой игры, которую я когда-то написал

//key codes
var KEY_LEFT = 37;
var KEY_RIGHT = 39;
var KEY_A = 65;
var KEY_D = 68;
var KEY_SPACE = 32;

var keys = {};

function onKeyDown(e)
{
    e = e || window.event;
    var key = window.event.keyCode || e.which; // ie

    keys[key] = true;
}

function onKeyUp(e)
{
    var key = window.event.keyCode || e.which; // ie

    delete keys[key];
}

Это отслеживает все текущие ключевые состояния. Тогда ваша игра «тикает» на setTimeout(), а не перемещается по ключевым событиям и проверяет соответствующие ключи.

function gameTick()
{
    // update paddle angles
if (keys[KEY_LEFT])
    {
        // move left
    }

if (keys[KEY_RIGHT])
    {
        // move right
    }
}

Вот игра;

person Chad Schouggins    schedule 31.07.2012

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

поместите эту строку в цикл по размеру e. это установит все нажатые клавиши как 1. в настоящее время он обнаруживает только одно нажатие клавиши и обрабатывает по одному за раз.

keys[e.keyCode] = 1;

почитай эту ветку и может найдешь то что тебе нужно. хотя это jquery, это может помочь концептуально. я также работаю над этим с помощью js... если появится что-то новое, поделитесь...

Обнаружение нескольких клавиш при нажатии одной клавиши в jQuery

ваш код и концепция круты, если вы действительно в программировании один месяц.

person Ashish Rana    schedule 06.08.2012