Randal Andrade Nunes
Randal Andrade Nunes

Reputation: 4864

How to add a delay to recursive loop html canvas

I have this game loop where I have a red rectangle and a yellow rectangle on top of it. When a player takes damage, the yellow rectangle's width decreases because it is based on player's life. When player's life reaches zero he loses the game and all animations are cancelled. The issue I am having is that because the loop is so quick, the yellow rectangle does not have time to lower the life to zero and a bit of it is left on the screen when the animations are cancelled. For that reason I need to add a bit of delay before cancelling the animations. Thanks guys.

// DECREASE PLAYER LIFE AND DELETE ENEMY IF IT COLIDES WITH PLAYER
    enemyArray.forEach(function(enemy) {
    if (collides(player, enemy)) {
        player.life += -10;
        enemy.delete();
    }
    });

      // ANIMATION LOOP

      function animate(currentTime) {
        const animation = requestAnimationFrame(animate);
        c.clearRect(0, 0, canvas.width, canvas.height);



        // PLAYER LIFE
        // RED REC
        c.beginPath();
        c.rect(20, 20, 150, 30);
        c.fillStyle = "red";
        c.fillRect(10, 30, 200, 20);
        // YELLOW REC
        c.beginPath();
        c.rect(20, 20, 150, 30);
        c.fillStyle = "yellow";
        c.fillRect(10, 30, player.life, 20);


        // END GAME

       //I need some delay here so that fillRect has time to decrease the yellow bar to 0;
        if (player.life <= 0) {
          console.log("You Lose");
          music.pause();
          paused = true;
          cancelAnimationFrame(animation);
        }
      }
      animate();

Image of player life bar when animations are canceled. There is a bit left still.

Upvotes: 2

Views: 147

Answers (1)

visibleman
visibleman

Reputation: 3315

You haven't really explained what the game logic looks like. But I suspect perhaps all you need to do is to move the game logic that is causing damage to above the rendering, instead of after.

Edit: As mentioned in the comments, if player life is allowed to turn negative, it can also cause the image you are showing, in that case you can add a Math.max(value,0) to the render

 // ANIMATION LOOP

  function animate(currentTime) {
    const animation = requestAnimationFrame(animate);
    c.clearRect(0, 0, canvas.width, canvas.height);

    // Move game logic that decreases player life to here.

    // PLAYER LIFE
    // RED REC
    c.beginPath();
    c.rect(20, 20, 150, 30);
    c.fillStyle = "red";
    c.fillRect(10, 30, 200, 20);
    // YELLOW REC
    c.beginPath();
    c.rect(20, 20, 150, 30);
    c.fillStyle = "yellow";
    c.fillRect(10, 30, Math.max(player.life,0) , 20); // prevent negative value


    // Is game logic that decreases player life here?
    // END GAME

   //I need some delay here so that fillRect has time to decrease the yellow bar to 0;
    if (player.life <= 0) {
      console.log("You Lose");
      music.pause();
      paused = true;
      cancelAnimationFrame(animation);
    }
  }
  animate();

Typically you would organize your code something like this.

var paused=false;
  // Game Logic
function update()
{
  enemyArray.forEach(function(enemy) {
  if (collides(player, enemy)) {
      player.life += -10;
      enemy.delete();
  }
  });
  if (player.life <= 0) {
    console.log("You Lose");
    music.pause();
    paused = true;
  }
}
// Render
function draw()
{
  c.clearRect(0, 0, canvas.width, canvas.height);
  // PLAYER LIFE
  // RED REC
  c.beginPath();
  c.rect(20, 20, 150, 30);
  c.fillStyle = "red";
  c.fillRect(10, 30, 200, 20);
  // YELLOW REC
  c.beginPath();
  c.rect(20, 20, 150, 30);
  c.fillStyle = "yellow";
  c.fillRect(10, 30, Math.max(player.life,0) , 20); // prevent negative value
}
 
 // Animation Loop
function animate(currentTime) {
  update();
  draw();
  if (!paused)
    const animation = requestAnimationFrame(animate);
}
animate();

Upvotes: 1

Related Questions