I have built a simple 2D game that makes use of the CanvasRenderingContext2D interface. There is a 'reset' method on the Game class that is called once the game has ended and the user clicked the 'r' key.
As far as I can tell the method resets the game object correctly but there is an issue with calling the animation function a second time because the deltaTime
variable is calculated incorrectly. When the animation is first run deltaTime
is around 16/ 17. When the animation is run again from the reset method, deltaTime
is equal to the gameTime
variable or more.
How can I factor in the difference in time when resetting the game?
Here is the animate function:
function animate(timeStamp) {
const deltaTime = timeStamp - lastTime
lastTime = timeStamp
ctx.clearRect(0, 0, canvas.width, canvas.height)
game.draw(ctx)
game.update(deltaTime)
if (game.gameOver) game.draw(ctx) // draw gameover text on top
if (!game.gameOver) requestAnimationFrame(animate)
}
The rest of the code can be found here. A live version of the game is deployed here.
I have tried adding another parameter to the animation function, to differentiate the initial animation from the reset animation. Then changing timeStamp
or lastTime
variable to gameTime
or 0 or a new time with the built-in new Date() method, but none of those worked.
function animate(timeStamp, restart) {
const deltaTime = timeStamp - lastTime
if (restart) timeStamp = 0
lastTime = timeStamp
ctx.clearRect(0, 0, canvas.width, canvas.height)
game.draw(ctx)
game.update(deltaTime)
if (game.gameOver) game.draw(ctx) // draw gameover text on top
if (!game.gameOver) requestAnimationFrame(animate)
}
I found the fix. I assigned requestAnimationFrame
to a variable, then used that to properly cancel the previous animation before starting the next one. Then declared a helper variable (restart
) with its initial value set to false.
The reset method on my main Game class cancels the animation frame and sets the restart
variable to true
.
The animation function checks if restart
is true and if it is, it calls the update
method on the game with 0
as the argument, instead of the default deltaTime
variable.
This is what the animation function looks like now:
function animate(timeStamp) {
const deltaTime = timeStamp - lastTime
lastTime = timeStamp
if (restart) {
game.update(0)
restart = false
} else game.update(deltaTime)
ctx.clearRect(0, 0, canvas.width, canvas.height)
game.draw(ctx)
if (game.gameOver) game.draw(ctx) // draw gameover text on top
if (!game.gameOver) requestID = requestAnimationFrame(animate)
}
And the reset method:
reset() {
if (this.gameOver) {
cancelAnimationFrame(requestID)
restart = true
// reset game objects
this.keys = []
this.enemies = []
this.particles = []
this.explosions = []
this.enemyTimer = 0
this.enemyInterval = 2000
this.ammo = 20
this.ammoTimer = 0
this.ammoInterval = 350
this.gameOver = false
this.score = 0
this.gameTime = 0
this.speed = 1
requestID = requestAnimationFrame(animate)
}
}
If you're interested you can check the rest of the code here.