0

I'm currently trying to make a sparkle effect that happens within the canvas. However, as I was testing out the animation, I noticed that some circles would be erased for a frame, and then reappear again.

This seems to be caused when a sparkle of a higher index is removed by splicing. You can notice the flash whenever a sparkle shrinks to a radius of 0. If this is the actual reason why it causes the issue, I really don't understand why splicing would cause such an issue.

https://jsfiddle.net/sketti21/2gfarp74/82/

// Handles the animation of the sparkles.
function animate(timestamp)
{
  // Observe the timestamp gives by requestAnimationFrame in console.
  // console.log(timestamp);

  // Clears the previous frame;
  draw.clearRect(0, 0, canvas.width, canvas.height);

  // Loop through each index of sparkles. Doing this lets us draw multiple
  // sparkles at once.
  for (i = 0; i < sparkles.length; i++)
  {
    if (sparkles[i] != null)
    {
      // If the sparkle's delay is not set, then set it.
      // This is necessary to do here since the timestamp that requestAnimationFrame
      // puts in as a parameter is always growing.
      if (sparkles[i].delay == null)
      {
        sparkles[i].delay = Math.floor(Math.random()*config.maxDelay) + timestamp;
      }

      // Handles whether to animate the next frame or to remove this sparkle from array.
      // If timestamp is larger than sparkle's delay, this means it's time to
      // animate this sparkle.
      if (timestamp > sparkles[i].delay)
      {
        // Increment the input variable and calculate the radius of circle.
        sparkles[i].inputX += config.increment;
        var radius = getRadius(sparkles[i].inputX, sparkles[i].multiplier);
        console.log("Radius of index " + i + ": " + radius);
        console.log("Multiplier of index " + i + ": " + sparkles[i].multiplier);

        if (radius < 0)
        {
          radius = 0;
        }

        // Drawing the circle.
        draw.beginPath();
        draw.arc(sparkles[i].x,
                 sparkles[i].y,
                 radius, 0, 360);
        draw.fill();
        draw.closePath();

        // If the sparkle's radius drops below 0, then remove it from the array.
        if (radius == 0)
        {
          sparkles.splice(i, 1);
          console.log("spliced indexes " + i + " to " + (i + 1));
        }
      }
    }
  }

  if (sparkles.length > 0)
  {
    animControl = window.requestAnimationFrame(animate);
  }
  else
  {
    console.log("Refilled the array.");
    for (i = 0; i < config.maxSparkles; i++)
    {
      sparkles[i] = new Sparkle();
    }
    animControl = window.requestAnimationFrame(animate);
  }
}

Let me summarize the logic of my code to make reading through it quicker and easier:

  1. Create the sparkles array.
  2. Start the animation. (animate())
  3. Clear the canvas.
  4. Fill sparkles array up to config.maxSparkles.
  5. requestAnimationFrame(animate)
  6. Clear the canvas.
  7. If a random delay hasn't been assigned to the Sparkle object, then calculate a delay that's below config.maxDelay and add the timestamp.
  8. If the current timestamp is greater than the Sparkle's delay..

    8a. Calculate and draw each sparkle individually for this frame.

    8b. If the Sparkle radius = 0, then splice that sparkle out of the sparkles array.

  9. If there are elements in the sparkles array, then requestAnimationFrame(animate)

    9a. Else, refill the array up to config.maxSparkles.

... So on and so forth.

Any help is greatly appreciated!

Nick Sabia
  • 39
  • 7
  • Possible duplicate of [Looping through array and removing items, without breaking for loop](https://stackoverflow.com/questions/9882284/looping-through-array-and-removing-items-without-breaking-for-loop) – Thomas Oct 19 '19 at 21:14
  • https://jsfiddle.net/xebq1dwo/ – Thomas Oct 19 '19 at 21:17
  • Thats a really cool way to handle everything! I've never heard of or used filter before, I'll be sure to read up more about it. The random colors are cool too. I'm assuming since splicing isn't involved, there's no stuttering occurring – Nick Sabia Oct 19 '19 at 21:44

1 Answers1

0

When you splice something from an array, an element gets removed, and thus the length is shortened by one.

So if you loop through an array and remove something, that means that the index for the item you are removing has now become the index for the next item. So on the next loop, that item is skipped.

To solve your problem, you need to decrement i when you splice something from the array, so it isn't skipped on the next iteration.

That should hopefully solve the issue!

danthony
  • 86
  • 6
  • 1
    Thanks for the explanation! I just implemented your solution and it worked wonders! I was also able to move the splicing out of the for loop and it fixed it as well. However, your solution is the simplest. – Nick Sabia Oct 19 '19 at 21:50