If you're seeing this message, it means we're having trouble loading external resources on our website.

If you're behind a web filter, please make sure that the domains *.kastatic.org and *.kasandbox.org are unblocked.

Main content

A single particle

Before we can create an entire ParticleSystem, we have to create an object that will describe a single particle. The good news: we've done this already. Our Mover object from the Forces section serves as the perfect template. For us, a particle is an independent body that moves about the screen. It has location, velocity, and acceleration, a constructor to initialize those variables, and functions to display() itself and update() its location.
// A simple Particle object
var Particle = function(position) {
  this.acceleration = new PVector();
  this.velocity = new PVector();
  this.position = position.get();
};

Particle.prototype.update = function(){
  this.velocity.add(this.acceleration);
  this.position.add(this.velocity);
};

Particle.prototype.display = function() {
  stroke(0, 0, 0);
  fill(175, 175, 175);
  ellipse(this.position.x, this.position.y, 8, 8);
};
This is about as simple as a particle can get. From here, we could take our particle in several directions. We could add an applyForce() method to affect the particle’s behavior (we’ll do precisely this in a future example). We could add variables to describe color and shape, or use image() to draw the particle. For now, however, let’s focus on adding just one additional detail: lifespan.
Typical particle systems involve something called an emitter. The emitter is the source of the particles and controls the initial settings for the particles, location, velocity, etc. An emitter might emit a single burst of particles, or a continuous stream of particles, or both. The point is that for a typical implementation such as this, a particle is born at the emitter but does not live forever. If it were to live forever, our program would eventually grind to a halt as the number of particles increased to an unwieldy number over time. As new particles are born, we need old particles to die. This creates the illusion of an infinite stream of particles, and the performance of our program does not suffer.
There are many different ways to decide when a particle dies. For example, it could come into contact with another object, or it could simply leave the screen. For our first Particle object, however, we’re simply going to add a timeToLive property. It will act as a timer, counting down from 255 to 0, at which point we'll consider the particle to be "dead." And so we expand the Particle object as follows:
// A simple Particle object
var Particle = function(position) {
  this.acceleration = new PVector();
  this.velocity = new PVector();
  this.position = position.get();
  this.timeToLive = 255;
};

Particle.prototype.update = function(){
  this.velocity.add(this.acceleration);
  this.position.add(this.velocity);
  this.timeToLive -= 2;
};

Particle.prototype.display = function() {
  stroke(255, 255, 255, this.timeToLive);
  fill(127, 127, 127, this.timeToLive);
  ellipse(this.position.x, this.position.y, 8, 8);
};
The reason we chose to start the timeToLive at 255 and count down to 0 is for convenience. With those values, we can use timeToLive as the alpha transparency for the ellipse as well. When the particle is “dead” it will also have faded away onscreen.
With the addition of the timeToLive property, we’ll also need one additional method—a function that can be queried (for a true or false answer) as to whether the particle is alive or dead. This will come in handy when we are writing the ParticleSystem object, whose task will be to manage the list of particles themselves. Writing this function is pretty easy; it just needs to return true if the value of timeToLive is less than 0.
Particle.prototype.isDead = function() {
  return this.timeToLive < 0;
};
Before we get to the next step of making many particles, it’s worth taking a moment to make sure our particle works correctly and create a sketch with one single Particle object. Here is the full code below, with two small additions. We add a convenience method called run() that simply calls both update() and display() for us. In addition, we give the particle a random initial velocity as well as a downward acceleration (to simulate gravity).
Now that we have an object to describe a single particle, we’re ready for the next big step. How do we keep track of many particles, when we can’t ensure exactly how many particles we might have at any given time?

