Nature of Code: Forces & Physics

Our homework this week was pretty wild, after going over some pretty epic notes on forces, physics, Newton’s laws, etc.  Here were the suggested exercises for homework:

  • Rework your motion sketch from week 1 using PVector. Try incorporating the concept of forces into the environment by affecting only the acceleration. Create a formula for calculating a dynamic acceleration, one that changes over time based on any number of factors. What happens if you make more than one object via an array.
  • Using forces, simulate a helium-filled balloon floating upward (and bouncing off the top of a window). Can you add a wind force which changes over time, perhaps according to Perlin noise?
  • Create an example where instead of objects bouncing off the edge of the wall, an invisible force pushes back on the objects to keep them in the window. Can you weight the force according to how far the object is from an edge, i.e. the closer it is, the stronger the force?
  • Create pockets of air resistance / friction in a Processing sketch. Try using circles instead of rectangles, i.e. pockets of mud (or ice). What if you vary the strength (drag / friction coefficient) of each circle? What if you make some of them the opposite of drag—i.e., when you enter a given pocket you actually speed up instead of slow down?
  • Can you create an example where all of the Mover objects are attracted to the mouse, but repel each other? Think about how you need to balance the relative strength of the forces and how to most effectively use distance in your force calculations.
  • Research a force not covered in class and implement it as a vector.
  • Use the concept of forces to visualize some input (could be data, literal example would be get windspeed online and translate to a wind force in Processing, but feel free to think more abstractly)
  • Build a sketch that has both “Movers” and “Attractors”. What if you make the Attractors invisible? Can you create a pattern / design from the trails of objects moving around attractors? See the Metropop Denim project by Clayton Cubitt and Tom Carden for an example.

 

The above link is pretty cool.  It shows the possibilities for working with forces, attractors, and particles, combined with the more organic, natural shapes and motions that we’re learning in Nature of Code.  I think I want to start incorporating something like this into my 2D designs.

Prof. Shiffman’s notes from his upcoming Nature of Code book are outstanding.  We’re currently learning how to affect objects using added forces which affect location, acceleration, and velocity with vectors.  So, just this type of code starts to create a more realistic physical environment: [code clipped for brevity]

PVector wind = new PVector(0.001,0);
PVector gravity = new PVector(0,0.1);
m.applyForce(wind);

void applyForce(PVector force) {
  PVector f = PVector.div(force,mass);
  acceleration.add(f);
}

I had already converted my first homework assignment into an array of objects and added some extra forces and reactions for the penguins.  But I also wanted to try some other forces, without delving into some of the homework suggestions that seemed a little too complex right now for me (still need to play with orbits, motion in liquid, etc.).  The sketch I made is just a simple balloon with a random walk floating up, bouncing off the top of the screen.

Sketch is running at OpenProcessing.org, and code is at Github and below the jump:

// Ben Turner
// Nature of Code

// Experimenting with forces and physics.

Mover[] m = new Mover[5];

int numLoops = 0;
float ceilBumpTimeDecay = 0;
float ceilBumpVar = 0.0;
PImage park;

void setup() {
  size(500, 200);
  smooth();
  park = loadImage("park.jpg");
  for (int i=0; i < m.length; i++) {
    m[i] = new Mover();
  }
}

void draw() {
  noStroke();
  fill(255, 200);
  //rect(0, 0, width, height);
  background(park);
  PVector wind = new PVector(0.01, 0);
  PVector gravity = new PVector(0, 0);
  PVector helium = new PVector(0, -0.002);

  for (int i=0; i < m.length; i++) {
     if (m[i].timeLoops != 0) {
       ceilBumpVar = m[i].timeLoops;
       ceilBumpTimeDecay = (ceilBumpVar * 0.001);
       m[i].timeLoops--;
     }
     else {
       ceilBumpTimeDecay = 0.0;
     }
     PVector ceilingBump = new PVector(0, ceilBumpTimeDecay);
     if (mousePressed) {
       m[i].applyForce(wind);
     }
     m[i].display();
     m[i].applyForce(gravity);
     m[i].applyForce(helium);
     m[i].update();
     m[i].checkEdges();
     m[i].timeLoops = m[i].ceilingCollision();
     if (m[i].timeLoops > 0) {
      m[i].applyForce(ceilingBump);
      m[i].timeLoops--;
    }
  }

  if (numLoops > 500) {
    numLoops = 0;
  }
  else {
    numLoops++;
  }
}
class Mover {

  PVector location;
  PVector velocity;
  PVector acceleration;
  float mass;
  float xoff;
  int timeLoops;
  float maxSpeed;
  int r,g,b;
  float randomNoise;

  Mover() {
    location = new PVector(random(width), height-20);
    velocity = new PVector(0,random(0,0.01));
    acceleration = new PVector(0,random(0,0.3));
    mass = 1;
    xoff = 0.0;
    timeLoops = 0;
    maxSpeed = 8;
    randomNoise = random(0.0,0.5);
    r = round(random(255));
    g = round(random(255));
    b = round(random(255));
  }

  void applyForce(PVector force) {
    PVector f = PVector.div(force,mass);
    acceleration.add(f);
  }

  void update() {
    velocity.add(acceleration);
    velocity.limit(maxSpeed);
    location.add(velocity);
    acceleration.mult(0);
  }

  void display() {
    stroke(0);
    fill(r,g,b);
    xoff = xoff + .01;
    float x = location.x + noise(xoff+randomNoise) * 100;
    ellipse(x,location.y,12,19);
    line(x,location.y+10,x+3,location.y+18);
  }

  void checkEdges() {

    if (location.x > width) {
      // location.x = 0;
      velocity.x = velocity.x * -1;
    } else if (location.x < 0) {
       // location.x = width;
       velocity.x = velocity.x * -1;
    }
    if (location.y > height) {
      velocity.y *= -1;
      location.y = height;
    }

    if (location.y < 0) {
      velocity.y *= -.5;
      location.y = 0;
    }

  }

  int ceilingCollision() {
    if (location.y < 0) {
      return timeLoops = 4;
    }
    else {
      return timeLoops = 0;
    }
  }

}