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

Eri*_*tor 3 javascript onkeydown

我正在与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";
    }

}
Run Code Online (Sandbox Code Playgroud)

它有效,但不是我喜欢的方式.我发现如果按住箭头键,它会移动一次,等待一秒钟,然后继续移动直到你松开.我认为造成这种情况的原因是Windows内置功能,在指定的延迟后以控制面板中设置的速度重复按下按钮.

我希望角色能够立即连续不断地移动.我不知道该如何解决这个问题.我还希望能够定义如果仍然按下按钮再次移动的速度(它一次移动十个像素,如果它重复得太快,它将飞过屏幕).

我知道Javascript并不是真正意义上的游戏编程,但希望有人可以想办法解决这个问题!谢谢!

Peb*_*bbl 6

这是许多依赖键盘中断来控制游戏角色的编码语言的标准问题,并不是特定于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);
Run Code Online (Sandbox Code Playgroud)

一个实例(也有上下移动):

    /// 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);
Run Code Online (Sandbox Code Playgroud)
#character {
    position: absolute;
    width: 42px;
    height: 42px;
    background: red;
    border-radius: 50%;
}
Run Code Online (Sandbox Code Playgroud)
<div id="character"></div>
Run Code Online (Sandbox Code Playgroud)

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

以上只是基础知识,您可以进行一些优化.上面也不是控制游戏角色的全部内容,遗憾的是,浏览器中的键盘事件是不可预测的(与JavaScript没有任何关系),如果有任何问题,你会发现你开始尝试制作更复杂的控制系统,即某些键不能同时按下而不会出现问题(尤其是控制字符,如CMD或CTRL).

有一天,如果JavaScript有一个Keyboard对象,那就像keys上面的对象一样.这意味着您可以随时测试当前按下的任何键的状态,而无需依赖事件模型.它可能发生在一些尚未知的未来点,但我们必须拭目以待.

如果确实发生了,我想建议一个功能:

Keyboard.isPressed(Keyboard.ANY)
Run Code Online (Sandbox Code Playgroud)

这将有助于无数的游戏介绍/菜单屏幕(为什么我必须在看到菜单之前按任意键?我们是否梦想街机?).更不用说上述内容将有助于所有那些仍在等待他们认为缺少密钥的人的存在.


Cha*_*ari 2

尝试使用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";
    }

}
Run Code Online (Sandbox Code Playgroud)