This is a verbatim copy of Shiffman’s Example 4.7. We did the extension that Shiffman suggests as Exercise 4.9.
// The Nature of Code
// Daniel Shiffman
// http://natureofcode.com
class Particle {
PVector position;
PVector velocity;
PVector acceleration;
float lifespan;
float mass = 1; // Let's do something better here!
Particle(PVector l) {
acceleration = new PVector(0, 0);
velocity = new PVector(random(-1, 1), random(-2, 0));
position = l.copy();
lifespan = 255.0;
}
void run() {
update();
display();
}
void applyForce(PVector force) {
PVector f = force.copy();
f.div(mass);
acceleration.add(f);
}
// Method to update position
void update() {
velocity.add(acceleration);
position.add(velocity);
acceleration.mult(0);
lifespan -= 2.0;
}
// Method to display
void display() {
stroke(0, lifespan);
strokeWeight(2);
fill(127, lifespan);
ellipse(position.x, position.y, 12, 12);
}
// Is the particle still useful?
boolean isDead() {
if (lifespan < 0.0) {
return true;
} else {
return false;
}
}
}
// A very basic Repeller class
class Repeller {
// Gravitational Constant
float G = 100;
// position
PVector position;
float r = 10;
Repeller(float x, float y) {
position = new PVector(x, y);
}
void display() {
stroke(0);
strokeWeight(2);
fill(175);
ellipse(position.x, position.y, 48, 48);
}
// Calculate a force to push particle away from repeller
PVector repel(Particle p) {
PVector dir = PVector.sub(position, p.position); // Calculate direction of force
float d = dir.mag(); // Distance between objects
dir.normalize(); // Normalize vector (distance doesn't matter here, we just want this vector for direction)
d = constrain(d, 5, 100); // Keep distance within a reasonable range
float force = -1 * G / (d * d); // Repelling force is inversely proportional to distance
dir.mult(force); // Get force vector --> magnitude * direction
return dir;
}
}
class ParticleSystem {
ArrayList<Particle> particles;
PVector origin;
ParticleSystem(PVector position) {
origin = position.copy();
particles = new ArrayList<Particle>();
}
void addParticle() {
particles.add(new Particle(origin));
}
// A function to apply a force to all Particles
void applyForce(PVector f) {
for (Particle p : particles) {
p.applyForce(f);
}
}
void applyRepeller(Repeller r) {
for (Particle p : particles) {
PVector force = r.repel(p);
p.applyForce(force);
}
}
void run() {
for (int i = particles.size()-1; i >= 0; i--) {
Particle p = particles.get(i);
p.run();
if (p.isDead()) {
particles.remove(i);
}
}
}
}
ParticleSystem ps;
Repeller repeller;
void setup() {
size(640, 360);
ps = new ParticleSystem(new PVector(width/2, 50));
repeller = new Repeller(width/2, height/2);
}
void draw() {
background(255);
ps.addParticle();
// Apply gravity force to all Particles
PVector gravity = new PVector(0, 0.1);
ps.applyForce(gravity);
ps.applyRepeller(repeller);
repeller.display();
ps.run();
}