如何在游戏循环中使用 addEventListener

How to use addEventListener in a game loop

我是 Javascript 的新手,所以如果这是一个相当微不足道的问题,请多多包涵。

我正在尝试制作一款可以使用箭头键控制玩家的游戏。代码的简化版本(不起作用)如下所示:

class Player {
  constructor(X) {
    this.X = X;
  }
}

class Game {
  constructor() {
    this.gamePlayer = new Player(0);
    window.requestAnimationFrame(() => this.gameLoop());
  }

  playerMovement(event) {
    switch (event.code) {
      case "ArrowLeft":
        console.log(this.gamePlayer.X);
        this.gamePlayer.X -= 1;
        break;
      case "ArrowRight":
        console.log(this.gamePlayer.X);
        this.gamePlayer.X += 1;
        break;
    }
  }

  gameLoop() {
    window.addEventListener("keydown", this.playerMovement);

    setTimeout(() => {
      window.requestAnimationFrame(() => this.gameLoop());
    }, 50);
  }
}

window.onload = () => {
  let game = new Game();
};

所以,基本上,我想用左右箭头键控制 gamePlayer.X。但是,使用上面的代码,每当我按箭头键时,都会收到以下错误消息:

Uncaught TypeError: Cannot read property 'X' of undefined at playerMovement

所以我的问题是,为什么它不能在函数 playerMovement 中读取这个。gamePlayer.X?我应该如何更改代码才能使其正常工作?

您只需注册一次事件侦听器,在构造函数中注册不会有任何坏处。您似乎已经知道这一点,因为您在其他地方正在这样做,但是您收到错误的原因是当您使用 window.addEventListener("keydown", this.playerMovement); 而不是 window.addEventListener("keydown", (e) => this.playerMovement(e)); 时范围发生了变化。当您直接传递函数时,作用域变为调用者的作用域 - 在本例中为 window。 lambda 维护作用域。

我也不确定 setTimeoutgameloop 中做了什么,我怀疑它以后会给你带来麻烦。

class Player {
  constructor(X) {
    this.X = X;
  }
}

class Game {
  constructor() {
    this.gamePlayer = new Player(0);
    window.requestAnimationFrame(() => this.gameLoop());
    window.addEventListener("keydown", (e) => this.playerMovement(e));
  }

  playerMovement(event) {
    switch (event.code) {
      case "ArrowLeft":
        console.log(this.gamePlayer.X);
        this.gamePlayer.X -= 1;
        break;
      case "ArrowRight":
        console.log(this.gamePlayer.X);
        this.gamePlayer.X += 1;
        break;
    }
  }

  gameLoop() {
    

    window.requestAnimationFrame(() => this.gameLoop());
  }
}

window.onload = () => {
  let game = new Game();
};