Search code examples
javascriptarraysfilterp5.jssplice

p5.js Array: Multiple Objects getting Spliced instead of Single


I'm trying to create a moving array of decorative circles, and as soon as a circle moves off the edge of the screen I would like to remove it from the array. I have tried both splicing and filtering from the array – however, as soon as I do this, all the circles in the array get deleted, instead of just the intended one. Checked multiple sources and tried different thinkgs but I simply can't figure out what's going wrong. You can have a look at the demo here in the p5.js editor: https://editor.p5js.org/devalladares/sketches/v6bWAiISM

Main code here if it helps:

function setup() {

   //Create new Circle
   for (let i = 0; i < circleNumber; i++) {
     circles.push(new createCircle())
   }
 }

 function draw() {

   for (let i = circles.length - 1; i >= 0; i--) {

     circles[i].update(i * 200)

     //This is the problem: Simply cannot figure it out

     //Splicing

     if (circles[i].isDead()) {
       circles.splice(i, 1)
     }
   }

   //Filtering
   // circles = circles.filter(x => !x.isDead())
 }

//Class to create Circle

class createCircle {

   constructor() {
     this.circle = []
       this.origin = i * gap + emptySpace2
     this.pos = 0
     this.xPos = width / 5
     this.create()
   }

   create() {
     for (let i = 0; i < ringNumber; i++) {
       this.circle.push(new circleRing())
     }
   }

   update(dist) {

     push()
     this.xPos -= xSpeed
     this.pos = this.xPos + dist / 1.8

     translate(this.pos, this.origin / 1.15)
     scale(0.6, 0.6)

     for (let circles of this.circle) {
       circles.update()
     }
     pop()
   }

   isDead() {
     if (this.pos < 40) {
       return true;
     } else {
       return false;
     }
   }
 }

Thanks in advance!!


Solution

  • Your issue isn't the most obvious thing in the world, but it comes from your for-loop and how you're updating your circles' x positions:

    for (let i = circles.length - 1; i >= 0; i--) {
         circles[i].update(i * 200)
    

    When you delete a circle, the subsequent circles all shift down one index in your array, meaning if you delete the circle at index 0, the circle at index 1 now becomes the circle at index 0, which when you apply your cricles[i].update(i * 200) in the next call to draw(), i*200 will evaluate to 0, which causes your circle to shift into the "kill zone".

    Instead, you store an internal circleNum property in your circles when you create them, and adjust your position based on that:

    class createCircle {
      constructor(circleNum) {
        this.circle = [];
        this.pos = 0;
        this.xPos = width / 5;
        this.circleNum = circleNum;
        this.create();
      }
      ...
    }
    

    Then when you create your circle, pass in the index:

    //Create new Circle
    for (let i = 0; i < circleNumber; i++) {
      circles.push(new createCircle(i))
    }
    

    also, change how you call .update():

    circles[i].update(200);
    

    and lastly, use circleNum when calculating the new pos (as circleNum will remain consistent unlike i):

    this.pos = this.xPos + (this.circleNum*dist) / 1.8;