如何通过箭头键连续/平滑地移动元素

How to move an element via arrow keys continuously/smoothly?

本文关键字:平滑 移动 元素 连续 何通过      更新时间:2023-09-26

为了好玩,我正在用Javascipt制作一个原始游戏。我已经设置了一些功能,当按下箭头键时,可以移动我的角色,如下所示:

document.getElementById("character").style.top = 0;
document.getElementById("character").style.left = 0;
document.body.onkeydown = function() {
var e = event.keyCode,
    charTop = parseInt(document.getElementById("character").style.top),
    charLeft = parseInt(document.getElementById("character").style.left);
    if (e == 40) { //down function
        document.getElementById("character").style.top = (parseInt(document.getElementById("character").style.top)) + 10 + "px";
    } else if (e == 37) { //left function
        document.getElementById("character").style.left = (parseInt(document.getElementById("character").style.left)) - 10 + "px";
    } else if (e == 39) { //right function
        document.getElementById("character").style.left = (parseInt(document.getElementById("character").style.left)) + 10 + "px";
    } else if (e == 38) { //up function
        document.getElementById("character").style.top = (parseInt(document.getElementById("character").style.top)) - 10 + "px";
    }
}

我发现,如果你按住一个箭头键,它会移动一次,等待一秒钟,然后不断移动,直到你放手。我认为造成这种情况的原因是Windows的内置功能在指定的延迟后以控制面板中设置的速度重复按下按钮。

我更希望角色能立即、连续地移动,没有延迟。我不知道该怎么办。我还希望能够定义如果按钮仍然被按下,再次移动的速度(它一次移动十个像素,如果重复得太快,它会在屏幕上飞过)。

我知道Javascript并不是真正用于游戏编程的,但希望有人能想办法解决这个问题!谢谢

这是许多依赖键盘中断来控制游戏角色的编码语言中的标准问题,而不是JavaScript特有的问题。解决方法是将按键与角色的移动分开,而不是依赖键盘事件来重新绘制/更新游戏。相反,使用一个连续的游戏循环,这种循环可以而且经常不会做任何事情(每秒多次)—直到你的游戏发生变化。这似乎是一件奇怪的事情,但这是许多游戏的设计和构建方式;甚至在JavaScript中;)

/// store key codes and currently pressed ones
var keys = {};
    keys.LEFT = 37;
    keys.RIGHT = 39;
/// store reference to character's position and element
var character = {
  x: 100,
  y: 100,
  element: document.getElementById("character")
};
/// key detection (better to use addEventListener, but this will do)
document.body.onkeyup = 
document.body.onkeydown = function(e){
  var kc = e.keyCode || e.which;
  keys[kc] = e.type == 'keydown';
};
/// character movement update
var moveCharacter = function(dx, dy){
  character.x += dx||0;
  character.y += dy||0;
  character.element.style.left = character.x + 'px';
  character.element.style.top = character.y + 'px';
};
/// character control
var detectCharacterMovement = function(){
  if ( keys[keys.LEFT] ) {
    moveCharacter(-1);
  }
  if ( keys[keys.RIGHT] ) {
    moveCharacter(1);
  }
};
/// game loop
setInterval(function(){
  detectCharacterMovement();
}, 1000/24);

