5

I am trying to create an animation in canvas. The first time it worked fine but when a new element was added through setTimeout, all the elements speed is increased. Can anyone tell me why this speed is increasing. Fiddle Link

  var canvas = $("#canvas")[0],
    context = canvas.getContext("2d"),
    bloons = {},
    bloonIndex = 0;

var c_wdh = 360,
    c_hgt =  540;


function createBloon(x, y) {
  this.x = x;
  this.y = y; 
  this.vx = 1,
  this.vy = 3;
  bloonIndex++;
  bloons[bloonIndex] = this;
  this.id = bloonIndex;
}

createBloon.prototype.drawImage = function() {
   this.y -= this.vy;
   context.fillStyle = "#FF0000";
   context.fillRect(this.x, this.y, 50, 50);
   if(this.y <= -120){
      delete bloons[this.id];  
   }
};


var nob = 0;
var i = 1;
var rendorBloon = setInterval(function(){ 
    bloons[i] = new createBloon(Math.random() * c_wdh, c_hgt);
    var animate = setInterval(function () {
      context.clearRect(0, 0, c_wdh, c_hgt);          
      for (var i in bloons){
         bloons[i].drawImage();
      }
    }, 30); 

    i++; 
    nob++;
    if(nob >= 10){
      clearInterval(rendorBloon);
    }    
}, 1000);
fionaredmond
  • 639
  • 7
  • 15
  • 3
    you are calling setInterval inside a setInterval, bad idea... Also, for animation, use [`requestAnimationFrame()`](https://developer.mozilla.org/en/docs/Web/API/window.requestAnimationFrame), setInterval is really not the proper method if you have to deal with anything based on time. – Kaiido Jan 01 '16 at 10:30
  • 3
    You need to call second setInterval outside of the first one https://jsfiddle.net/v5eoeybe/5/ – jcubic Jan 01 '16 at 10:32
  • @jcubic thanks working now. – Gaurav Thakur Jan 01 '16 at 10:39
  • @Kaiido thanks for comment. I will look into your advise. – Gaurav Thakur Jan 01 '16 at 10:41
  • 4
    here is a version using rAF : https://jsfiddle.net/v5eoeybe/6/, should be tweaked to avoid the loop continues when there is no more bloon in the viewPort (setInterval version have the same problem) – Kaiido Jan 01 '16 at 10:43
  • @jcubic:can you help me with this question:http://stackoverflow.com/questions/37208156/update-html-canvas-tag-on-every-ajax-request-with-new-data – I Love Stackoverflow May 13 '16 at 13:16

1 Answers1

0

I'll try to explain to you why the animation is accelerated. Every time that the rendorBloon setInterval is called a new setInterval is created. The next steps explain the process:

1 - First run of rendorBloon setInterval (1 second):

    1 setInterval is created. 1 setInterval is running, it will run every 30 milliseconds

2 - Second run of rendorBloon setInterval (2 second):

    1 setInterval is created. 2 setInterval are running, they will run every 30 milliseconds

3 - Third run of rendorBloon setInterval (3 second):

    1 setInterval is created. 3 setInterval are running, they will run every 30 milliseconds

4 - ... Continues 10 times

In every rendorBloon execution, a new setInterval is created and each setInterval executes the drawImage method that moves the image 3 pixels above. When you clear the rendorBloon setInterval you will have 10 functions trying to move each box. The result: the boxes move 3 pixels with the first iteration, 6 pixels with the second, 9 pixels with the third, and go on.

I've created a new jsfiddle changing some things:

1 - Separate the two setIntervals.

2 - Move the animation logic to the animation function.

3 - Move the deletion of the boxes to the animation function.

4 - Create the drawImage method directly in the createBloon function avoiding the prototype.

5 - Clear the animate setInterval when the animation finished.

6 - Ensure that all boxes are drawed inside the canvas using c_wdh - width of the boxes for the random values.

Here you have the new jsfiddle.

ElChiniNet
  • 2,778
  • 2
  • 19
  • 27