You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何解决onkeydown实现角色WASD控制时移动几秒后停止的问题?

问题:键盘控制角色移动仅持续数毫秒就停止

我实现了鼠标控制角色移动的功能,但改用onkeydown替代onmousedown时,角色仅移动数毫秒就停止,松开按键后角色进入idle动画。请问该如何修复?


左右移动核心逻辑代码

const rightHandler = () => {
heroImg.style.transform = "scale(1,1)";
direction = "right";
spritePosition = spritePosition + 1;
imgBlockPosition = imgBlockPosition + 1;
if (spritePosition > 7) {
    spritePosition = 0;
}
heroImg.style.left = `-${spritePosition * 64}px`;
heroImg.style.top = '-64px';
imgBlock.style.left = `${imgBlockPosition * 7}px`;
}

const leftHandler = () => {
heroImg.style.transform = "scale(-1,1)";
direction = "left";
spritePosition = spritePosition - 1;
imgBlockPosition = imgBlockPosition - 1;
if (spritePosition < 7) {
    spritePosition = 13;
}
heroImg.style.left = `-${spritePosition * 64}px`;
heroImg.style.top = '-64px';
imgBlock.style.left = `${imgBlockPosition * 7}px`;
}

正常工作的鼠标控制代码

let onMouseDown = (event) => {
clearInterval(timer);
x = event.screenX;
timer = setInterval(() => {
    if (x > halfWidth) {
        direction = "right";
        rightHandler();
    }
    else {
        direction = "left";
        leftHandler();
    }
}, 100);
}

let onMouseUp = (event) => {
clearInterval(timer);
idleAnimation();
}

存在问题的键盘控制代码

let onKeyDown = (event) => {
clearInterval(timer);
var keyCode = event.keyCode;
timer = setInterval(() => {
    if (keyCode == 39) {
        direction = "right";
        rightHandler();
    }
    else if (keyCode == 37) {
        direction = "left";
        leftHandler();
    }
}, 100);
}

let onKeyUp = () => {
clearInterval(timer);
idleAnimation();
}

修复方案

问题根源

按住键盘按键时,浏览器会先触发一次onkeydown,随后等待系统默认的按键重复延迟(通常几百毫秒)才会连续触发onkeydown事件。你的代码每次触发onkeydown都会执行clearInterval(timer),导致第一次创建的定时器被后续重复触发的onkeydown清空,角色因此停止移动。

修复代码(基础版)

新增一个状态变量标记是否正在移动,避免重复创建/清空定时器:

// 新增状态变量,标记当前是否处于移动状态
let isMoving = false;

let onKeyDown = (event) => {
    // 如果已经在移动,直接返回,跳过后续逻辑
    if (isMoving) return;
    
    clearInterval(timer);
    const keyCode = event.keyCode;
    
    isMoving = true;
    timer = setInterval(() => {
        if (keyCode === 39) {
            direction = "right";
            rightHandler();
        } else if (keyCode === 37) {
            direction = "left";
            leftHandler();
        }
    }, 100);
}

let onKeyUp = () => {
    clearInterval(timer);
    isMoving = false; // 重置移动状态
    idleAnimation();
}

进阶优化方案(支持多按键同时按下)

如果需要支持多按键操作(比如同时按住左右键的逻辑处理),可以用集合记录当前按下的按键,定时器中检查按键状态:

// 用集合存储当前按下的按键码
const pressedKeys = new Set();
let timer = null;

document.addEventListener('keydown', (event) => {
    pressedKeys.add(event.keyCode);
    // 仅当定时器未启动时创建
    if (!timer) {
        timer = setInterval(() => {
            // 优先处理右键,可根据需求调整优先级
            if (pressedKeys.has(39)) {
                direction = "right";
                rightHandler();
            } else if (pressedKeys.has(37)) {
                direction = "left";
                leftHandler();
            }
        }, 100);
    }
});

document.addEventListener('keyup', (event) => {
    pressedKeys.delete(event.keyCode);
    // 没有按键按下时停止定时器
    if (pressedKeys.size === 0) {
        clearInterval(timer);
        timer = null;
        idleAnimation();
    }
});

内容的提问来源于stack exchange,提问作者daniel vor

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 07:43:24