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

原生JS实现双人键盘控制仅最后绑定事件生效如何解决

问题根源

你的代码只有最后绑定的控制生效,核心原因是直接对DOM元素的onxxx事件属性赋值时,后赋值的回调会完全覆盖之前绑定的回调:你先给window.onkeydown赋值了玩家1的WASD控制逻辑,之后调用player2.setControlsArrow()时又给同一个属性赋了方向键控制的回调,玩家1的绑定直接被覆盖,自然不会生效。
另外你的代码里还有一处笔误:方向键上的keyCode判断写了38d,属于非法语法,运行时会直接报错,需要改成38。

实现方案

不推荐给每个玩家单独绑定keydown事件的写法,一方面事件绑定冗余,另一方面原生键盘事件的触发机制会导致多键同按时容易出现按键冲突、移动卡顿的问题,更适合游戏场景的写法是统一维护按键状态表,在游戏主循环里处理移动逻辑,实现步骤如下:

  • 全局初始化一个按键状态对象,记录每个按键的按下/抬起状态
  • 仅在全局绑定一次keydown和keyup事件,事件触发时只更新对应按键的状态,不直接修改玩家位置
  • 在每一帧的游戏更新逻辑里,根据当前按下的按键,分别计算两个玩家的位移
  • 移除原来两个玩家类里单独绑定键盘事件的方法

参考实现代码

// 全局按键状态表,key是keyCode,value是布尔值代表是否按下
const keys = {};

// 绑定一次键盘事件,更新按键状态
window.addEventListener('keydown', (e) => {
  keys[e.keyCode] = true;
  // 阻止方向键滚动页面的默认行为
  if ([37, 38, 39, 40].includes(e.keyCode)) {
    e.preventDefault();
  }
});
window.addEventListener('keyup', (e) => {
  keys[e.keyCode] = false;
});

// 游戏主循环,每帧执行
function gameLoop() {
  // 按自己项目逻辑补充清空画布的代码
  // ctx.clearRect(0, 0, canvas.width, canvas.height);

  // 处理玩家1的WASD控制
  if (keys[65]) player1.x -= player1.velX; // A键左移
  if (keys[68]) player1.x += player1.velX; // D键右移
  if (keys[87]) player1.y -= player1.velY; // W键上移
  if (keys[83]) player1.y += player1.velY; // S键下移

  // 处理玩家2的方向键控制
  if (keys[37]) player2.x -= player2.velX; // 方向键左
  if (keys[39]) player2.x += player2.velX; // 方向键右
  if (keys[38]) player2.y -= player2.velY; // 方向键上
  if (keys[40]) player2.y += player2.velY; // 方向键下

  // 原有游戏逻辑
  player1.checkBounds();
  player1.collisionDetect();
  player1.draw();

  player2.checkBounds();
  player2.collisionDetect();
  player2.draw();

  // 递归调度下一帧
  requestAnimationFrame(gameLoop);
}

// 启动游戏
gameLoop();

快速修复方案(仅适合临时测试)

如果你不想重构原有逻辑,只需要把两个控制方法里直接给window.onkeydown赋值的写法,改成addEventListener绑定,同时修正38d的笔误即可:

setControlsButton(){
  const _this = this;
  window.addEventListener('keydown', function(e) {
    if (e.keyCode === 65) {
      _this.x -= _this.velX;
    } else if (e.keyCode === 68) {
      _this.x += _this.velX;
    } else if (e.keyCode === 87) {
      _this.y -= _this.velY;
    } else if (e.keyCode === 83) {
      _this.y += _this.velY;
    }
  })
}

setControlsArrow(){
  const _this = this;
  window.addEventListener('keydown', function(e) {
    if (e.keyCode === 37) {
      _this.x -= _this.velX;
    } else if (e.keyCode === 39) {
      _this.x += _this.velX;
    } else if (e.keyCode === 38) {
      _this.y -= _this.velY;
    } else if (e.keyCode === 40) {
      _this.y += _this.velY;
    }
  })
}

这种写法存在键盘事件触发频率不稳定、多键同按容易失效、移动卡顿的问题,不建议在正式游戏逻辑里使用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 00:39:18