Want to join the conversation?

  • leafers ultimate style avatar for user Ethan Bierlein
    Why cant the Particle.prototype.isDead function just return a boolean value, like this,
    Particle.prototype.isDead = function() {
    return this.timeToLive <= 0;
    }

    instead of having a series of uneeded if statements?
    (28 votes)
    Default Khan Academy avatar avatar for user
  • leafers seed style avatar for user Noah Schwartz
    Just curious, what does this.position = position.get(); do?
    (7 votes)
    Default Khan Academy avatar avatar for user
    • spunky sam blue style avatar for user Dalendrion
      PVector.get() creates a copy of the vector object.
      Then that copy is assigned to the position of the particle.

      So the particle now has a position with the same values, but it can be changed independently.
      If you didn't use get() to make a copy, then you would not be able to change one position without also changing the other. Too bad KA doesn't teach why.
      (12 votes)
  • male robot hal style avatar for user lennons
    step 3 im getting "Make sure you also change the leaf's angular velocity and acceleration when it hits the ground! "
    now ive applied it to the draw , update, display, im not sure where im going wrong?
    if(this.position.y < height){
    this.velocity.set(0,0);
    this.acceleration.set(0,0);
    }
    (5 votes)
    Default Khan Academy avatar avatar for user
    • ohnoes default style avatar for user Cyan Wind
      Does this.position.y < height mean that the leaf have not still hit the ground yet?

      By the way, according to the hint, you should change angular velocity and angular acceleration of the leaf. It should stop moving or rotating when hitting the ground.
      (7 votes)
  • aqualine ultimate style avatar for user wchargin
    For step two on the challenge: I've tried using
    if (leaves[i].position.y >= height) {
    leaves[i].position.y = height;
    leaves[i].velocity.y = 0;
    leaves[i].acceleration = new PVector();
    }

    in a couple of variations: using height - 40; using > instead of >=; placing in the draw function at the top, at the bottom, in its own loop; placing in Particle.prototype.update using this; etc. These all work: the leaves pile up at the bottom, but I'm not getting credit by the autograder. Any tips?
    (3 votes)
    Default Khan Academy avatar avatar for user
  • hopper jumping style avatar for user Susan Labadorf
    The autoGrader doesn't accept my changes in step one:
    var ds =[];
    mouseClicked=function(){
    ds.push( new Particle(new PVector(mouseX,mouseY)));
    };
    draw = function() {
    background(194, 231, 255);
    tree.display();
    for(var i=0;i<ds.length;i++){
    ds[i].run();
    }
    };

    Thanks in advance!
    (4 votes)
    Default Khan Academy avatar avatar for user
  • male robot hal style avatar for user yogesh kumar
    what is the difference between these three:
    var v1 = new PVector(0,1);
    var v2 = v1; ...............................(1)
    var v2 = v1.get(); .......................(2) &
    var v2;
    v2.set(v1); ...............................(3)
    (3 votes)
    Default Khan Academy avatar avatar for user
    • old spice man green style avatar for user Bob Lyon
      1.
      var v1 = new PVector(12, 5);
      var v2 = new PVector(12, 5);
      println(v2 === v1);
      We see that v1 and v2 are separate objects as witnessed by the equality operator ===, where as
      var v1 = new PVector(12, 5);
      var v2 = v1;
      println(v2 === v1);
      show us that v1 and v2 refer to the same object. In the latter case, if you modify v2 then v1 will also show that modification.

      2.
      var v1 = new PVector(3, 4);
      var v2 = v1.get();
      The get method returns a new PVector. So v1 and v2 are separate objects that have the same property values, like in the first case of example one.

      3.
      var v1 = new PVector(8, 15);
      var v2;
      v2.set(v1);
      will fail since v2 is undefined and as such has no set method. Try
      var v1 = new PVector(8, 15);
      var v2 = new PVector();
      v2.set(v1);
      to make the separate objects v1 and v2 have the same property values as in the first case of example one.
      (7 votes)
  • primosaur ultimate style avatar for user Bliz
    I need help, in the next challenge, on step one. I am writing the next code:
    mouseClicked = function (){
    leaves.push(new Particle(new PVector(mouseX, mouseY)));
    };
    draw = function() {
    background(194, 231, 255);
    tree.display();
    for (var i=0;i<leaves.length;i++){
    leaves[i].run();
    }

    };

    It is working, leaves are falling, but the "beaver" don't pass me into the next part of the challenge. What is wrong, please someone can help me?
    (3 votes)
    Default Khan Academy avatar avatar for user
  • male robot hal style avatar for user Madd Sam
    Why, all of the sudden, you have to include "new PVector" as part of the position argument. Did I miss something along the way?
    What about a simple
    var Particle = function(x,y) {
    this.acceleration = new PVector(0, 0.05);
    this.velocity = new PVector(random(0, 1), random(0, 0));
    this.position = new PVector(x,y);
    };

    mouseClicked = function(){

    var particle = (new Particle(mouseX,mouseY));
    leaves.push(particle);
    };
    (2 votes)
    Default Khan Academy avatar avatar for user
    • aqualine ultimate style avatar for user Max Zhao
      That works just fine as well too. (Perhaps if you wanted to specify initial velocity for the particle as well, using new Particle(x, y, vx, vy) is less desirable compared to new Particle(new PVector(x, y), new PVector(vx, vy)), because the latter groups together it's components together more clearly)
      (3 votes)
  • hopper cool style avatar for user Sandybeaches2002
    i need help on the next challenge... i looked in the comments and tried to use what they said, but am still not getting it. here is my code:

    angleMode = "radians";

    var Particle = function(position) {
    this.acceleration = new PVector(0, 0.05);
    this.velocity = new PVector(random(0, 1), random(0, 0));
    this.position = position;
    };

    Particle.prototype.run = function() {
    this.update();
    this.display();
    };

    Particle.prototype.update = function(){
    this.velocity.add(this.acceleration);
    this.position.add(this.velocity);
    };

    Particle.prototype.display = function() {
    image(getImage("avatars/leaf-green"), this.position.x, this.position.y, 40, 40);
    };

    var Tree = function(position, options) {
    this.position = position.get();
    this.branchingFactor = 3;
    this.angleBetweenBranches = 32;
    this.scaleFactor = 0.7;
    this.numLevels = 4;
    this.baseBranchLength = 120;
    };

    Tree.prototype.display = function() {
    var self = this;

    var forward = function(distance) {
    line(0, 0, 0, -distance);
    translate(0, -distance);
    };

    var back = function(distance) {
    forward(-distance);
    };

    var right = function(angle) {
    rotate(angle * PI / 180);
    };

    var left = function(angle) {
    right(-angle);
    };

    var drawTree = function(depth, length) {
    if (depth === 0) {
    image(getImage("avatars/leaf-green"), -10, -30, 40, 40);
    return;
    }
    var totalAngle = self.angleBetweenBranches * (self.branchingFactor - 1);

    strokeWeight(depth*5);
    forward(length);
    right(totalAngle / 2.0);
    for (var i = 0; i < self.branchingFactor; i += 1) {
    drawTree(depth - 1, length * self.scaleFactor);
    left(self.angleBetweenBranches);
    }
    right(totalAngle / 2.0 + self.angleBetweenBranches);
    back(length);
    };

    pushMatrix();
    translate(this.position.x, this.position.y);
    stroke(122, 112, 85);
    drawTree(this.numLevels, this.baseBranchLength);
    popMatrix();
    };

    var leaves = [];
    var tree = new Tree(new PVector(width/2, 400));
    mouseClicked = function(){
    ds.push( new Particle(new PVector(mouseX,mouseY)));
    };

    draw = function() {
    background(194, 231, 255);
    tree.display();
    for(var i = 0; i < leaves.length; i++) {
    var fall = leaves[i];

    };
    (3 votes)
    Default Khan Academy avatar avatar for user
    • starky ultimate style avatar for user Swara Patil
      You are on the right track, you want to call the various methods on leaves[i] or fall (since that's the variable you have used to store leaves[i]) such as fall.display(), fall.run(), fall.update(). Also, you want to push the new particle values into the null leaves array or else when you call these methods on the leaves[i], it will be empty and nothing will happen.
      (1 vote)
  • duskpin tree style avatar for user Judith Verdonck
    In the next challenge, even though the grader lets me pass all steps, I can't make it so the leaves stop at the bottom of the screen while rotating during their fall. I think it's because I'm rotating the grid, so my
    if (leaf.position.y > height - 30)
    isn't checking the bottom of the screen anymore, but wherever that y is while being rotated, but I can't find how to make it so that the leaf rotates and still hits the bottom, lying still.

    My code (I left out the Tree object):
    angleMode = "radians";

    var Particle = function(position) {
    this.acceleration = new PVector(0, 0.05);
    this.velocity = new PVector(random(0, 1), random(0, 0));
    this.position = position;

    this.angle = 0;
    this.aVelocity = 0;
    this.aAcceleration = 0.0005;
    };

    Particle.prototype.run = function() {
    this.update();
    this.display();
    };

    Particle.prototype.update = function(){
    this.velocity.add(this.acceleration);
    this.position.add(this.velocity);

    this.aVelocity += this.aAcceleration;
    this.angle += this.aVelocity;
    };

    Particle.prototype.display = function() {
    pushMatrix();
    rotate(this.angle);
    image(getImage("avatars/leaf-green"), this.position.x, this.position.y, 40, 40);
    popMatrix();
    };
    var leaves = [];
    var tree = new Tree(new PVector(width/2, 400));


    mouseClicked = function() {
    var particle = new Particle(new PVector(mouseX, mouseY));
    leaves.push(particle);
    };

    draw = function() {
    background(194, 231, 255);
    tree.display();
    for (var i = 0; i < leaves.length; i++) {
    var leaf = leaves[i];
    leaf.run();
    if (leaf.position.y >= height - 30) {
    leaf.acceleration.set(0, 0);
    leaf.velocity.set(0, 0);
    resetMatrix();
    leaf.aAcceleration = 0;
    leaf.aVelocity = 0;
    }
    }
    };
    (3 votes)
    Default Khan Academy avatar avatar for user