在javascript中使用键盘移动播放器



我正在制作一款网页游戏(不是使用webGL,而是使用html元素),我需要使用WaSD键移动角色。我尝试了这些方法:

  1. 使用的事件监听器keydown和keyup。问题是,当同时按下多个键时,它反应迟钝,不能很好地工作

  2. 使用setInterval(20ms)和事件监听器。在我的更强的笔记本电脑上,一切都很好,但我觉得它使用了大量的cpu,因为我的笔记本电脑开始听起来像一架飞机。在较弱的笔记本电脑上,它的工作效果不如第一个好,它是起伏不定的和滞后的

keyDict = {}
document.addEventListener('keydown', key => keyDict[key.code] = true);
document.addEventListener('keyup', key => keyDict[key.code] = false);
moveID = setInterval(move, 20)
function move()
{
if(!finished)
{
newDirs = [0,0]
//Left
if(keyDict.ArrowLeft == true) 
{
newDirs[0] -= 1;
}
//Right
if(keyDict.ArrowRight == true) 
{
newDirs[0] += 1;
}
//Up
if(keyDict.ArrowUp == true) 
{
newDirs[1] -= 1;
}
//Down
if(keyDict.ArrowDown == true) 
{
newDirs[1] += 1;
}
map.updateDir(newDirs); 
}
}
  1. 使用requestAnimationFrame和事件监听器。在性能更强的笔记本电脑上,它看起来使用144fps,甚至更流畅,但有时它甚至对我的控制没有反应。我的笔记本电脑仍然发出声音,因为它工作太辛苦了
keyDict = {}
document.addEventListener('keydown', key => keyDict[key.code] = true);
document.addEventListener('keyup', key => keyDict[key.code] = false);
requestAnimationsFrame(move)
function move()
{
same code...
requestAnimationFrame(move)
}

我想让它反应灵敏,非常流畅,我知道有办法,但不知道怎么做。这方面的例子是鼠标,你的笔记本电脑不会因为滚动而工作(并且,例如,用鼠标移动谷歌地图是平滑的,并且不会占用cpu太多)。

不要使用20ms的间隔。
根据关键事件将玩家移动到requestAnimationFrame中。代码被按下并在keyDict对象中保存真值:

const keyDict = {};
const Player = {
el: document.querySelector("#player"),
x: 200,
y: 100,
speed: 2,
move() {
this.el.style.transform = `translate(${this.x}px, ${this.y}px)`;
}
};
const updateKeyDict = (ev) => {
const k = ev.code;
if (/^Arroww+/.test(k)) { // If is arrow
ev.preventDefault();
keyDict[k] = ev.type === "keydown"; // set boolean true / false
}
};
const update = () => {
// Determine move distance to account diagonal move: 1/Math.sqrt(2) = ~0.707
let dist =
keyDict.ArrowUp   && (keyDict.ArrowLeft || keyDict.ArrowRight) ||
keyDict.ArrowDown && (keyDict.ArrowLeft || keyDict.ArrowRight) ? 0.707 : 1;

dist *= Player.speed;

if (keyDict.ArrowLeft)  Player.x -= dist;
if (keyDict.ArrowUp)    Player.y -= dist;
if (keyDict.ArrowRight) Player.x += dist;
if (keyDict.ArrowDown)  Player.y += dist;
Player.move();
}
document.addEventListener('keydown', updateKeyDict);
document.addEventListener('keyup', updateKeyDict);
(function engine() {
update();
window.requestAnimationFrame(engine);
}());
#player {
position: absolute;
left: 0;
top: 0;
width: 20px;
height: 20px;
background: #000;
border-radius: 50%;
}
Click here to focus, and use arrows
<div id="player"></div>

上面的例子使用Event.code来表示箭头,它给出的是"ArrowLeft/Up/Right/Down",但您可以相应地更改为使用"KeyW/A/S/D"

"WASD"键示例

const keyDict = {};
const Player = {
el: document.querySelector("#player"),
x: 200,
y: 100,
speed: 2,
move() {
this.el.style.transform = `translate(${this.x}px, ${this.y}px)`;
}
};
const updateKeyDict = (ev) => {
const k = ev.code;
if (/^Key[WASD]/.test(k)) { // If is "KeyW,A,S,D" key
ev.preventDefault();
keyDict[k] = ev.type === "keydown"; // set boolean true / false
}
};
const update = () => {
// Determine move distance to account diagonal move: 1/Math.sqrt(2) = ~0.707
let dist =
keyDict.KeyW && (keyDict.KeyA || keyDict.KeyD) ||
keyDict.KeyS && (keyDict.KeyA || keyDict.KeyD) ? 0.707 : 1;
dist *= Player.speed;
if (keyDict.KeyA) Player.x -= dist;
if (keyDict.KeyW) Player.y -= dist;
if (keyDict.KeyD) Player.x += dist;
if (keyDict.KeyS) Player.y += dist;
Player.move();
}
document.addEventListener('keydown', updateKeyDict);
document.addEventListener('keyup', updateKeyDict);
(function engine() {
update();
window.requestAnimationFrame(engine);
}());
#player {
position: absolute;
left: 0;
top: 0;
width: 20px;
height: 20px;
background: #000;
border-radius: 50%;
}
Click here to focus, and use keys WASD
<div id="player"></div>