开发者问题收集

p5.j​​s - 无法在程序运行时的随机点读取我的更新函数

2020-04-28
138

我正在尝试创建一个程序,其中在画布左边缘生成的粒子在到达画布右端时会从数组中删除(使用 splice)。

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);
    }  
}

该程序在运行时似乎大部分时间都运行良好。为了确保数组中的元素确实被删除,我尝试记录数组的长度。 当我运行它时,元素在到达画布右端时被删除,但随着数组大小减少到大约 30% 左右(每次运行它时都不同),我收到此错误:

Uncaught TypeError: Cannot read property 'update' of undefined

我对此感到困惑,因为我不明白为什么在之前已经在循环中使用过多次更新函数后无法读取它。

2个回答

问题是,在遍历数组时,您会从数组中删除元素。注意 P.splice(i, 1); 如果元素是数组中的最后一个元素,则会从数组中删除该元素,然后 P[i].update(); 会越界访问数组。这会导致错误 “Uncaught TypeError:无法读取未定义的属性‘update’”

我建议从后面遍历数组:
(另请参阅 循环遍历数组并删除项目,而不中断 for 循环

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

查看示例:

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
2020-04-28

由于您要从数组中删除元素,因此需要向后迭代它:

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
2020-04-28