Creating a Particle System in Processing: Beginning with Particle Animation

I have recently decided to take on the task of creating a particle system from scratch designed to work specifically with Processing. I have always been interested in the subject and I wanted to challenge myself and share something with the Processing community. I am going to write this series of articles to document my learning process as well as the evolution of this library.

For this first article, I am going to start with the most basic concepts of dealing with particles in Processing. No differential equations, no numerical methods, just simple linear algebra and Java. This one may be pretty boring to most Processing users, but I want to start off simple to establish a good base of knowledge because it will get pretty hairy later. If you are a complete beginner, I suggest you start here and come back when you have a decent understanding of Processing.

The “Hello World!” of particle physics

The first thing we want to examine is how to draw and move a single particle. First check out this code in action here then come back and closely examine the source:

//particle's screen coordinates
float x, y;
//particle's velocity
//velocity is change in postion
float vx, vy;   

void setup() {
 size(400, 400);
 stroke(0);
 strokeWeight(3);
 fill(150);
 smooth();
 //set position and velocity
 resetParticle();
}

void draw() {
  background(255);

  //draw the particle with diameter of 10
  ellipse(x, y, 10, 10); 

  /*
   * update the position by adding on the velocity
   * remember that velocity means incremental change
   * in position.
   */
  x += vx;
  y += vy;

}

// on a mouse click
void mousePressed() {
  resetParticle();
}

void resetParticle() {
  //reset the particle to the middle of the screen
  x = y = width/2f;    

  //set new random velocity
  // b/w - and + numbers
  vx = random(-0.39, 0.1);
  vy = random(-0.1, 0.21);
}

Let’s quickly dissect what is going on here. First we establish the two floats x and y to be the center point of the particle in screen coordinates. Hopefully you have messed with Processing or computer animation enough to understand screen coordinates. Then we establish vx and vy as the velocity of our particle. As we remember in high school physics, velocity is defined as the change in position over time. In computer animation, our general unit of time is a “frame”. As you should know, the draw() function is called at the framerate that you run the program at [Processing default is 60 times a second I think]. So every time that function is called, we redraw a white background drawing over any previous frames:

background(255);

then we draw the particle as an ellipse at it’s current x, y position:

ellipse(x, y, 10, 10);

then we update the position one time step:

x += vx;
y += vy;

and this is done 60 times a second creating the illusion of motion due to persistence of vision.

Adding Acceleration

You may also remember from your childhood science classes that acceleration is the change in velocity over time. Quickly view this code in action and take note of the now non-uniform speed of the particle:

float x, y;
float vx, vy;
//acceleration
float ax, ay;

void setup() {
 size(400, 400);
 stroke(0);
 strokeWeight(3);
 fill(150);
 smooth();
 //set position and velocity
 resetParticle();
}

void draw() {
  background(255);

  //draw the particle with diameter of 10
  ellipse(x, y, 10, 10); 

   /*
   * update the velocity by adding on the acceleration
   * remember that acceleration means incremental change
   * in velocity.
   */
  vx += ax;
  vy += ay;

  /*
   * update the position by adding on the velocity
   * remember that velocity means incremental change
   * in position.
   */
  x += vx;
  y += vy;

}

// on a mouse click
void mousePressed() {
  resetParticle();
}

void resetParticle() {
  //reset the particle to the middle of the screen
  x = y = width/2f;    

  //set velocity to 0
  vx = vy = 0f;

  ax = random(-0.01, 0.01);
  ay = random(0.003, 0.01);//downward
}

Now that we are adding on the acceleration to the velocity each frame, the velocity increases as time goes on and the particle moves faster and faster. Kind of like gravity (an acceleration of 9.8 m/s2) or a car accelerating faster and faster. Congratulations! We now have the ability to crudely describe Newtonian motion!

Abstraction and Multiple Particles

Now that we can create one particle with ease, let’s create many. Basically what we need to do is create an abstraction of what a particle is then turn that into a Java class. This isn’t a Java lesson and I hope you know what that means so let’s jump straight into it. Check out this program then come back and learn about the code.

Particle[] particles;
int NUM_PARTICLES = 100;

void setup() {
 size(400, 400);
 stroke(0);
 strokeWeight(3);
 fill(150);
 smooth();
}

