Array releasing particles in specific intervals

Hi,
I have made an array of particles and I initiate the particles in the draw function to get a particle stream.

But what I really want is to release the particles from the array at specific intervals. Like every second or so. The best would be if I could decide how many particles per interval.

I am working with particles attracted by the flowfield. Here is the full code I am working with:

sketch.js

var fr;

var inc = 0.06;
var scl = 33;
var cols, rows;

var zoff = 0;

var start = 0;

var flowfield;

let particles = [];

function setup() {
  createCanvas(800, 800);
  pixelDensity(1);

  cols = floor(width / scl);
  rows = floor(height / scl);
  fr = createP("");

  //particle array
  //  p = new Particle();
  //  for (var i = 0; i < 200; i++) {
  //  particles[i] = new Particle();

  //flowfield array
  flowfield = new Array(cols * rows);
}

function draw() {
  background(20);
  let p = new Particle();
  particles.push(p);
  var yoff = 0;

  for (var y = 0; y < rows; y++) {
    var xoff = 0;
    for (var x = 0; x < cols; x++) {
      var index = x + y * cols;

      var angle = noise(xoff, yoff, zoff) * TWO_PI * 4;
      var v = p5.Vector.fromAngle(angle);
      v.setMag(0.1);

      flowfield[index] = v;

      xoff += inc;
      strokeWeight(2);
      stroke(70, 100, 0);
      push();
      translate(x * scl, y * scl);
      rotate(v.heading());
      line(0, 0, scl, 0);

      pop();
    }
    yoff += inc;

    zoff += 0.000045;
  }

  for (var i = particles.length-1; i >= 0; i--) {
    particles[i].follow(flowfield);
    particles[i].update();
    particles[i].show();
    particles[i].edges();
    if (particles[i].finished()) {
      //remove this particle
      particles.splice(i, 1);
      
    }
  }
}

particle.js

function Particle() {
  this.pos = createVector((mouseX+random(-20,20)),(mouseY+random(-20,20)));
  this.vel = createVector(0.2,2);
  this.acc = createVector(0, 0);
  this.r = 30;
  this.maxspeed = 5;
  this.alpha = 255;
  
  // when alpha less than 0 function is true 
  //for particle delete
  this.finished = function () {
    return this.alpha < 0;
 }
  
  
  this.update = function () {
    this.vel.add(this.acc);
    this.vel.limit(this.maxspeed);
    this.pos.add(this.vel);
    this.acc.mult(0);
    this.alpha -= 1;
  }
  
  

  
  this.follow = function(vectors) {
    var x = floor(this.pos.x / scl);
    var y = floor(this.pos.y / scl);
    var index = x +y * cols;
    var force = vectors[index];
    this.applyForce(force);
  }
  

  this.applyForce = function (force) {
    this.acc.add(force);
  };

  this.show = function () {
    noStroke();
    fill(200, 50, 50, this.alpha);
    circle(this.pos.x, this.pos.y, 10);
  };

  this.edges = function () {
    if (this.pos.x > width) this.pos.x = 0;
    if (this.pos.x < 0) this.pos.x = width;
    if (this.pos.y > height) this.pos.y = 0;
    if (this.pos.y < 0) this.pos.y = height;
  };
}

One praticle every 5 seconds, comments in the code.

var fr;

var inc = 0.06;
var scl = 33;
var cols, rows;

var zoff = 0;

var start = 0;

var flowfield;

let particles = [];

// a var to track elapsed time
let elapsed = 0;

// one for how many particles 
let particles_to_release = 1;

// and one for interval to release
// 1000 = 1seg (milliseconds)
let interval = 5000;

function setup() {
  createCanvas(800, 800);
  pixelDensity(1);

  cols = floor(width / scl);
  rows = floor(height / scl);
  fr = createP("");

  //particle array
  //  p = new Particle();
  //  for (var i = 0; i < 200; i++) {
  //  particles[i] = new Particle();

  //flowfield array
  flowfield = new Array(cols * rows);
  
  //all set, lets reset our timer
  elapsed = millis();
}

function draw() {
  background(20);

  //if current time minus stored is 
  // bigger than interval, release particles
  if (millis() - elapsed > interval) {
    //count released particles and stop after limit
    for (let i = 0; i < particles_to_release; i++) {
      let p = new Particle();
      particles.push(p);
    }
    //reset de clock...
    //voila :)
    elapsed = millis();
  }
  var yoff = 0;

  for (var y = 0; y < rows; y++) {
    var xoff = 0;
    for (var x = 0; x < cols; x++) {
      var index = x + y * cols;

      var angle = noise(xoff, yoff, zoff) * TWO_PI * 4;
      var v = p5.Vector.fromAngle(angle);
      v.setMag(0.1);

      flowfield[index] = v;

      xoff += inc;
      strokeWeight(2);
      stroke(70, 100, 0);
      push();
      translate(x * scl, y * scl);
      rotate(v.heading());
      line(0, 0, scl, 0);

      pop();
    }
    yoff += inc;

    zoff += 0.000045;
  }

  for (var i = particles.length - 1; i >= 0; i--) {
    particles[i].follow(flowfield);
    particles[i].update();
    particles[i].show();
    particles[i].edges();
    if (particles[i].finished()) {
      //remove this particle
      particles.splice(i, 1);
    }
  }
}

A much simpler alternative solution combines frameCount w/ the remainder % operator:

const FPS = 60, FRAMES = 5 * FPS; // 5 seconds of frames elapse (300 frames)
var particles = [];

function draw() {
  // ...

  frameCount % FRAMES || particles.push(new Particle); // 1 new particle each 5s

  // ...
}
2 Likes

perfect thank you, @GoToLoop !

