为什么我的游戏进阶太多了?
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.length
将 gameState
更改为 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 开始的事实。
此外,最好有另一个游戏状态来赢得游戏,而不是 运行在打完最后一个关卡后使用相同的更新循环。
我正在尝试制作我的第一款游戏,但我无法弄清楚为什么 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.length
将 gameState
更改为 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 开始的事实。
此外,最好有另一个游戏状态来赢得游戏,而不是 运行在打完最后一个关卡后使用相同的更新循环。