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.

## Computer programming

### Course: Computer programming>Unit 5

Lesson 8: Particle Systems

# Particle types

Now we're going to use more advanced object-oriented programming techniques like inheritance, so you may want to review Object inheritance from the Intro to JS course and come back. Don't worry, we'll wait!
Feeling good about how inheritance works? Good, because we're going to use inheritance to make different types of `Particle` sub-objects, which share much of the same functionality but also differ in key ways.
Let's review a simplified `Particle` implementation:
``````var Particle = function(position) {
this.acceleration = new PVector(0, 0.05);
this.velocity = new PVector(random(-1, 1), random(-1, 0));
this.position = position.get();
};

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

Particle.prototype.update = function(){
};

Particle.prototype.display = function() {
fill(127, 127, 127);
ellipse(this.position.x, this.position.y, 12, 12);
};``````
Next, we create a new object type based on `Particle`, which we'll call `Confetti`. We'll start off with a constructor function that accepts the same number of arguments, and simply calls the `Particle` constructor, passing them along:
``````var Confetti = function(position) {
Particle.call(this, position);
};``````
Now, in order to make sure that our `Confetti` objects share the same methods as `Particle` objects, we need to specify that their prototype should be based on the `Particle` prototype:
``````Confetti.prototype = Object.create(Particle.prototype);
Confetti.prototype.constructor = Confetti;``````
At this point, we have `Confetti` objects that act exactly the same way as `Particle` objects. The point of inheritance isn't to make duplicates, it's to make new objects that share a lot of functionality but also differ in some way. So, how is a `Confetti` object different? Well, just based on the name, it seems like it should look different. Our `Particle` objects are ellipses, but confetti is usually little bits of square paper, so at the very least, we should change the `display` method to show them as rectangles instead:
``````Confetti.prototype.display = function(){
rectMode(CENTER);
fill(0, 0, 255, this.timeToLive);
stroke(0, 0, 0, this.timeToLive);
strokeWeight(2);
rect(0, 0, 12, 12);
};``````
Here's a program with one `Particle` object instance and one `Confetti` object instance. Notice they behave similarly but differ in their appearance:

Let’s make this a bit more sophisticated. Let’s say we want to have the `Confetti` particle rotate as it flies through the air. We could, of course, model angular velocity and acceleration as we did in the Oscillations section. Instead, we’ll try a quick and dirty solution.
We know a particle has an `x` location somewhere between 0 and the width of the window. What if we said: when the particle’s `x` location is 0, its rotation should be 0; when its `x` location is equal to the width, its rotation should be equal to `TWO_PI`? Sound familiar? Whenever we have a value with one range that we want to map to another range, we can use the ProcessingJS `map()` function to easily compute the new value.
``var theta = map(this.position.x, 0, width, 0, TWO_PI);``
And just to give it a bit more spin, we can actually map the angle’s range from 0 to `TWO_PI*2`. Let’s look at how this code fits into the `display()` method.
``````Confetti.prototype.display = function(){
rectMode(CENTER);
fill(0, 0, 255);
stroke(0, 0, 0);
strokeWeight(2);
pushMatrix();
translate(this.position.x, this.position.y);
var theta = map(this.position.x, 0, width, 0, TWO_PI * 2);
rotate(theta);
rect(0, 0, 12, 12);
popMatrix();
};``````
Here's how that looks - restart it a few time to see the effect of the rotation:
We could also base the theta on the `y` position, which has a bit of a different effect. Why is that? Well, the particle has a non-zero constant acceleration in the `y` direction, which means that the `y` velocity is a linear function of time, and that the `y` position is actually a parabolic function of time. You can see what that means in the graphs below (which were generated based on the above program):
Three graphs of position (a line arcing down), velocity (a straight line from the top to bottom), and acceleration (a straight line).
That means that if we base the confetti rotation on the `y` position, the rotation will also be parabolic. This won't be too physically accurate since the actual rotation of confetti falling through the air is pretty complicated, but try it yourself and see how realistic it looks! Can you think of other functions which might look even more realistic?

### A diverse ParticleSystem

Now, what we really want is to be able to create many `Particle` objects and many `Confetti` objects. That's what we made the `ParticleSystem` object for, so perhaps we can just extend it to also keep track of `Confetti` objects? Here's one way we could do that, copying what we did for the `Particle` objects:
``````var ParticleSystem = function(position) {
this.origin = position;
this.particles = [];
this.confettis = [];
};

this.particles.push(new Particle(this.origin));
this.confettis.push(new Confetti(this.origin));
};

ParticleSystem.prototype.run = function(){
for (var i = this.particles.length-1; i >= 0; i--) {
var p = this.particles[i];
p.run();
}
for (var i = this.confettis.length-1; i >= 0; i--) {
var p = this.confettis[i]; p.run();
}
};``````
Notice that we have two separate arrays, one for particles and one for confetti. Every time we do something to the particles array, we have to do it to the confetti array! That's annoying, because it means we have to write twice as much code, and if we change something, we have to change it in two places. We could actually avoid this duplication, because we're allowed to store objects of different types in arrays in JavaScript, and because our objects have the same interface - we're calling the `run()` method, and both types of objects define that interface. So, we'll go back to just storing a single array, we'll randomly decide what type of particle object to add, and we'll go back to iterating through the single array. This is a much simpler change - all we end up modifying is the `addParticle` method:
``````var ParticleSystem = function(position) {
this.origin = position;
this.particles = [];
};

