# Objects and Particle Systems

## Plan for Week 9

- Oct 23
- Lecture on particles: force, drag, gravity, bounce
- Activity 1: implement a single particle with random intial velocity pxv, pyv
- Activity 2: add force of gravity
- Activity 3: add bounce off the bottom: pyv becomes -pyv
- Activity 4: add drag force proportional to -pxv*pxv, -pyv*pyv
- Activity 5: change bounce to be not perfectly elastic: pyv becomes -pyv*bounce, where bounce
- Save this sketch for reuse on Friday!

- Oct 24 (Lab) – particle systems, creating particles
- Oct 25
- Lecture on springs
- Activity 1: Implement a fixed object at 100,100, a moveable object at mouseX,mouseY when mouse is pressed, and a spring joining the two points (keep it simple, no objects needed – just use variables).
- Activity 2: If there’s time review spring examples in the notes

- Oct 27
- Lecture on mutual interaction
- Activity 1: Modify the sketch from Monday: turn off gravity, add force inversely proportional to the distance to the mouse, i.e. SCALEFACTOR / max(1, dist(x, y, mouseX, mouseY)), where max(1, …) here prevents the denominator from going to zero, which would make the force “blow up”. forceX should be (mouseX – x)/dist(x, y, mouseX, mouseY) and forceY should be (mouseY – y)/dist(x, y, mouseX, mouseY).
- Activity 2: Watch flocking video and play with sketch demo on that page.

## Why Objects?

Your last encounter with objects may have been “houses as objects”. The point of this was to show that you can create *objects* with multiple properties (such as width, height, color, position, etc.). Grouping properties into objects is much more convenient than managing all the properties separately. For example, if you wanted to “push” a house into an array, it is much simpler to write `houses.push(house)`

than to manage each property separately: `houseWidths.push(houseWidth)`

, `houseHeights.push(houseHeight)`

, `houseColors.push(houseColor)`

, etc.!

Objects allow us to create new abstractions like houses that have a combination of state (properties that serve as per-object variables) and operations (functions).

A key to thinking about objects is to realize there are two points of view: The * user* point of view makes instances of objects and calls object methods to accomplish tasks, e.g.

`flower.draw()`

, not worrying about the details of how the object is implemented. The *point of view is concerned with setting the object properties and creating functions that manipulate these properties or use them, for example, to draw the object. It is best to take one point of view or the other. Thinking of both at once is very confusing.*

**implementer**In standard terminology, a * class* is the definition and implementation for a kind of object. An

*is a particular instance of the class. For example, we say the “class of houses” or “the ‘house’ class” and “this particular ‘house’ object is an instance of the class of houses.”*

**object**Javascript does not have specific syntax for defining a class. You will see different approaches that are conceptually similar but differ in notation. However, Javascript has specific notation for objects, e.g. `{x: 10, y: 50}`

, so we will focus on creating and using objects, and we will minimize the discussion of classes.

## Physics of Particles

Now we will use objects to implement some simple physics: gravity and bouncing. In the next section, we’ll create lots of these objects, attach some graphics and turn them loose.

### Specifications

Our particle objects will model a simple physics simulation. The object contains state representing the x and y coordinates, and the x and y velocities (named `dx`

and `dy`

). (Note: “d” commonly means “delta” which means “change”, so “dx” is the “change in x (at each time step),” thus “dx” is velocity.) At each time step, the object position is updated according to velocity, the velocity is modified to account for `gravity`

(a global), and the velocity is modified to account for drag, which is proportional to velocity squared.

In addition, when the object reaches either the left, right, or bottom edges of the canvas, the object “bounces” with a new velocity scaled by the global named `springy`

.

Using particle objects, we can have many moving and bouncing objects where the details of motion are encapsulated into the properties of the objects themselves.

### Implementation

