1

I am trying to create a program where particles generated on the left edge of the canvas get removed from the array (using splice) when they reach the right end of the canvas.

let P = [];
let n = 10;

function setup() 
{
    createCanvas(500,500);
    for(let i = 0; i < n; i++)
        P.push(new particle());
}

function draw() 
{
    background(0);
    for(let i = 0; i < n; i++)
    {
        if(P[i].out == true)
        {
            P.splice(i, 1);
            n--;
        }
        P[i].update();     
        P[i].plot();
        console.log(P.length)
    }   
}

class particle
{
    constructor()
    {
        this.brightness = 0;
        this.vel = random(1);
        this.dia = 3;
        this.x = 0;
        this.y = random(height);
        this.out = false;
    }

    update()
    {
        this.x += this.vel;
        if(this.x >= width)
            this.out = true;
    }

    plot()
    {
        noStroke();
        fill(255);
        circle(this.x, this.y, this.dia);
    }  
}

The program seems to be working fine for the most part when it runs. To make sure the elements in the array are actually being deleted, I tried logging the length of the array. When I run it, the elements get deleted as they reach the right end of the canvas but as the size of the array decreases to about 30% or so (its different every time I run it), I get this error :

Uncaught TypeError: Cannot read property 'update' of undefined

I'm stumped by this because I don't understand how the update function is unable to be read when it has already been used several times in the loop previously.

Rabbid76
  • 202,892
  • 27
  • 131
  • 174
Rumble down
  • 113
  • 4

2 Answers2

2

The issue is, that you remove elements from the array, while you iterate through the array. Note P.splice(i, 1);removes an element from the array if that was the last element in the array, then P[i].update(); access the array out of bounds. That causes the error "Uncaught TypeError: Cannot read property 'update' of undefined"

I recommend to travers the array from the back:
(See also Looping through array and removing items, without breaking for loop)

let i = P.length;
while (i--) {
    if (P[i].out == true) {
        P.splice(i, 1);
        n--;
    } else {
        P[i].update();     
        P[i].plot();
    }
}

See the example:

let P = [];
let n = 10;

function setup() 
{
    createCanvas(500,500);
    for(let i = 0; i < n; i++)
        P.push(new particle());
}

function draw() 
{
    background(0);

    let i = P.length;
    while (i--) {
        if (P[i].out == true) {
            P.splice(i, 1);
        } else {
            P[i].update();     
            P[i].plot();
        }
    }   
}

class particle
{
    constructor()
    {
        this.brightness = 0;
        this.vel = random(1);
        this.dia = 3;
        this.x = 0;
        this.y = random(height);
        this.out = false;
    }

    update()
    {
        this.x += this.vel;
        if(this.x >= width)
            this.out = true;
    }

    plot()
    {
        noStroke();
        fill(255);
        circle(this.x, this.y, this.dia);
    }  
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.0.0/p5.min.js"></script>
Rabbid76
  • 202,892
  • 27
  • 131
  • 174
1

Since you're removing elements from the array, you need to iterate through it backwards:

function draw() {
    background(0);
    for(let i = n - 1; i >= 0; i--) {
        if(P[i].out == true) {
            P.splice(i, 1);
            n--;
        }

        P[i].update();     
        P[i].plot();
        console.log(P.length)
    }   
}
cegredev
  • 1,485
  • 2
  • 11
  • 25