我正在制作一款网页游戏(不是使用webGL,而是使用html元素),我需要使用WaSD键移动角色。我尝试了这些方法:
-
使用的事件监听器keydown和keyup。问题是,当同时按下多个键时,它反应迟钝,不能很好地工作
-
使用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);
}
}
- 使用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>