### Here are definitions for particle objects:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
var gravity = 0.1; // downward acceleration var springy = 0.9; // how much velocity is retained after bounce var drag = 0.0001; // drag causes particles to slow down function particleStep() { this.age++; this.x += this.dx; this.y += this.dy; if (this.x > width) { // bounce off right wall this.x = width - (this.x - width); this.dx = -this.dx * springy; } else if (this.x < 0) { // bounce off left wall this.x = -this.x; this.dx = -this.dx * springy; } if (this.y > height) { // bounce off bottom this.y = height - (this.y - height); this.dy = -this.dy * springy; } else if (this.y < 0) { // bounce off top this.y = -this.y; this.dy = -this.dy * springy; } this.dy = this.dy + gravity; // force of gravity // drag is proportional to velocity squared // which is the sum of the squares of dy and dy var vs = Math.pow(this.dx, 2) + Math.pow(this.dy, 2); // d is the ratio of old velocty to new velocity var d = vs * drag; // d goes up with velocity squared but can never be // so high that the velocity reverses, so limit d to 1 d = min(d, 1); // scale dx and dy to include drag effect this.dx *= (1 - d); this.dy *= (1 - d); } function particleDraw() { point(this.x, this.y); } // create a "Particle" object with position and velocity function makeParticle(px, py, pdx, pdy) { p = {x: px, y: py, dx: pdx, dy: pdy, age: 0, step: particleStep, draw: particleDraw } return p; } |

Notice how `makeParticle`

makes an object: We use the `{`

to initialize properties, creating a new object each time *property*: *value*, *property*: *value*, ...}*makeParticle* is called.

Two of the properties, `step`

and `draw`

, are initialized to *functions* (not your typical values!). This lets us, for example, draw a particle by writing `someParticle.draw()`

. The draw property is initialized to `particleDraw`

,so it is `particleDraw`

that is actually called. Within `particleDraw`

, the keyword `this`

refers to the object that “contains” the function. In this case, `this`

means whatever object is stored in the variable `someParticle`

.

When a function is a property and called using the syntax like `someParticle.draw()`

, the object is implicitly passed to the function as a formal parameter named `this`

.

The most complex method here is `step`

. You should be able to understand this method by reading the comments.

## Particle Systems

Now, we can put the particle objects to work by creating a particle system. In the first example, we just launch np particles in random directions from the center of the canvas and draw them as they move:

```
var gravity = 0.1; // downward acceleration
var springy = 0.9; // how much velocity is retained after bounce
var drag = 0.0001; // drag causes particles to slow down
var np = 100; // how many particles
function particleStep() {
this.age++;
this.x += this.dx;
this.y += this.dy;
if (this.x > width) { // bounce off right wall
this.x = width - (this.x - width);
this.dx = -this.dx * springy;
} else if (this.x < 0) { // bounce off left wall
this.x = -this.x;
this.dx = -this.dx * springy;
}
if (this.y > height) { // bounce off bottom
this.y = height - (this.y - height);
this.dy = -this.dy * springy;
} else if (this.y < 0) { // bounce off top
this.y = -this.y;
this.dy = -this.dy * springy;
}
this.dy = this.dy + gravity; // force of gravity
// drag is proportional to velocity squared
// which is the sum of the squares of dy and dy
var vs = Math.pow(this.dx, 2) + Math.pow(this.dy, 2);
// d is the ratio of old velocty to new velocity
var d = vs * drag;
// d goes up with velocity squared but can never be
// so high that the velocity reverses, so limit d to 1
d = min(d, 1);
// scale dx and dy to include drag effect
this.dx *= (1 - d);
this.dy *= (1 - d);
}
function particleDraw() {
point(this.x, this.y);
}
// create a "Particle" object with position and velocity
function makeParticle(px, py, pdx, pdy) {
p = {x: px, y: py,
dx: pdx, dy: pdy,
age: 0,
step: particleStep,
draw: particleDraw
}
return p;
}
var particles = [];
function setup() {
createCanvas(400, 400);
for (var i = 0; i < np; i++) {
// make a particle
var p = makeParticle(200, 200,
random(-50, 50), random(-50, 50));
// push the particle onto particles array
particles.push(p);
}
frameRate(10);
}
function draw() {
background(230);
stroke(0);
strokeWeight(10);
for (var i = 0; i < np; i++) { // for each particle
var p = particles[i];
p.step();
p.draw();
}
}
```

Note that `setup`

creates `np`

objects, and `draw`

calls the `step`

and `draw`

methods on each particle to implement the simulation of particle motion.

## Mouse Particles

