title: How to set a delay after each shot in HTML 5 JS Canvas football penalty game
body: <p>I am trying to make a simple football penalty game using HTML5/JS Canvas. The aim is to make a game where you control the goal keeper and you have three attempts to save the ball.</p>
  
  <p>I have most of the functionality done, I have a score system and collision detection.</p>
  
  <p>My problem is that after the ball is shot, the feedback text only appears for a split second and it resets my canvas ready for the next penalty shot attempt.</p>
  
  <p>Any advice? I tried using setTimeout() to delay it but it still doesn't work.</p>
  
  <p>Thanks</p>
  
  <pre><code> &lt;html&gt;
  &lt;head&gt;
      &lt;meta charset="utf-8" /&gt;
      &lt;title&gt;Phantom football&lt;/title&gt;
      &lt;style&gt;
          * { padding: 0; margin: 0; }
          #myCanvas { 
              background: url('http://i754.photobucket.com/albums/xx182/rache_R/Phantom-Football_Title-v1_zpsuj9jgu27.jpg');
              display: block; 
          }
  
      &lt;/style&gt;
  &lt;/head&gt;
  &lt;body&gt;
  
  &lt;canvas id="myCanvas" width="300" height="250"&gt;&lt;/canvas&gt;
  &lt;script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.18.5/TweenMax.min.js"&gt;&lt;/script&gt;
  &lt;script&gt;
  
  
  
  var canvas = document.getElementById('myCanvas');
  var ctx = canvas.getContext("2d");
  
  //Sets the original position of the ball
  var x = canvas.width/2;
  var y = 20;
  
  // Defines  values that will be added to the position of x and y values
  // List of possible values for the x position
  var x_options = [2.4, 2, 1.4, 1, 0.4, 0, -0.5, -1, -1.5, -2, -2.5, -3, -2.4];
  
  // Gets a random value from the x_options array
  var dx = -2.4;
  var dy = 5;
  
  var ballRadius = 10;
  
  // Defines the height and width of the goal
  var goal_height = 40;
  var goal_width = 200
  
  
  // Defines the height, width and position of goalie
  var goalieHeight = 20;
  var goalieWidth = 40;
  var goalieX = (canvas.width-goalieWidth)/2;
  var goalieY = (canvas.height - goal_height) - 30;
  
  // Set to false by default
  var rightPressed = false;
  var leftPressed = false;
  
  // Set default values for score and number of attempts left
  var goalkeeper_blocked = 0;
  var goalkeeper_missed = 0;
  var attempts_left = 3;
  
  
  var footBall = {
  
       // is a shot in progress
      isShooting:false,
  
      // time when next shot will run
      nextShotTime:0,
  
      // delay until next shot will run
      delayUntilNextShot:3000,
  
      // is the game currently running
      inGame : false,
  
      shapes : {
          ball: function (){
              ctx.beginPath();
              ctx.arc(x, y, ballRadius, 0, Math.PI*2, false);
              ctx.fillStyle = "red";
              ctx.fill();
              ctx.closePath();
  
          },
  
          goal : function (){
              ctx.beginPath();
              ctx.rect((canvas.width - goal_width) / 2 , canvas.height - goal_height, goal_width, goal_height);
              ctx.strokeStyle = "#000000";
              ctx.stroke();
              ctx.closePath();
          },
  
          goalie : function(){
              ctx.beginPath();
              ctx.rect(goalieX, goalieY, goalieWidth, goalieHeight);
              ctx.fillStyle = "#666666";
              ctx.fill();
              ctx.closePath();
          },
  
          score : function(){
              ctx.font = "16px Arial";
              ctx.fillStyle = "#ffffff";
              ctx.fillText("Saved: "+goalkeeper_blocked, 8, 20);
          },
  
          missedScore : function(){
              ctx.font = "16px Arial";
              ctx.fillStyle = "#ffffff";
              ctx.fillText("Missed: "+goalkeeper_missed, 8, 40);
          },
  
          attempts : function(){
              ctx.font = "16px Arial";
              ctx.fillStyle = "#ffffff";
              ctx.fillText("Attempts left: "+attempts_left, canvas.width-110, 20);
          },
  
          missedBallMessage : function(){
              ctx.font = "16px Arial";
              ctx.fillStyle = "#ffffff";
              ctx.fillText("You missed the ball! Attempts left : " +attempts_left, 20, canvas.height / 2);
          },
  
          savedBallMessage : function(){
              ctx.font = "16px Arial";
              ctx.fillStyle = "#ffffff";
              ctx.fillText("You saved the ball! Attempts left : " +attempts_left, 20, canvas.height / 2);
  
          },
  
          gameOverLoserMessage : function(){
              ctx.font = "16px Arial";
              ctx.fillStyle = "#ffffff";
              ctx.fillText("GAME OVER! You Lose!" , 20, canvas.height / 2);
          },
  
          gameOverWinnerMessage : function(){
              ctx.font = "16px Arial";
              ctx.fillStyle = "#ffffff";
              ctx.fillText("GAME OVER! You Win" , 20, canvas.height / 2);
          }
  
      },
  
      controls : {
          keyDownHandler : function (e){
              if(e.keyCode == 39) {
                  rightPressed = true;
              }
              else if(e.keyCode == 37) {
                  leftPressed = true;
              }
  
          },
  
          keyUpHandler : function(e){
              if(e.keyCode == 39) {
                  rightPressed = false;
              }
              else if(e.keyCode == 37) {
                  leftPressed = false;
              }
  
          },
  
          mouseMoveHandler : function(e){
              var relativeX = e.clientX - canvas.offsetLeft;
              if(relativeX &gt; 0 &amp;&amp; relativeX &lt; canvas.width) {
                  goalieX = relativeX - goalieWidth/2;
              }
          }
  
      },
  
      calculateScore : function(){
          if(goalkeeper_missed &gt; goalkeeper_blocked){
              footBall.shapes.gameOverLoserMessage();
              document.location.reload();
  
          } else {
              footBall.shapes.gameOverWinnerMessage();
              document.location.reload();
          }
      },
  
  
      resetShapePositions : function(){
          //Sets the original position of the ball
          x = canvas.width/2;
          y = 20;
  
          // Sets a new shooting path
          dx = x_options[Math.floor(Math.random() * x_options.length)];
          dy = 5;
  
          // Resets the goalie to the middle
          goalieX = (canvas.width-goalieWidth)/2;
  
      },
  
      drawField: function(){
          // This ensures that the ball doesn't leave a trail
          // Clears the canvas of shapes each frame
          ctx.clearRect(0, 0, canvas.width, canvas.height);
  
          // Draws shapes on the canvas
          footBall.shapes.ball();
          footBall.shapes.goal();
          footBall.shapes.goalie();
          footBall.shapes.score();
          footBall.shapes.missedScore();
          footBall.shapes.attempts();
      },
  
  
      draw : function(currentTime){
  
          //   makes paddle move left and right and only within the canvas
          if(rightPressed &amp;&amp; goalieX &lt; canvas.width-goalieWidth) {
              goalieX += 7;
          }
          else if(leftPressed &amp;&amp; goalieX &gt; 0) {
            goalieX -= 7;
          }
  
          // draw the scene
          footBall.drawField();
  
          // delay until next shot time is due 
          if(!footBall.isShooting){
              // time has elapsed, let's shoot again
              if(currentTime&gt;footBall.nextShotTime){
                  console.log("Shot time delay " + footBall.nextShotTime);
                  footBall.isShooting=true;
              }else{
                  // time has not elapsed, just request another loop
                  requestAnimationFrame(footBall.draw);
                  return;
              }
          }
  
          // adds values to the balls  x and y position every frame
          x += dx;
          y += dy;
  
  
  
          // Ball hits the goal 
          if(y + dy &gt; canvas.height - goal_height) {
  
              // end the shot
              footBall.isShooting=false;
              // delay the next shot
              footBall.nextShotTime=currentTime+footBall.delayUntilNextShot;
  
  
              attempts_left--;
              goalkeeper_missed++;
              if (!attempts_left){
                  footBall.calculateScore();
              } 
              else {
  
  
                  footBall.shapes.missedBallMessage();
  
                  footBall.resetShapePositions();
              }
  
  
  
          } // Ball saved by goalie
          else if (x  &gt; goalieX &amp;&amp; x  &lt; goalieX + goalieWidth &amp;&amp; y + dy &gt; goalieY - ballRadius){
              // end the shot
              footBall.isShooting=false;
              // delay the next shot
              footBall.nextShotTime=currentTime+footBall.delayUntilNextShot;
  
              attempts_left--;
              goalkeeper_blocked++;
  
              if (!attempts_left){
                  footBall.calculateScore();
              } 
              else {
                  footBall.shapes.savedBallMessage();
                  footBall.resetShapePositions();
  
              }
  
  
          } 
  
          requestAnimationFrame(footBall.draw);       
      }
  
  
  }
  
  TweenMax.from("#myCanvas", 0.5, {opacity: 0, scale: 0, ease: Bounce.easeOut});
  
  
  
  var hideIntro = function (e) {
      if(e.keyCode == 32 &amp;&amp; footBall.inGame == false) {
          document.getElementById('myCanvas').style.background = '#a5bd7b';
          console.log("hide");
          requestAnimationFrame(footBall.draw);
          footBall.nextShotTime = footBall.delayUntilNextShot;
          footBall.inGame = true;
      }
  };
  
  
  
  document.addEventListener("keydown", hideIntro, false);
  
  // Defines what functions are fired when keydown or keyup event triggers
  document.addEventListener("keydown", footBall.controls.keyDownHandler, false);
  document.addEventListener("keyup", footBall.controls.keyUpHandler, false);
  document.addEventListener("mousemove", footBall.controls.mouseMoveHandler, false);
  
  &lt;/script&gt;
  
  &lt;/body&gt;
  &lt;/html&gt;
  </code></pre>