JavaScript键盘重复延迟问题:WASD控制游戏移动不流畅求助
WASD角色移动卡顿问题修复
我制作了一款通过WASD按键控制角色移动的游戏,但实际效果不符合预期:每次按下按键时,角色先移动一小步,之后会无延迟重复移动,导致画面卡顿不流畅。
原代码如下:
var Player = document.getElementById("Player"); const SpeedX = 35; const SpeedY = 20; var x = parseInt(getComputedStyle(Player).marginLeft); var y = parseInt(getComputedStyle(Player).marginTop); var keysPressed = {}; document.addEventListener("keydown", (e) => { keysPressed[e.key] = true; if(e.key == 'w') { if(y > 30 && y < 950) { y -= SpeedY; Player.style.marginTop = y + "px"; console.log(y); } else if(y == 950) Player.style.marginTop = (y -= SpeedY) + "px"; } if(e.key == 'a') { if(x > -5 && x < 1780) { x -= SpeedX; Player.style.marginLeft = x + "px"; console.log(x); } else if(x == 1780) Player.style.marginLeft = (x -= SpeedX) + "px"; } if(e.key == 's') { if(y > 30 && y < 950) { y += SpeedY; Player.style.marginTop = y + "px"; console.log(y); } else if(y == 30) Player.style.marginTop = (y += SpeedY) + "px"; } if(e.key == 'd') { if(x > -5 && x < 1780) { x += SpeedX; Player.style.marginLeft = x + "px"; console.log(x); } else if(x == -5) Player.style.marginLeft = (x += SpeedX) + "px"; } if(e.key == 'w' && keysPressed['a']) { if(x > -5 && x < 1780 && y > 30 && y < 950) { y -= SpeedY; x -= SpeedX; Player.style.marginLeft = x + "px"; Player.style.marginTop = y + "px"; }} if(e.key == 'w' && keysPressed['d']) { if(x > -5 && x < 1780 && y > 30 && y < 950) { y -= SpeedY; x += SpeedX; Player.style.marginLeft = x + "px"; Player.style.marginTop = y + "px"; }} if(e.key == 's' && keysPressed['a']) { if(x > -5 && x < 1780 && y > 30 && y < 950) { y += SpeedY; x -= SpeedX; Player.style.marginLeft = x + "px"; Player.style.marginTop = y + "px"; }} if(e.key == 's' && keysPressed['d']) { if(x > -5 && x < 1780 && y > 30 && y < 950) { y += SpeedY; x += SpeedX; Player.style.marginLeft = x + "px"; Player.style.marginTop = y + "px"; }} if(e.key == 'a' && keysPressed['w']) { if(x > -5 && x < 1780 && y > 30 && y < 950) { y -= SpeedY; x -= SpeedX; Player.style.marginLeft = x + "px"; Player.style.marginTop = y + "px"; }} if(e.key == 'd' && keysPressed['w']) { if(x > -5 && x < 1780 && y > 30 && y < 950) { y -= SpeedY; x += SpeedX; Player.style.marginLeft = x + "px"; Player.style.marginTop = y + "px"; }} if(e.key == 'a' && keysPressed['s']) { if(x > -5 && x < 1780 && y > 30 && y < 950) { y += SpeedY; x -= SpeedX; Player.style.marginLeft = x + "px"; Player.style.marginTop = y + "px"; }} if(e.key == 'd' && keysPressed['s']) { if(x > -5 && x < 1780 && y > 30 && y < 950) { y += SpeedY; x += SpeedX; Player.style.marginLeft = x + "px"; Player.style.marginTop = y + "px"; }} }) document.addEventListener('keyup', (event) => { delete keysPressed[event.key]; });
问题原因
- 依赖
keydown事件触发移动:系统默认键盘按键重复有初始延迟,第一次按下后会先触发一次,间隔一小段时间才会连续触发,导致移动卡顿。 - 多按键判断冗余:同一组合按键的判断逻辑重复,可能导致单次按键触发多次移动计算,干扰流畅度。
修复方案
改用requestAnimationFrame实现游戏循环,实时检测按键状态,和屏幕刷新率同步更新角色位置,彻底解决延迟问题,同时简化多按键判断逻辑:
修改后的代码:
var Player = document.getElementById("Player"); const SpeedX = 35; const SpeedY = 20; var x = parseInt(getComputedStyle(Player).marginLeft); var y = parseInt(getComputedStyle(Player).marginTop); var keysPressed = {}; // 记录按键状态 document.addEventListener("keydown", (e) => { keysPressed[e.key.toLowerCase()] = true; }); document.addEventListener('keyup', (event) => { delete keysPressed[event.key.toLowerCase()]; }); // 游戏循环 function gameLoop() { let dx = 0; let dy = 0; // 检测按键状态,计算位移 if (keysPressed['w']) dy -= SpeedY; if (keysPressed['s']) dy += SpeedY; if (keysPressed['a']) dx -= SpeedX; if (keysPressed['d']) dx += SpeedX; // 边界判断 const newX = x + dx; const newY = y + dy; if (newX > -5 && newX < 1780) x = newX; if (newY > 30 && newY < 950) y = newY; // 统一更新位置 Player.style.marginLeft = x + "px"; Player.style.marginTop = y + "px"; // 持续循环 requestAnimationFrame(gameLoop); } // 启动循环 gameLoop();
关键优化点
- 分离按键记录与移动逻辑:
keydown和keyup只负责维护按键状态,不处理移动计算。 - 游戏循环同步屏幕刷新:
requestAnimationFrame会在浏览器每次重绘前执行,保证移动动画和屏幕刷新率一致,消除卡顿。 - 简化多按键处理:直接叠加多个按键的位移,自然支持斜向移动,无需重复判断组合按键。
- 统一边界判断:先计算目标位置,再判断是否在边界内,避免冗余的条件分支。
内容的提问来源于stack exchange,提问作者kas kas
相关产品推荐
相关产品推荐