var r = random(1);
if (r < 0.5) {
this.particles.push(new Particle(this.origin));
} else {
this.particles.push(new Confetti(this.origin));
}
};

ParticleSystem.prototype.run = function(){
for (var i = this.particles.length-1; i >= 0; i--) {
var p = this.particles[i];
p.run();
this.particles.splice(i, 1);
}
}
};``````
All together now!

## Want to join the conversation?

• what does ` Confetti.prototype.constructor = Confetti;` do ?
i tried to remove it and it still works. • So confetti has a much greater surface area than a particle, and a greater drag coefficient. Therefore, I would expect it would fall a little slower. Since confetti inherits the particle constructor where acceleration is set, how do I use a different random() statement to generate a different acceleration?

This is a broadly focused question asked on a specific item, but applies in many situations, I would think. • What does `Particle.call(this, position);` do, literally? • I'm stuck on step one of Magical Cauldron. Can someone tell me what the mistake is in my code?

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

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

Particle.prototype.update = function(){
this.timeToLive -= 2;
};

Particle.prototype.display = function() {
stroke(0, 0, 0, this.timeToLive);
strokeWeight(2);
fill(255, 0, 0, this.timeToLive);
ellipse(this.position.x, this.position.y, 12, 12);
};

if (this.timeToLive < 0) {
return true;
} else {
return false;
}
};

var Smoke = function(position){
this.position = position.get();
};
Smoke.prototype.constructor = Smoke;

Smoke.prototype = Object.create(Particle.prototype);

Smoke.prototype.display = function(){
var size = random(10, 40);
noStroke();
fill(217, 204, 204);
ellipse(this.position.x, this.position.y, size, size);
};

var ParticleSystem = function(position) {
this.origin = position.get();
this.particles = [];
};

this.particles.push(new Particle(this.origin));
};

ParticleSystem.prototype.run = function(){
for (var i = this.particles.length-1; i >= 0; i--) {
var p = this.particles[i];
p.run();
this.particles.splice(i, 1);
}
}
};

var particleSystem = new ParticleSystem(new
PVector(width/2, 280));

draw = function() {
background(72, 7, 105);
particleSystem.run();

// The magical cauldron
fill(36, 36, 36);
var cauldronX1 = 150;
var cauldronX2 = 250;
var cauldronY = 285;
bezier(cauldronX1, cauldronY,
cauldronX1-100, cauldronY+145,
cauldronX2+100, cauldronY+145,
cauldronX2, cauldronY);
}; • I can't satisfy grader's requirements at step 4. I have a random generated size variable, i pass this variable as width and height to imageFunctions. There are no errors, but grader do not accept this.

var Star = function(position){
Particle.call(this, position);
this.size = random(10)+10;
};

Star.prototype = Object.create(Particle.prototype);

Star.prototype.display = function() {
image(getImage("cute/Star"),this.position.x, this.position.y, this.size, this.size);
}; • Wouldn't it be more efficient to have a "datablock" variable for each particle type?
That way, you wouldn't need to store the gravity value and other constants separately in each particle. Something like this, keeping Particle.acceleration in case you want more forces:
``var ParticleDB = {    gravity: new PVector(0, 0.05)};var Particle = function(position) {    this.datablock = ParticleDB;    this.acceleration = new PVector(0, 0);    this.velocity = new PVector(random(-1, 1), random(-1, 0));    this.position = position.get();};Particle.prototype.update = function() {    this.acceleration.add(this.datablock.gravity);    this.velocity.add(this.acceleration);    this.position.add(this.velocity);    this.acceleration.set(0, 0);};var Confetti = function(position) {    Particle.call(this, position);    datablock = ParticleDB;};``

Just hard-coding the gravity into Particle.update() or using a regular global variable (`var gravity = new PVector(0, 0.05);`) would be better for this example where both particle types fall at the same speed and don't have unique physics, but wouldn't this be better than what they did in the example program?

And maybe you could go farther by only having the base Particle code, nothing like Confetti, and put the code for individual particle types in the datablocks too:
``var ParticleDB = {    gravity: new PVector(0, 0.05),    draw: function() {...}};var ConfettiDB = {    gravity: ParticleDB.gravity, // want speed to be the same    draw: function() {...}};``

The question is, which of these three ways is best? • In the next challenge, why does Oh noes guy always say : "p.run is not a function". I am so confused • On Step 1 of Magical Cauldron, I did exactly as the lesson showed, but it's not letting me pass. What else do I need to do?
(1 vote) • We use following statements to base functionality of one object to another.
``Confetti.prototype = Object.create(Particle.prototype);``
``Confetti.prototype.constructor = Confetti;``
Could somebody explain & deconstruct the above statements? In the next challenge I just used
``Stars.prototype = Object.create(Particle.prototype);``
& it worked fine without use of 2nd statement. Why so?
(1 vote) • How did you get the rectangles to rotate by themselves on their own "axle"
(1 vote) 