Thanks a lot! This is what I was looking for. Now I tried to implement a lifespan for each particle and implemented your timer into the particle.js but did not succeed. Here is what I did:

sketch.js

var fr;

var inc = 0.04;
var scl = 40;
var cols, rows;

var zoff = 0;

var start = 0;

var flowfield;

let particles = [];

// a var to track elapsed time
let elapsed = 0;

// one for how many particles 
let particles_to_release = 1;

// and one for interval to release
// 1000 = 1seg (milliseconds)
let interval = 500;

function setup() {
  createCanvas(800, 800);
  pixelDensity(1);

  cols = floor(width / scl);
  rows = floor(height / scl);
  fr = createP("");

  //particle array
  //  p = new Particle();
  //  for (var i = 0; i < 200; i++) {
  //  particles[i] = new Particle();

  //flowfield array
  flowfield = new Array(cols * rows);
  
  //all set, lets reset our timer
  elapsed = millis();
}

function draw() {
  background(20);
  
  if (millis() - elapsed > interval) {
  for (let i = 0; i < particles_to_release; i++) {
      let p = new Particle();
      particles.push(p);
    }
    //reset de clock...
    //voila :)
    elapsed = millis();
  }
  
  var yoff = 0;

  for (var y = 0; y < rows; y++) {
    var xoff = 0;
    for (var x = 0; x < cols; x++) {
      var index = x + y * cols;

      var angle = noise(xoff, yoff, zoff) * TWO_PI * 4;
      var v = p5.Vector.fromAngle(angle);
      v.setMag(0.6);

      flowfield[index] = v;

      xoff += inc;
      strokeWeight(2);
      stroke(70, 100, 0);
      push();
      translate(x * scl, y * scl);
      rotate(v.heading());
      line(0, 0, scl, 0);

      pop();
    }
    yoff += inc;

    zoff += 0.000445;
  }

  for (var i = particles.length-1; i >= 0; i--) {
    particles[i].follow(flowfield);
    particles[i].update();
    particles[i].show();
    particles[i].edges();
    
    if (particles[i].finished()) {
      //remove this particle
      particles.splice(i, 1);
      
    }
  }
}

particle.js

// a var to track elapsed time
let particleelapsed = 0;

// and one for interval to release
//1000 = 1seg (milliseconds)
let particleinterval = 100;

function Particle() {
  this.pos = createVector(mouseX + random(-20, 20), mouseY + random(-20, 20));
  this.vel = createVector(0.2, 2);
  this.acc = createVector(0, 0);
  this.r = 30;
  this.maxspeed = 20;
  this.alpha = 255;

  // when alpha less than 0 function is true
  //for particle delete

  //all set, lets reset our timer
  particleelapsed = millis();

  this.finished = function () {
    return this.alpha < 0;
  };

  this.update = function () {
    this.vel.add(this.acc);
    this.vel.limit(this.maxspeed);
    this.pos.add(this.vel);
    this.acc.mult(0);

    if (millis() - particleelapsed > particleinterval) {
      this.alpha -= 10;
    }
    particleelapsed = millis();
  };

  this.follow = function (vectors) {
    var x = floor(this.pos.x / scl);
    var y = floor(this.pos.y / scl);
    var index = x + y * cols;
    var force = vectors[index];
    this.applyForce(force);
  };

  this.applyForce = function (force) {
    this.acc.add(force);
  };

  this.show = function () {
    noStroke();
    fill(200, 50, 50, this.alpha);
    circle(this.pos.x, this.pos.y, 10);
  };

  this.edges = function () {
    if (this.pos.x > width) this.pos.x = 0;
    if (this.pos.x < 0) this.pos.x = width;
    if (this.pos.y > height) this.pos.y = 0;
    if (this.pos.y < 0) this.pos.y = height;
  };
}

Hello @Tilman,

Try a search for time to live in this forum.

:)

You missed the this. in some vars at particle.js so each one would know it’s own timer. And also have reset the timer outside the loop resetting the timer every frame, meaning time never will pass because elapsed is = milli() always.

function Particle() {
  this.pos = createVector(mouseX + random(-20, 20), mouseY + random(-20, 20));
  this.vel = createVector(0.2, 2);
  this.acc = createVector(0, 0);
  this.r = 30;
  this.maxspeed = 20;
  this.alpha = 255;

  this.particleinterval = 100;

  //all set, lets reset our timer
  this.particleelapsed = millis();

  this.finished = function () {
    return this.alpha < 0;
  };

  this.update = function () {
    this.vel.add(this.acc);
    this.vel.limit(this.maxspeed);
    this.pos.add(this.vel);
    this.acc.mult(0);

    if (millis() - this.particleelapsed > this.particleinterval) {
      this.alpha -= 10;
      this.particleelapsed = millis();
    }
  };

  this.follow = function (vectors) {
    var x = floor(this.pos.x / scl);
    var y = floor(this.pos.y / scl);
    var index = x + y * cols;
    var force = vectors[index];
    this.applyForce(force);
  };

  this.applyForce = function (force) {
    this.acc.add(force);
  };

  this.show = function () {
    noStroke();
    fill(200, 50, 50, this.alpha);
    circle(this.pos.x, this.pos.y, 10);
  };

  this.edges = function () {
    if (this.pos.x > width) this.pos.x = 0;
    if (this.pos.x < 0) this.pos.x = width;
    if (this.pos.y > height) this.pos.y = 0;
    if (this.pos.y < 0) this.pos.y = height;
  };
}
1 Like

I’ve got this Countdown class in “countdown.js” file which sets its property done to true after property delay has elapsed via setTimeout():

3 Likes

Thank you @GoToLoop !

This.dot! Thank you @vkbr This fixed it and is working now. Awesome. Thank you!

1 Like