The following variation adds particles to the system when the mouse is pressed. Particles start at the mouse position with random velocities. After 200 steps, the particles are removed from the list of particles so that the number does not grow too big as we continue adding particles with the mouse.

mouseparticles – click the mouse in the canvas to create new particles

```
var gravity = 0.3; // downward acceleration
var springy = 0.7; // how much velocity is retained after bounce
var drag = 0.0001; // drag causes particles to slow down
var np = 100; // how many particles
function particleStep() {
this.age++;
this.x += this.dx;
this.y += this.dy;
if (this.x > width) { // bounce off right wall
this.x = width - (this.x - width);
this.dx = -this.dx * springy;
} else if (this.x < 0) { // bounce off left wall
this.x = -this.x;
this.dx = -this.dx * springy;
}
if (this.y > height) { // bounce off bottom
this.y = height - (this.y - height);
this.dy = -this.dy * springy;
} else if (this.y < 0) { // bounce off top
this.y = -this.y;
this.dy = -this.dy * springy;
}
this.dy = this.dy + gravity; // force of gravity
// drag is proportional to velocity squared
// which is the sum of the squares of dy and dy
var vs = Math.pow(this.dx, 2) + Math.pow(this.dy, 2);
// d is the ratio of old velocty to new velocity
var d = vs * drag;
// d goes up with velocity squared but can never be
// so high that the velocity reverses, so limit d to 1
d = min(d, 1);
// scale dx and dy to include drag effect
this.dx *= (1 - d);
this.dy *= (1 - d);
}
function particleDraw() {
point(this.x, this.y);
}
// create a "Particle" object with position and velocity
function makeParticle(px, py, pdx, pdy) {
p = {x: px, y: py,
dx: pdx, dy: pdy,
age: 0,
step: particleStep,
draw: particleDraw
}
return p;
}
var particles = [];
function setup() {
createCanvas(400, 400);
for (var i = 0; i < np; i++) {
// make a particle
var p = makeParticle(200, 200,
random(-50, 50), random(-50, 50));
// push the particle onto particles array
particles.push(p);
}
frameRate(10);
}
// draw all particles in the particles array
//
function draw() {
background(230);
stroke(0);
strokeWeight(10);
if (mouseIsPressed) {
var newp = makeParticle(mouseX, mouseY,
random(-10, 10), random(-10, 0));
particles.push(newp);
}
// newParticles will hold all the particles that we want to
// retain for the next call to draw() -- we will retain particles
// if the age is < 200 (frames). Initially, newParticle is empty
// because we have not found any "young" particles yet.
newParticles = [];
for (var i = 0; i < particles.length; i++) { // for each particle
var p = particles[i];
p.step();
p.draw();
// since we are "looking" at every particle in order to
// draw it, let's use the opportunity to see if particle[i]
// is younger than 200 frames. If so, we'll push it onto the
// end of newParticles.
if (p.age < 200) {
newParticles.push(p);
}
}
// now, newParticles has EVERY particle with an age < 200 frames.
// these are the particles we want to draw next time, so assign
// particles to this new array. The old value of particles, i.e.
// the entire array, is simply "lost" -- Javascript will reclaim
// and reuse the memory since that array is no longer needed.
particles = newParticles;
}
```

Note how “old” particles are gotten rid of: Since we are iterating through all particles, we construct a new list with every particle whose age is less than 200. You might expect a method such as `p.getAge()`

to get the current age of a particle, but here we just access the property directly using the `p.age`

notation. Some frown on this direct access to the inner representation of an object, while others see it as an efficient and largely harmless shortcut. Anyway, after constructing the new list we simply replace the old list with the new one.

Consider the line `particles = newParticles`

. You might expect to see something like `particles[i] = newParticles[i]`

since both variables are arrays. In this case, we are not changing the array referred to by `particles`

. Instead, we are saying that `particles`

no longer refers to that array, and now `particles`

will refer to the new array. After the assignment, `particles`

and `newParticles`

both refer to the same array! However, `newParticles`

was just a temporary variable that allowed us to refer to bothh arrays while we constructed `newParticles`

. We want to forget about the old `particles`

and remember `newParticles`

for the next `draw()`

, hence the assignment.

The “forgotten” `particles`

array is reclaimed by the Javascript runtime system so that the array memory can be reused.