void draw() {
  background(255);
  if (particles != null) {
    for (int i = 0; i < NUM_PARTICLES; i++) {
      particles[i].exist();
    }
  }
}

void mousePressed() {
  particles = new Particle[NUM_PARTICLES];
  for (int i = 0; i < NUM_PARTICLES; i++) {
    particles[i] = new Particle();
  }
}

public class Particle {
  float x, y;
  float vx, vy;
  float ax, ay;

  public Particle() {
      x = mouseX;
      y = mouseY;
      vx = vy = 0f;
      ax = random(-0.2, 0.2);
      ay = random(-0.08, 0.05);
  }

  public void exist() {
     vx += ax;
     vy += ay;
     x += vx;
     y += vy;
     ellipse(x, y, 10, 10);
  }
}

Of course this is too crazy to resemble anything real in the our physical world, but it shows the point. Basically what we have done is created a Particle class which contains references to it’s own state information. Then we can have an array of Particles and update those in a nice loop. There is still some more improvement that can be done to this though. Let’s talk about vectors.

Vectors

A Vector is essentially a 1 row N column matrix. In computer graphics, we use the Vector data structure to represent multi-dimensional state information such as position, velocity, and acceleration. Because they are matrices and we set them to have the same dimensions, we can use standard matrix operations and concepts from linear algebra to help us solve some of the systems of linear equations we face. Processing contains it’s own implementation of a vector called a “PVector”. It is a 3-dimensional vector so we can represent things in 2d or 3d space. Check out this re-write of the last program in action and I will explain how it works after the code:

ArrayList particles;
int LIFESPAN = 120;
//global gravity
PVector acceleration =  new PVector(0f, 0.025);

void setup() {
 size(400, 400);
 stroke(0);
 strokeWeight(3);
 fill(150);
 smooth();
 particles = new ArrayList();
}

void draw() {
  background(255);
  //only create when mouse moves
  if (abs(mouseX-pmouseX) > 0.0001) {
    particles.add(new Particle());
  }
  for (int i = particles.size()-1; i >= 0; i--) {
    Particle p = (Particle)particles.get(i);
    if(!p.exist()) {
      particles.remove(i);
    }
  }
}

public class Particle {
  PVector location;
  PVector velocity;
  int age;

  public Particle() {
      location = new PVector(mouseX, mouseY);
      //get velocity from direction and speed of mouse movement
      velocity = new PVector(mouseX-pmouseX, mouseY-pmouseY);
      age = 0;
  }

  public boolean exist() {
     velocity.add(acceleration);
     location.add(velocity);
     ellipse(location.x, location.y, 10, 10);
     if (age > LIFESPAN) {
       return false;
     }
     age++;
     return true;
  }

}

Notice that I changed over the x and y variables to the PVectors and this gives us operations like add, subtract, multiply, magnitude, normalize, and etc. Check out this article on matrix math if you don’t remember it from grade school. In this example, all you need to know is that when you add two PVectors, it does a matrix add. I do, however, highly suggest that you get real familiar with matrix math and systems of equations if you want to move on:

velocity.add(acceleration);

//is equivalent to 

velocity.set( acceleration.x+velocity.x,
                    acceleration.y+velocity.y,
                    acceleration.z+velocity.z );

I also moved the acceleration vector out to have global static scope. And I am getting the velocity from the changing mouse positions. Remember that velocity is change in position, so we can get the velocity vector by subtracting the new cursor position from the old.

I don’t really want to go into Java stuff but notice that I also changed the array to an ArrayList. And if you are wondering why I didn’t use a parameterized ArrayList, it is b/c Processing uses a light-weight open source java compiler that doesn’t support it.

Until next time

That is it for now. I hope that wasn’t too boring. In the next article, I am going to talk more about vectors, different kinds of forces. I will also briefly point out the inaccuracies in our integration technique and open up a huge can of maths worms.


Click here to view the next article of this series —>

2 comments ↓

#1 Philipp on 03.12.10 at 9:23 am

nice tutorial, simple but effective. excited about the next part

#2 benjamin on 03.12.10 at 9:47 am

Thanks Phillipp! Hopefully I can get to it by this weekend. It should be soon.

Leave a Comment