为什么我的游戏进阶太多了?

Why does my game advance to one level too many?

我正在尝试制作我的第一款游戏,但我无法弄清楚为什么 gameState.nextLevel 屏幕在只有 4 个级别时将我推进到第 5 级。

我认为这可能与 promptNextLevel 函数有关,该函数具有设置 currentLevel++ 的超时函数。

我已经尝试添加 if 语句来防止函数从 运行 if this.currentLevel = this.levels.length 但是当我完成所有 4 个级别时,我仍然从 gameState.nextLevel 获得弹出窗口那说 "You completed level 4" 然后在 1 秒后它变成 "You completed level 5".

我尝试添加一个 if 语句,如果 this.currentLevel = this.levels.lengthgameState 更改为 gameOver,但它没有任何作用。

我查看代码已经有一段时间了,还是想不通。请帮忙!

我不确定需要帮助的相关内容,所以我将复制 game.js 文件。

const gameState = {
  paused: 0,
  running: 1,
  menu: 2,
  gameOver: 3,
  attempt: 4,
  nextLevel: 5,
}

export default class Game {

  constructor(gameWidth, gameHeight) {
    this.gameWidth = gameWidth;
    this.gameHeight = gameHeight;
    this.gameState = gameState.menu;
    this.paddle = new Paddle(this);

    this.ball = new Ball(this);
    this.gameObjects = [];
    this.lives = 3;
    this.lifeLost = false;
    this.bricks = [];
    this.levels = [Level1, Level2, Level3, Level4];
    this.currentLevel = 3;
    new InputHandler(this.paddle, this);
  }

  start() {
    //Start only from menu and nextLevel
    if (this.gameState !== gameState.menu &&
      this.gameState !== gameState.nextLevel
    ) return;

    this.bricks = buildLevel(this, this.levels[this.currentLevel]);

    this.ball.reset();
    this.gameObjects = [
      this.paddle,
      this.ball,
    ];

    this.gameState = gameState.running;
  }

  update(deltaTime) {
    //do not update if gameState is paused, menu, or gameOver
    if (this.gameState === gameState.paused ||
      this.gameState === gameState.menu ||
      this.gameState === gameState.gameOver ||
      this.gameState === gameState.nextLevel) {
      return
    }

    //Check for gameover       
    if (this.lives === 0) {
      this.gameState = gameState.gameOver
    };

    //if lifeLost then gameState attempt shows remaining lives for 3 sec
    if (this.lifeLost) {
      this.gameState = gameState.attempt;
      this.lifeLost = false;
      setTimeout(() => {
        this.gameState = gameState.running;
      }, 3000);
      clearTimeout();
    }


    //update objects every frame game is running
    if (this.gameState === gameState.running) {
      [...this.gameObjects, ...this.bricks].forEach((object) => object.update(deltaTime));

      //filter out hit bricks
      this.bricks = this.bricks.filter(
        (object) => !object.markedForDeletion
      )
    }

    //progress to next level once all bricks hit

    if (!this.bricks.length) {
      if (this.currentLevel < this.levels.length) {
        this.gameState = gameState.nextLevel;
        this.promptNextLevel();
        return;
      }
    }
  }

  promptNextLevel() {
    setTimeout(() => {
      if (this.gameState === gameState.nextLevel) {
        this.currentLevel++;
        this.start();
      }
    }, 1000);
    clearTimeout();
  }

  draw(ctx) {
    //draw objects if game is running
    if (this.gameState === gameState.running)
      [...this.gameObjects, ...this.bricks].forEach((object) => object.draw(ctx));

    //sets the dialog and background for each gameState
    if (this.gameState === gameState.paused) {
      ctx.fillStyle = 'rgba(211, 211, 211, .5)';
      ctx.fillRect(0, 0, this.gameWidth, this.gameHeight);
      ctx.fill();

      ctx.font = '30px Arial';
      ctx.fillStyle = 'black';
      ctx.textAlign = 'center';
      ctx.fillText('PAUSED', this.gameWidth / 2, this.gameHeight / 2);
    }

    if (this.gameState === gameState.menu) {
      ctx.fillStyle = 'rgba(0, 0, 0, 1)';
      ctx.fillRect(0, 0, this.gameWidth, this.gameHeight);
      ctx.fill();

      ctx.font = '30px Arial';
      ctx.fillStyle = 'white';
      ctx.textAlign = 'center';
      ctx.fillText('MENU', this.gameWidth / 2, this.gameHeight / 2 - 60);
      ctx.font = '18px Arial';
      ctx.fillText('Press SPACEBAR to start', this.gameWidth / 2, this.gameHeight / 2);
      ctx.fillText('Press H to view High Scores', this.gameWidth / 2, this.gameHeight / 2 + 30)
    }

    if (this.gameState === gameState.gameOver) {
      ctx.fillStyle = 'rgba(0, 0, 0, 1)';
      ctx.fillRect(0, 0, this.gameWidth, this.gameHeight);
      ctx.fill();

      ctx.font = '30px Arial';
      ctx.fillStyle = 'white';
      ctx.textAlign = 'center';
      ctx.fillText('GAME OVER', this.gameWidth / 2, this.gameHeight / 2 - 60);
      ctx.font = '18px Arial';
      ctx.fillText('Press ENTER for Main Menu', this.gameWidth / 2, this.gameHeight / 2);
    }

    if (this.gameState === gameState.attempt) {
      ctx.fillStyle = 'rgba(0, 0, 0, .5)';
      ctx.fillRect(0, 0, this.gameWidth, this.gameHeight);
      ctx.fill();

      ctx.font = '30px Arial';
      ctx.fillStyle = 'black';
      ctx.textAlign = 'center';
      if (this.lives > 1) {
        ctx.fillText(`You have ${this.lives} lives left`, this.gameWidth / 2, this.gameHeight / 2 - 60);
      } else {
        ctx.fillText(`You have ${this.lives} life left`, this.gameWidth / 2, this.gameHeight / 2 - 60);
      }
    }

    if (this.gameState === gameState.nextLevel) {
      ctx.fillStyle = 'rgba(0, 0, 0, .5)';
      ctx.fillRect(0, 0, this.gameWidth, this.gameHeight);
      ctx.fill();

      ctx.font = '30px Arial';
      ctx.fillStyle = 'black';
      ctx.textAlign = 'center';
      ctx.fillText(`You completed Level ${this.currentLevel + 1}`, this.gameWidth / 2, this.gameHeight / 2 - 60);
    }
  }

  togglePause() {
    if (this.gameState === gameState.running || this.gameState === gameState.paused) {
      if (this.gameState === gameState.paused) {
        this.gameState = gameState.running;
      } else this.gameState = gameState.paused;
    } else return;
  }
}

需要游戏结束

const gameOver = this.currentLevel === this.levels.length -1;

你必须记住,数组索引从 0

您的级别数组包含四个项目,因此长度为 4。但是,索引 (currentLevel) 从 0 开始。这意味着级别 1 是索引 0,级别 2 是索引 1,依此类推。

所以,当你 运行 这个:

if (this.currentLevel < this.levels.length )

在第 4 关,您实际上是在检查是否 3 < 4,这当然是正确的。于是,又提示了下一级

相反,您应该检查:

if (this.currentLevel < this.levels.length - 1)

从数组的长度中减去 1 将解释 JavaScript 中的数组从 0 而不是 1 开始的事实。

此外,最好有另一个游戏状态来赢得游戏,而不是 运行在打完最后一个关卡后使用相同的更新循环。