Как я могу сделать переход коробки только для горизонтального и вертикального? - PullRequest
1 голос
/ 21 марта 2020

Я пытаюсь сделать так, чтобы коробка двигалась по горизонтали и вертикали на стрелки пресса. Но когда я нажимаю, например, up arrow и right arrow, он идет по диагонали. Вот мой кодовый блок

.box {
  background-color: gray;
  height: 100px;
  width: 100px;
  transition: margin 0.5s cubic-bezier(0, .7, 0, 1);
}
const box = document.getElementsByClassName('box')[0];

document.addEventListener('keydown', function({keyCode, which}) {
  const keycode = keyCode ? keyCode : which,
        startValue = '0px',
        shiftValue = '400px';

  console.log(box.style.marginLeft, box.style.marginTop)
  switch(keycode) {
    case(40):
      box.style.marginTop = shiftValue;
      break;
    case(39):
      box.style.marginLeft = shiftValue;
      break;
    case(38):
      box.style.marginTop = startValue;
      break;
    case(37):
      box.style.marginLeft = startValue;
      break;
  }
});

Ответы [ 4 ]

0 голосов
/ 22 марта 2020

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

.box {
  background-color: gray;
  height: 100px;
  width: 100px;
}

.animation {
  transition: margin 0.5s cubic-bezier(0, .7, 0, 1);
}
const box = document.getElementsByClassName('box')[0];
let prevTime = 0;

document.addEventListener('keydown', function({keyCode, which}) {
  const keycode = keyCode ? keyCode : which,
        startValue = '0px',
        shiftValue = '400px',
        currentTime = Date.now();
  let diff = 0;

  diff = currentTime - prevTime;

  if (diff > 500) {
    box.classList.add('animation');
  } else {
    box.classList.remove('animation');
  }

  switch(keycode) {
    case(40):
      box.style.marginTop = shiftValue;
      break;
    case(39):
      box.style.marginLeft = shiftValue;
      break;
    case(38):
      box.style.marginTop = startValue;
      break;
    case(37):
      box.style.marginLeft = startValue;
      break;
  }

  prevTime = currentTime;
});
0 голосов
/ 21 марта 2020

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

const box = document.getElementsByClassName('box')[0];
let pressedKeys = [];
let timeoutHandler = -1;

document.addEventListener('keydown', function({keyCode, which}) {
  // As soon as the user presses a key we will clear the time out
  clearTimeout(timeoutHandler);

  const keycode = keyCode ? keyCode : which,
    startValue = '0px',
    shiftValue = '400px';

  pressedKeys.push(keycode);

  // register the timeout to a variable in order for this function 
  // only run once every x second. This implementation is also 
  // known as 'debounce function to poor people'
  timeoutHandler = setTimeout(() => {
    pressedKeys.forEach((key, index) => {
      // The animation time for each key pressed will be incremental
      // which means the second key pressed will have an animation delay
      // higher than the first one
      const timeoutSeconds = index === 0 ? 1 : index + (index * 100);
      setTimeout(() => {
        switch(key) {
          case(40):
            box.style.marginTop = shiftValue;
            break;
          case(39):
            box.style.marginLeft = shiftValue;
            break;
          case(38):
            box.style.marginTop = startValue;
            break;
          case(37):
            box.style.marginLeft = startValue;
            break;
        }
      }, timeoutSeconds)
    });

    pressedKeys = [];
  }, 100)
});

0 голосов
/ 22 марта 2020

Одно из возможных решений: вы можете отслеживать, какие ходы были запрошены, и ждать, пока не завершится предыдущий ход. Пример:

const box = document.getElementsByClassName('box')[0];

const startValue = '0px';
const shiftValue = '400px';

function moveDown() {
  // The move* functions only perform the move if is valid - i.e., 
  // if it would actually cause a visible change.
  if (box.style.marginTop !== shiftValue) {
    box.style.marginTop = shiftValue;
    return true;
  }
  // The move* functions return true iff the move was made.
  return false;
}

function moveRight() {
  if (box.style.marginLeft !== shiftValue) {
    box.style.marginLeft = shiftValue;
    return true;
  }
  return false;
}

function moveUp() {
  if (box.style.marginTop !== startValue) {
    box.style.marginTop = startValue;
    return true;
  }
  return false;
}

function moveLeft() {
  if (box.style.marginLeft !== startValue) {
    box.style.marginLeft = startValue;
    return true;
  }
  return false;
}

const moves = [];
let timeOfLastMoveInMilliseconds = null;
const animationDurationInSeconds = 0.5; // should match css transition duration
const animationDurationInMilliseconds = animationDurationInSeconds * 1000; 

function onFrame() {
  if (!timeOfLastMoveInMilliseconds) {
    timeOfLastMoveInMilliseconds = performance.now();
  }
  const timeSinceLastMove = performance.now() - timeOfLastMoveInMilliseconds;
  if (moves.length > 0 && timeSinceLastMove >= animationDurationInMilliseconds) {
    const wasMoved = moves.pop()();
    if (wasMoved) {
      timeOfLastMoveInMilliseconds = performance.now();
    }
  }
  window.requestAnimationFrame(onFrame);
}
window.requestAnimationFrame(onFrame);

document.addEventListener('keydown', function({keyCode, which}) {
  const keycode = keyCode ? keyCode : which;
  switch(keycode) {
    case(40):
      moves.unshift(moveDown);
      break;
    case(39):
      moves.unshift(moveRight);
      break;
    case(38):
      moves.unshift(moveUp);
      break;
    case(37):
      moves.unshift(moveLeft);
      break;
  }
});

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

0 голосов
/ 21 марта 2020

Попробуйте следующее:

const box = document.getElementsByClassName('box')[0];

let moving = false;

document.addEventListener('keydown', function({keyCode, which}) {
  const keycode = keyCode ? keyCode : which,
        startValue = '0px',
        shiftValue = '400px';

  console.log(box.style.marginLeft, box.style.marginTop)
  if (!moving && [37, 38, 39, 40].includes(keycode)){
      switch(keycode) {
        case(40):
          box.style.marginTop = shiftValue;
          break;
        case(39):
          box.style.marginLeft = shiftValue;
          break;
        case(38):
          box.style.marginTop = startValue;
          break;
        case(37):
          box.style.marginLeft = startValue;
          break;
      }
      moving = true;
      window.setTimeout(() => moving = false, 400); // Not 500, because visually it is very slow towards the end anyway.
  }
});
...