This question already has answers here:
move element with keypress (multiple)
                            
                                (3个答案)
                            
                    
                去年关闭。
        

    

我做了一个非常基本的演示,您按箭头键,正方形朝该方向移动。一个问题:当我第一次按下该键时,方块会移动一点,停顿一下,然后继续移动。如何摆脱或解决暂停问题?

码:



    var canvas = document.getElementById("canvas")
    var ctx = canvas.getContext('2d');
    var p1 = document.getElementById("p1");
    var keys = [];
    var x = 25
    var y = 25

    document.addEventListener("keydown", function(e) {
      keys[e.keyCode] = true;
      update();
    });

    document.addEventListener("keyup", function(e) {
      keys[e.keyCode] = false;
      update();
    });

    function update() {
      ctx.clearRect(0, 0, 400, 400)

      if(keys[40] == true) {
        y += 5
      }

      if(keys[38] == true) {
        y -= 5
      }

      if(keys[39] == true) {
        x += 5
      }

      if(keys[37] == true) {
        x -= 5
      }

      ctx.fillRect(x, y, 100, 100)

      console.log(keys);

      p1.innerText = "";

      for (i = 0; i < keys.length; i++) {
        if (keys[i]) {
          p1.innerText += i + " | ";
        }
      }
    }

    <canvas id='canvas' width='400' height='400'></canvas>
    <p id='p1'>testing</p>

最佳答案

发生这种情况是因为keydown事件是continuously fired at different intervals in different browsers

与其依赖浏览器不定期发送keydown,不如让自己的更新循环在60fps上运行,最好使用requestAnimationFrame,并且每帧根据所按下的键移动框。



var canvas = document.getElementById("canvas")
var ctx = canvas.getContext('2d');
var p1 = document.getElementById("p1");
var keys = [];
var x = 25
var y = 25

document.addEventListener("keydown", function(e) {
  e.preventDefault(); // make sure this doesn't scroll the window
  keys[e.keyCode] = true;
});

document.addEventListener("keyup", function(e) {
  keys[e.keyCode] = false;
});

function update() {
  //  Tell the browser to run again update when it is "free",
  // preferably at 60fps (actually your monitor's refresh rate)
  requestAnimationFrame(update);

  ctx.clearRect(0, 0, 400, 400)

  if(keys[40] == true) {
    y += 5
  }

  if(keys[38] == true) {
    y -= 5
  }

  if(keys[39] == true) {
    x += 5
  }

  if(keys[37] == true) {
    x -= 5
  }

  ctx.fillRect(x, y, 100, 100)

  p1.innerText = "";

  for (i = 0; i < keys.length; i++) {
    if (keys[i]) {
      p1.innerText += i + " | ";
    }
  }
}
update(); // Start running the loop at 60fps

<canvas id='canvas' width='400' height='400'></canvas>
<p id='p1'>testing</p>





请注意,框在给定时间内的移动距离取决于您的帧速率,因此,如果浏览器无法跟上60fps并仅在30fps上运行,则update只会被调用一半时间,因此该框将仅移动其在60fps处移动的一半距离。要了解有关动画和游戏更新循环的更多信息,我建议阅读此fix your timestep article

08-05 17:15