I have modified a particle system to create an effect similar to the one that I want. However, with any substantial amount of particles it performs very slowly on my laptop (around 1.7 fps at the worst when I remove the if statement limiting the creation of new particles). I'm guessing that this is because all the work is on the CPU? Can I batch together the processing somehow?
// Based on https://github.com/benjaminmbrown/particle-system-repeller
var Repeller = function(x, y) {
this.power = 500;
this.position = createVector(x, y);
this.display = function() {
stroke(0);
strokeWeight(2);
fill(127);
ellipse(this.position.x, this.position.y, 40, 40);
}
this.repel = function(p) {
var dir = p5.Vector.sub(this.position, p.position);
var d = dir.mag();
dir.normalize(); //just want the direction
d = constrain(d, 1, 100);
var force = -1 * this.power / (d * d);
dir.mult(force);
return dir;
}
}
var Attractor = function(x, y) {
this.power = 150;
this.position = createVector(x, y);
this.display = function() {
stroke(255);
strokeWeight(2);
fill(127);
ellipse(this.position.x, this.position.y, 40, 40);
}
this.attract = function(p) {
var force = p5.Vector.sub(this.position, p.position);
var distance = force.mag();
distance = constrain(distance, 5, 50);
force.normalize();
var strength = 1 * this.power / (distance * distance);
force.mult(strength);
return force;
}
}
function Particle(position, velObj, color) {
this.position = position.copy();
this.acceleration = createVector(0, 0.00);
this.velocity = createVector(random(velObj.xMin, velObj.xMax), random(velObj.yMin, velObj.yMax));
color = color || {r: 0, g: 0, b: 0};
this.lifespan = 255;
this.mass = 5;
this.run = function() {
this.update();
this.display();
}
this.display = function() {
stroke(255, this.lifespan); //gets more transparent as it dies
strokeWeight(2);
fill(color.r, color.g, color.b, this.lifespan);
ellipse(this.position.x, this.position.y, 4, 4);
}
this.update = function() {
this.velocity.add(this.acceleration);
this.position.add(this.velocity);
this.acceleration.mult(0);
this.lifespan -= 1.5;
}
this.isDead = function() {
return this.lifespan < 0.0 ? true : false;
}
this.applyForce = function(force) {
var f = force.copy();
f.div(this.mass);
this.acceleration.add(f);
}
}
function ParticleSystem(num, position, velObj, color) {
this.origin = position.copy();
this.particles = [];
this.run = function() {
for(var i = this.particles.length - 1; i >= 0; i--) {
var p = this.particles[i];
p.run();
if(p.isDead()) {
this.particles.splice(i, 1);
}
}
};
this.applyForce = function(force) {
for(var i = 0; i < this.particles.length; i++) {
this.particles[i].applyForce(force);
}
}
this.applyRepeller = function(r) {
for(var i = 0; i < this.particles.length; i++) {
this.particles[i].applyForce(r.repel(this.particles[i]));
}
}
this.applyAttractor = function(r) {
for(var i = 0; i < this.particles.length; i++) {
this.particles[i].applyForce(r.attract(this.particles[i]));
var p = this.particles[i];
var force = r.attract(p);
p.applyForce(force);
}
}
this.addParticle = function() {
var r = random(1);
this.particles.push(new Particle(this.origin, velObj, color));
};
}
var particleSystems = [];
var repeller, attractor;
function setup() {
createCanvas(windowWidth, windowHeight, WEBGL);
setFrameRate(60);
repeller = new Repeller(0, 0);
leftAttractor = new Attractor(0, height / 2);
rightAttractor = new Attractor(width, height / 2);
particleSystems.push(new ParticleSystem(1, createVector(width / 5, height / 2), {xMin: 0, xMax: 2, yMin: -4, yMax: 4}, {r: 0, g: 0, b: 255}));
particleSystems.push(new ParticleSystem(1, createVector(width * 4 / 5, height / 2), {xMin: -2, xMax: 0, yMin: -4, yMax: 4}, {r: 255, g: 0, b: 0}));
// Ones not affected by attractor
particleSystems.push(new ParticleSystem(1, createVector(width / 5, height / 2), {xMin: -2, xMax: 1, yMin: -2, yMax: 2}, {r: 0, g: 0, b: 255}));
particleSystems.push(new ParticleSystem(1, createVector(width * 4 / 5, height / 2), {xMin: -1, xMax: 2, yMin: -2, yMax: 2}, {r: 255, g: 0, b: 0}));
}
var numDraws = 0;
function draw() {
background(255);
// var gravity = createVector(0.0, 0.1);
translate(-windowWidth / 2, -windowHeight / 2);
for(var i = 0; i < particleSystems.length; i++) {
// particleSystems[i].applyForce(gravity);
particleSystems[i].applyRepeller(repeller);
if(i === 0) {
particleSystems[i].applyAttractor(rightAttractor);
} else if(i === 1) {
particleSystems[i].applyAttractor(leftAttractor);
}
// if(numDraws % 3 === 0 || i < 2)
particleSystems[i].addParticle();
particleSystems[i].run();
}
repeller.display();
numDraws++;
}
function mouseMoved() {
repeller.position = createVector(mouseX, mouseY);
}
function touchMoved() {
repeller.position = createVector(mouseX, mouseY);
}
Any insight as to how to improve this performance is appreciated.