一个活生生的例子(也有上下移动):

    /// store key codes and currently pressed ones
    var keys = {};
        keys.UP = 38;
        keys.LEFT = 37;
        keys.RIGHT = 39;
        keys.DOWN = 40;
    /// store reference to character's position and element
    var character = {
      x: 100,
      y: 100,
      speedMultiplier: 2,
      element: document.getElementById("character")
    };
    /// key detection (better to use addEventListener, but this will do)
    document.body.onkeyup = 
    document.body.onkeydown = function(e){
      /// prevent default browser handling of keypresses
      if (e.preventDefault) { 
        e.preventDefault();
      }
      else {
        e.returnValue = false; 
      }
      var kc = e.keyCode || e.which;
      keys[kc] = e.type == 'keydown';
    };
    /// character movement update
    var moveCharacter = function(dx, dy){
      character.x += (dx||0) * character.speedMultiplier;
      character.y += (dy||0) * character.speedMultiplier;
      character.element.style.left = character.x + 'px';
      character.element.style.top = character.y + 'px';
    };
    /// character control
    var detectCharacterMovement = function(){
      if ( keys[keys.LEFT] ) {
        moveCharacter(-1, 0);
      }
      if ( keys[keys.RIGHT] ) {
        moveCharacter(1, 0);
      }
      if ( keys[keys.UP] ) {
        moveCharacter(0, -1);
      }
      if ( keys[keys.DOWN] ) {
        moveCharacter(0, 1);
      }
    };
    /// update current position on screen
    moveCharacter();
    /// game loop
    setInterval(function(){
      detectCharacterMovement();
    }, 1000/24);
#character {
    position: absolute;
    width: 42px;
    height: 42px;
    background: red;
    border-radius: 50%;
}
<div id="character"></div>

http://jsfiddle.net/7a106ck7/1/

以上只是基本内容,您可以进行一些优化。以上也不是控制游戏角色的全部和最终,可悲的是,浏览器中的键盘事件是不可预测的(与JavaScript无关),如果你开始尝试制作更复杂的控制系统,你会发现很多问题,即某些键不能同时按下而不会出现问题(尤其是CMD或CTRL等控制字符)。

有一天,如果JavaScript有一个Keyboard对象,它的行为就像上面的keys对象一样,那就太好了。这意味着您可以在任何时候测试当前按下的任何键的状态,而不必依赖事件模型。它可能会在未来某个未知的时刻发生,但我们必须拭目以待。

如果真的发生了,我想推荐一个功能:

Keyboard.isPressed(Keyboard.ANY)

这将有助于无数的游戏介绍/菜单屏幕(为什么我必须在看到菜单之前按下任何键?我们梦想着街机吗?)。更不用说,以上这些将帮助所有仍在等待他们认为缺失的钥匙存在的人。

尝试使用onkeyup而不是onkeydown,onkeyup在密钥释放后取值

 document.getElementById("character").style.top = 0;
 document.getElementById("character").style.left = 0;
document.body.onkeyup = function() {
var e = event.keyCode,
    charTop = parseInt(document.getElementById("character").style.top),
    charLeft = parseInt(document.getElementById("character").style.left);
    if (e == 40) { //down function
        document.getElementById("character").style.top = (parseInt(document.getElementById("character").style.top)) + 10 + "px";
    } else if (e == 37) { //left function
        document.getElementById("character").style.left = (parseInt(document.getElementById("character").style.left)) - 10 + "px";
    } else if (e == 39) { //right function
        document.getElementById("character").style.left = (parseInt(document.getElementById("character").style.left)) + 10 + "px";
    } else if (e == 38) { //up function
        document.getElementById("character").style.top = (parseInt(document.getElementById("character").style.top)) - 10 + "px";
    }
}

创建一个全局HOP变量,该变量将定义角色移动的速度。

在按下键时创建一个:

var inter = setInterval(function(){
 //apply movements here
}, HOP);

然后在按下键时,您使用以下命令停止移动:

clearInterval(inter);

setInterval()将在每个HOP(以毫秒为单位)调用自己。这将循环,直到您检测到用户已释放密钥。

为了确保不创建多个setIntervals,请确保全局初始化您的var inter = -1,并且每次清除它时都将其设置回-1。当检测到按键按下时,采用这种方式。。只需检查inter是否>-1。如果是,那就什么都不做。

的简单演示

HTML:

<div id="container"></div>

JS:

var container = document.getElementById('container');
var p = document.createElement('p');
var inter = -1;
var HOP = 50; //miliseconds
window.onkeydown = function(){
    if(inter == -1){
        inter = setInterval(function(){
            var p_temp = p.cloneNode();
            p_temp.innerHTML = "Key is down";
            container.appendChild(p_temp);
        }, HOP);
    }
};
window.onkeyup = function(){
    clearInterval(inter);
    inter = -1;
};