简体   繁体   English

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

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

I'm making a primitive game with Javascipt for fun. 我正在与Javascipt进行一场原始游戏,以获得乐趣。 I have set up functions to move my character around when the arrow keys are pressed as follows: 按下箭头键时,我设置了移动角色的功能,如下所示:

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";
    }

}

and it works, but not the way I'd like it to. 它有效,但不是我喜欢的方式。 I find that if you hold down an arrow key, it will move once, wait a second, then continuously move until you let go. 我发现如果按住箭头键,它会移动一次,等待一秒钟,然后继续移动直到你松开。 I think what is causing this is Windows' built in function to repeat a pressed button at a speed set in Control Panel after a specified delay. 我认为造成这种情况的原因是Windows内置功能,在指定的延迟后以控制面板中设置的速度重复按下按钮。

I would prefer that the character move immediately and continuously without the delay. 我希望角色能够立即连续不断地移动。 I am not sure how to go about this. 我不知道该如何解决这个问题。 I'd also like to be able to define how quickly to move again if the button is still pressed (it moves ten pixels at a time, and if it repeated too quickly it would fly across the screen). 我还希望能够定义如果仍然按下按钮再次移动的速度(它一次移动十个像素,如果它重复得太快,它将飞过屏幕)。

I know that Javascript is not really meant for game programming, but hopefully someone can think of a way around this! 我知道Javascript并不是真正意义上的游戏编程,但希望有人可以想办法解决这个问题! Thanks! 谢谢!

This is a standard issue in lots of coding languages that rely on keyboard interrupts to control game characters, and isn't particular to JavaScript. 这是许多编码语言中的标准问题,这些编码语言依赖于键盘中断来控制游戏角色,而不是JavaScript特有的。 The way around this is to trap the keys separately from your character's movement, and not rely on the keyboard event to redraw/update your game. 解决这个问题的方法是将键与角色的移动分开捕获,而不是依赖键盘事件来重绘/更新游戏。 Instead use a continual game loop that can, and will quite often, do nothing (many times a second) — until something in your game changes. 相反,使用一个连续的游戏循环,它可以并且经常不做任何事情(很多次一秒) - 直到游戏中的某些内容发生变化。 Which seems a strange thing to do, but it is the way that many games are designed and built — even in 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);

A live example (also with up and down movement): 一个实例(也有上下移动):

  /// 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/ http://jsfiddle.net/7a106ck7/1/

The above is just the basics, there are a number of optimisations you can make. 以上只是基础知识,您可以进行一些优化。 Nor is the above the be-all-and-end-all of controlling a game character, as sadly, keyboard events in browsers are rather unpredictable (has nothing really to do with JavaScript) and there are a number of issues you will find if you start trying to make more complicated control systems ie certain keys cannot be pressed simultaneously without problems arising (especially control characters like CMD or CTRL). 上面也不是控制游戏角色的全部内容,遗憾的是,浏览器中的键盘事件是不可预测的(与JavaScript没有任何关系),如果有任何问题,你会发现你开始尝试制作更复杂的控制系统,即某些键不能同时按下而不会出现问题(尤其是控制字符,如CMD或CTRL)。

One day it would be great if JavaScript had a Keyboard object, one which behaved just as the keys object above. 有一天,如果JavaScript有一个Keyboard对象,那就像上面的keys对象一样。 Meaning you can test for the status of any key currently pressed, at any time, without having to rely on an event model. 这意味着您可以随时测试当前按下的任何键的状态,而无需依赖事件模型。 It may happen at some yet-unknown-future-point, but we'll have to wait and see. 它可能发生在一些尚未知的未来点,但我们必须拭目以待。

If it does happen, I'd like to suggest a feature: 如果确实发生了,我想建议一个功能:

Keyboard.isPressed(Keyboard.ANY)

This would help in an untold number of game intro/menu screens (why do I have to press any key before I see the menu? Are we dreaming of arcade machines?). 这将有助于无数的游戏介绍/菜单屏幕(为什么我必须在看到菜单之前按任意键?我们是否梦想街机?)。 Not to mention the above would help out all those still waiting for the existence of what they deem a missing key. 更不用说上述内容将有助于所有那些仍在等待他们认为缺少密钥的人的存在。

Try using onkeyup instead of onkeydown, onkeyup takes the value after the key is released 尝试使用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";
    }

}

Create a global HOP variable which will define how fast your character moves. 创建一个全局HOP变量,用于定义角色移动的速度。

onkeydown you create a: onkeydown你创建一个:

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

Then on keyup you stop the movement with: 然后在keyup上停止运动:

clearInterval(inter);

The setInterval() will call itself every HOP ( which is in milliseconds ). setInterval()将每个HOP (以毫秒为单位)调用自身。 This will loop till you detect that the user has released the key. 这将循环,直到您检测到用户已释放密钥。

To make sure that you don't create multiple setIntervals make sure you initialize globally your var inter = -1 and everytime you clear it you set it back to -1 . 要确保不创建多个setIntervals,请确保全局初始化 var inter = -1并且每次清除它时都将其设置回-1 This way when a keydown is detected.. just check to see if inter is > -1 . 这样,当检测到keydown时,只需检查inter是否> -1 If it is, then do nothing. 如果是,那就什么都不做。

Simple demo here 这里简单的演示

HTML: HTML:

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

JS: 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;
};

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM