Nature of Code: Final

This is my final for Nature of Code, an evolution of my semester’s work playing with balloons and physics engines. It was created using Box2D, and I’m excited by the future possibilities of this balloon system as a game.

Here is the app, and my code is pasted below.

http://itp.nyu.edu/~mll331/noc/NoC_Final/

 

// The Nature of Code
// Matt London Balloon Platforms

import pbox2d.*;
import org.jbox2d.collision.shapes.*;
import org.jbox2d.common.*;
import org.jbox2d.dynamics.*;
import org.jbox2d.dynamics.joints.*;
import org.jbox2d.collision.shapes.Shape;
import org.jbox2d.dynamics.contacts.*;

// A reference to our box2d world
PBox2D box2d;

// A list we'll use to track fixed objects
ArrayList<Boundary> boundaries;
ArrayList<Orb> orbs;

Box b1;
//Orb o1;

int numOrb;

void setup() {
  size(1280, 720);
  numOrb = 0;
  // Initialize box2d physics and create the world
  box2d = new PBox2D(this);
  box2d.createWorld();
  // We are setting a custom gravity
  box2d.setGravity(0, -100);

  // Create ArrayLists
  b1 = new Box(150, height-55);

  boundaries = new ArrayList<Boundary>();

  // Add a bunch of fixed boundaries
  boundaries.add(new Boundary(width/2, height-5, width, 10));
  boundaries.add(new Boundary(width/2, 5, width, 10));
  boundaries.add(new Boundary(5, height/2, 10, height));
  boundaries.add(new Boundary(width-5, height/2, 10, height));
  boundaries.add(new Boundary(width-50, height-50, 20, 150));
  boundaries.add(new Boundary(width-200, height-50, 20, 150));
  boundaries.add(new Boundary(width/4, height/2+100, 20, 500));
  boundaries.add(new Boundary(width/2, height/2-100, 20, 400));
  boundaries.add(new Boundary(width/4+width/2, height/2+100, 20, 500));
  boundaries.add(new Boundary(width/2, height/4, width/8, 10));
}

void draw() {
  background(255);

  // We must always step through time!
  box2d.step();

  Vec2 pos1 = box2d.getBodyPixelCoord(b1.body);
  Vec2 wind = new Vec2(0, 3000);

  // Display all the boxes
  b1.display(); 

  if (numOrb >= 1){
    for (Orb o: orbs){
      o.applyForce(wind);
//      if(!o.done()){
        o.display();
//      }
     }
  }

  // Display all the boundaries
  for (Boundary wall: boundaries) {
    wall.display();
  }
}

void mousePressed() {
    //for(Orb o: orbs){
      if(numOrb > 0){
    for (int i = numOrb; i > 0; i--){
      if(orbs.get(i-1).contains(mouseX, mouseY)){
//        orbs.get(i).c = 0;
        orbs.remove(i-1);
        numOrb--;
      }
    }
      }
  if (b1.contains(mouseX, mouseY)) {
    createOrb();
  }
}

void createOrb() {
  if(numOrb == 0){
      orbs = new ArrayList<Orb>();
  }
  numOrb++;
  Orb o = new Orb(b1, mouseX, mouseY-100);
  orbs.add(o);
  }

  void keyPressed(){
    Vec2 wRight = new Vec2(500, 0);
    Vec2 wLeft = new Vec2(-500, 0);
    if(keyPressed = true){
      if(keyCode == SHIFT){
        //setup();
        orbs.clear();
        numOrb = 0;
      } else if (keyCode == RIGHT){
          if (numOrb >= 1){
    for (Orb o: orbs){
      o.applyForce(wRight);
        o.display();
    }
          }
      } else if (keyCode == LEFT){
          if (numOrb >= 1){
    for (Orb o: orbs){
      o.applyForce(wLeft);
        o.display();
    }
          }
      }
    }
  }

// The Nature of Code
// Daniel Shiffman
// http://natureofcode.com

// A fixed boundary class

class Boundary {

  // A boundary is a simple rectangle with x,y,width,and height
  float x;
  float y;
  float w;
  float h;

  // But we also have to make a body for box2d to know about it
  Body b;

  Boundary(float x_,float y_, float w_, float h_) {
    x = x_;
    y = y_;
    w = w_;
    h = h_;

    // Define the polygon
    PolygonShape sd = new PolygonShape();
    // Figure out the box2d coordinates
    float box2dW = box2d.scalarPixelsToWorld(w/2);
    float box2dH = box2d.scalarPixelsToWorld(h/2);
    // We're just a box
    sd.setAsBox(box2dW, box2dH);

    // Create the body
    BodyDef bd = new BodyDef();
    bd.type = BodyType.STATIC;
    bd.position.set(box2d.coordPixelsToWorld(x,y));
    b = box2d.createBody(bd);

    // Attached the shape to the body using a Fixture
    b.createFixture(sd,1);
  }

  // Draw the boundary, if it were at an angle we'd have to do something fancier
  void display() {
    fill(0);
    stroke(0);
    rectMode(CENTER);
    rect(x,y,w,h);
  }

}

// The Nature of Code
// Daniel Shiffman
// http://natureofcode.com

// A rectangular box
class Box {

  // We need to keep track of a Body and a width and height
  Body body;
  float w;
  float h;

  // Constructor
  Box(float x, float y) {
    w = 200;
    h = w/4;
    // Add the box to the box2d world
    makeBody(new Vec2(x, y), w, h);
  }

  // This function removes the particle from the box2d world
  void killBody() {
    box2d.destroyBody(body);
  }

  // Is the particle ready for deletion?
  boolean done() {
    // Let's find the screen position of the particle
    Vec2 pos = box2d.getBodyPixelCoord(body);
    // Is it off the bottom of the screen?
    if (pos.y > height+w*h) {
      killBody();
      return true;
    }
    return false;
  }

  void applyForce(Vec2 force) {
    Vec2 pos = body.getWorldCenter();
    body.applyForce(force, pos);
  }

  boolean contains(float x, float y) {
    Vec2 worldPoint = box2d.coordPixelsToWorld(x, y);
    Fixture f = body.getFixtureList();
    boolean inside = f.testPoint(worldPoint);
    return inside;
  }

  // Drawing the box
  void display() {
    // We look at each body and get its screen position
    Vec2 pos = box2d.getBodyPixelCoord(body);
    // Get its angle of rotation
    float a = body.getAngle();

    rectMode(CENTER);
    pushMatrix();
    translate(pos.x, pos.y);
    rotate(-a);
    fill(175);
    stroke(0);
    rect(0, 0, w, h);
    popMatrix();
  }

  // This function adds the rectangle to the box2d world
  void makeBody(Vec2 center, float w_, float h_) {

    // Define a polygon (this is what we use for a rectangle)
    PolygonShape sd = new PolygonShape();
    float box2dW = box2d.scalarPixelsToWorld(w_/2);
    float box2dH = box2d.scalarPixelsToWorld(h_/2);
    sd.setAsBox(box2dW, box2dH);

    // Define a fixture
    FixtureDef fd = new FixtureDef();
    fd.shape = sd;
    // Parameters that affect physics
    fd.density = 1;
    fd.friction = 0.3;
    fd.restitution = 0.2;

    // Define the body and make it from the shape
    BodyDef bd = new BodyDef();
    bd.type = BodyType.DYNAMIC;
    bd.position.set(box2d.coordPixelsToWorld(center));
    bd.angularDamping = 1.0;
    //bd.angle = random(TWO_PI);

    body = box2d.createBody(bd);
    body.createFixture(fd);
  }
}

// The Nature of Code
// Daniel Shiffman
// http://natureofcode.com

// A rectangular box
class Orb {

  // We need to keep track of a Body and a width and height
  Body body;
  DistanceJoint dj;
  float w;
  float h;
  int c = 200;

  // Constructor
  Orb(Box bx, float x, float y) {
    w = 30;
    h = 45;
    // Add the box to the box2d world
    makeBody(new Vec2(x, y), w, h);

    Vec2 orbpos = box2d.coordPixelsToWorld(x, y+h/2);

    Vec2 boxpos = box2d.coordPixelsToWorld(mouseX, mouseY);
    DistanceJointDef djd = new DistanceJointDef();
    djd.initialize( bx.body, body, boxpos, orbpos);

    //djd.bodyA = b1.body;
    //djd.bodyB = o1.body;
    //djd.length = box2d.scalarPixelsToWorld(200);
    //djd.frequencyHz = 1;
    //djd.dampingRatio = .1;
    dj = (DistanceJoint) box2d.world.createJoint(djd);
  }

  // This function removes the particle from the box2d world
  void killBody() {
    box2d.destroyBody(body);
  }

  // Is the particle ready for deletion?
  boolean done() {
    // Let's find the screen position of the particle
    Vec2 pos = box2d.getBodyPixelCoord(body);
    // Is it off the bottom of the screen?
    if (pos.y > height+w*h) {
      killBody();
      return true;
    }
    return false;
  }

  void applyForce(Vec2 force) {
    Vec2 pos = body.getWorldCenter();
    body.applyForce(force, pos);
  }

  boolean contains(float x, float y) {
    Vec2 worldPoint = box2d.coordPixelsToWorld(x, y);
    Fixture f = body.getFixtureList();
    boolean inside = f.testPoint(worldPoint);
    return inside;
  }

  // Drawing the box
  void display() {
    // We look at each body and get its screen position
    Vec2 pos = box2d.getBodyPixelCoord(body);
    // Get its angle of rotation
    float a = body.getAngle();

    rectMode(CENTER);
    pushMatrix();
    translate(pos.x, pos.y);
    rotate(-a);
    fill(c, 0, 0);
    stroke(0);
    ellipse(0, 0, w, h);
    popMatrix();

    Vec2 pos1 = new Vec2(0, 0);
    dj.getAnchorA(pos1);
    Vec2 pos2 = new Vec2(0, 0);
    dj.getAnchorB(pos2);
    pos1 = box2d.coordWorldToPixels(pos1);
    pos2 = box2d.coordWorldToPixels(pos2);

    // Display the chain
    stroke(0);
    strokeWeight(2);
    line(pos1.x, pos1.y, pos2.x, pos2.y);
  }

  // This function adds the rectangle to the box2d world
  void makeBody(Vec2 center, float w_, float h_) {

    // Define a polygon (this is what we use for a rectangle)
    PolygonShape sd = new PolygonShape();
    float box2dW = box2d.scalarPixelsToWorld(w_/2);
    float box2dH = box2d.scalarPixelsToWorld(h_/2);
    sd.setAsBox(box2dW, box2dH);

    // Define a fixture
    FixtureDef fd = new FixtureDef();
    fd.shape = sd;
    // Parameters that affect physics
    fd.density = 0.1;
    fd.friction = 0.3;
    fd.restitution = 0.2;

    // Define the body and make it from the shape
    BodyDef bd = new BodyDef();
    bd.type = BodyType.DYNAMIC;
    bd.position.set(box2d.coordPixelsToWorld(center));
    //bd.angle = random(TWO_PI);

    body = box2d.createBody(bd);
    body.createFixture(fd);
  }
}

Nature of Code: Week Two — Balloon Game!

I wanted to create a real game that used balloon anti-gravity physics and collision detection. The result is this fun little maze, where, if you make a wrong turn, you’re trapped!

The one thing I wasn’t able to figure out had to do with frameRate and the collisions. I created a gap window where if the balloon hit the barriers it would bounce off. But if the balloon is moving too fast it will pass the entire barrier in one frame and the game glitches. I’m not sure how to fix this.

Code below, but you can also see it on my link for BALLOON GAME

//NoC_Class02_Homework_BalloonGame
// by Matt London

Balloon b;
String s = "Use the 'a' and 's' keys to navigate\n the balloon through the maze.";

int numBarrier;
Barrier[] barrier;

float dirWind;

void setup() {
  size(700, 700);
  b = new Balloon();
  dirWind = 0.0;
  numBarrier = 22;
  barrier = new Barrier[numBarrier];
  barrier[0] = new Barrier(width/2-29, height-470, 60, 399, 100);
  barrier[1] = new Barrier(width/2+70, height-170, 500, 100, 100);
  barrier[2] = new Barrier(width/2+70, height-360, 100, 150, 100);
  barrier[3] = new Barrier(width/2+210, height-360, 100, 150, 100);
  barrier[4] = new Barrier(width/2+70, height-450, 240, 50, 100);
  barrier[5] = new Barrier(width/2+110, height-550, 500, 100, 100);
  barrier[6] = new Barrier(width/2+192, height-690, 120, 100, 100);
  barrier[7] = new Barrier(width/2+10, height-690, 140, 100, 100);
  barrier[8] = new Barrier(width/2+10, height-640, 60, 130, 100);
  barrier[9] = new Barrier(width/2-230, height-890, 100, 100, 100);
  barrier[10] = new Barrier(70, height-170, 50, 300, 100);
  barrier[11] = new Barrier(width/2, height-690, 350, 50, 100);
  barrier[12] = new Barrier(70, height-170, 210, 100, 100);
  barrier[13] = new Barrier(70, height-360, 100, 150, 100);
  barrier[14] = new Barrier(210, height-360, 110, 150, 100);
  barrier[15] = new Barrier(70, height-450, 210, 50, 100);
  barrier[16] = new Barrier(120, height-550, 200, 100, 100);
  barrier[17] = new Barrier(0, height-550, 120, 40, 100);
  barrier[18] = new Barrier(0, height-690, 200, 50, 100);
  barrier[19] = new Barrier(250, height-690, 150, 50, 100);
  barrier[20] = new Barrier(0, 0, 30, height, 100);
  barrier[21] = new Barrier(width/2+30, height-360, 40, 40, 100);
}

void draw() {
  displayBG();
  for (int i = 0; i < numBarrier; i++) {
    barrier[i].display();
  }
  PVector lift = new PVector(0, -0.01); // PVector lift raises the balloon
  b.applyForce(lift);
  PVector wind = new PVector(dirWind, 0);
  b.applyForce(wind);
  b.update();
  b.edges();
  barrierBounce();
  b.display();
  fill(50);
  text(s, width-230, height-50, 300, 100);
}

void keyPressed() {
  if (key == 's') {
    dirWind = 0.1;
  }
  else if (key == 'a') {
    dirWind = -0.1;
  }
  else {
    dirWind = 0;
  }
}

void keyReleased() {
  dirWind = 0;
}

void displayBG() {
  if (b.location.y < 0) {
    background(0, 255, 0);
  }
  else {
    background(255);
  }
}

void barrierBounce() {
  for (int i = 0; i < numBarrier; i++) {
    if (((barrier[i].locY + barrier[i].barH +16) >= (b.location.y)) && ((barrier[i].locY + 50) <= b.location.y)) {
      if (((barrier[i].locX + barrier[i].barW) >= b.location.x - 10) && (b.location.x + 10 >= barrier[i].locX)) {
        b.location.y = (barrier[i].locY + barrier[i].barH +16);
        b.velocity.y *= -0.5;
      }
    }
    if ((barrier[i].locX >= b.location.x) && ((barrier[i].locX - 12) <= b.location.x)) {
      if (((barrier[i].locY + barrier[i].barH) >= b.location.y) && (b.location.y >= barrier[i].locY)) {
        b.location.x = (barrier[i].locX - 12);
        b.velocity.x *= -0.5;
      }
    }
    if (((barrier[i].locX + barrier[i].barW + 12) >= (b.location.x)) && ((barrier[i].locX + barrier[i].barW) <= b.location.x)) {
      if (((barrier[i].locY + barrier[i].barH) >= b.location.y) && (b.location.y >= barrier[i].locY)) {
        b.location.x = (barrier[i].locX + barrier[i].barW + 12);
        b.velocity.x *= -0.5;
      }
    }
    if ((barrier[i].locY >= b.location.y) && ((barrier[i].locY - 12) <= b.location.y)) {
      if (((barrier[i].locX + barrier[i].barW) >= b.location.x) && (b.location.x >= barrier[i].locX)) {
        b.location.y = (barrier[i].locY - 12);
        b.velocity.y *= -0.5;
      }
    }
  }
}

class Balloon {
  PVector location;
  PVector velocity;
  PVector acceleration;

  Balloon() {
    location = new PVector(width/2, height-35);
    velocity = new PVector(0, 0);
    acceleration = new PVector(0, 0);
  }

  void applyForce(PVector force) {
    acceleration.add(force);
  }   

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

  void edges() {
    if (location.x > width-10) {
      location.x = width-10;
      velocity.x *= -0.5;
    }
    if (location.y > height) {
      location.y = height;
      velocity.y *= -0.5;
    }
    if (location.x < 10) {
      location.x = 10;
      velocity.x *= -0.5;
    }
  }

  void display() {
    stroke(0);
    strokeWeight(2);
    fill(255, 0, 0);
    ellipse(location.x, location.y, 20, 30);
    stroke(255);
    fill(255);
    rect(location.x+3, location.y-7, 2, 3, 0);
    stroke(0);
    line(location.x, location.y+15, location.x, location.y+50);
  }
}

class Barrier {
float locX;  // Barrier's x-location
float locY;   // Barrier's y-location
float barW;   // Barrier's width
float barH;   // Barrier's height
float brightness; // barrier's color 

  Barrier(float tempLocX, float tempLocY, float tempBarW, float tempBarH, float tempBright){
    this.locX = tempLocX;
    this.locY = tempLocY;
    this.barW = tempBarW;
    this.barH = tempBarH;
    this.brightness = tempBright;
  }

    void display(){
      stroke(0);
      strokeWeight(2);
      fill(brightness,255,255);
      rect(locX, locY, barW, barH);
    }
  }

 

Nature of Code: Week One

I took the code for a random mover and tried to incorporate as much of what I learned in ICM to it, as a refresher. I added images, sound effects, and basic animation. The fly buzzes around the screen, and at semi-random intervals stops and sits for a random interval, then starts buzzing around again. The coolest thing about it is that using the flyswatter, you can never actually kill the fly. When you try to swat it, it cues the fly to start moving again, even if it is standing still.

I did have several things in this project that I couldn’t figure out, but I hope to explore more in the next week.

- I wanted to get the buzz of the fly to start and stop when the fly was moving and not moving.

- I couldn’t push the counter variable from the Walker object to the main code.

- I couldn’t get the audio files to play properly if cued inside the Walker or Swatter object.

My code:

 

// Nature of Code - Homework - Week 01
// by Matt London
// Images from Google Images
// Audio from FreeSound.org: Users benboncan, qubodup 

import ddf.minim.spi.*;
import ddf.minim.signals.*;
import ddf.minim.*;
import ddf.minim.analysis.*;
import ddf.minim.ugens.*;
import ddf.minim.effects.*;

Walker w;
Swatter s;
Minim minim;
AudioPlayer whoosh;
AudioPlayer buzz;
PImage img;
PImage img1;
PImage img2;
PImage img3;

void setup() {               // Run at start of sketch
  size(800, 600);            // Sets Frame size
  w = new Walker();         // Create a walker object
  s = new Swatter();        // Create a swatter object
  // background(255);          // Sets background color
  frameRate(60);            // Sets the framerate.
  minim = new Minim(this);
  whoosh = minim.loadFile("whoosh.wav");
  buzz = minim.loadFile("buzz.wav");
  img = loadImage("imgTile.jpg");
  img1 = loadImage("fly.png");
  img2 = loadImage("swatterUp.png");
  img3 = loadImage("swatterDown.png");
    buzz.loop();
}

void draw() {                // Runs every loop
  image(img, 0,0);
  // background(255);
  stroke(0);
  // line(0, height-200, width, height-200);
  // Run the walker object
  w.counter();              // Keeps track of how long something...
                            // ...has been happening.
  w.step();                 // Moves the walker object one step
  w.render();               // Displays the walker object on screen
  s.swat();                 // Makes the swatter swat, and the swat sound play.
}

void mousePressed(){
      whoosh.rewind();
      whoosh.play();
}

void stop(){
  whoosh.close();
  buzz.close();
  minim.stop();
  super.stop();
}
class Swatter {
  float x, y;

  Swatter() {
    x = mouseX;
    y = mouseY;

  }
  void swat() {
    if (mousePressed == true) {
      image(img3, mouseX-200, mouseY-200);
    }
    else {
      image(img2, mouseX-200, mouseY-200);
    }
  }

}

class Walker {
  float x, y;
  float tx, ty;
  float theCount;
  float timeMax = 30000;
  float timeMin = 0;
  float landings = 0;
  AudioPlayer buzz;

  Walker() {
    tx = 0;
    ty = 10000;
  }

  void counter() {                   // Times how long bug is flying/landing.
    if ( theCount >= timeMax) {
      theCount = 0;
      // landings = landings + 1;      // DEBUG counts frequency of landings.
      // println(landings);            // DEBUG displays frequency of landings.
    }
    else if (mousePressed == true) {
      theCount = 0;
    }
    else {
      theCount = theCount + random(100);
    }
    // println(theCount);
  }

  void render() {
    stroke(255);
    fill(0);
    //  ellipse(x, y, 20, 20);
    image(img1, x, y);
  }

  void step() {
    if (theCount < timeMax/2) {

      //[full] x- and y-location mapped from noise
      x = map(noise(tx), 0, 1, 0, width);
      y = map(noise(ty), 0, 2, 0, height);
      //[end]

      //[full] Move forward through “time.”
      tx += 0.01;
      ty += 0.01;
      //[end]
    }
    else {
      x = x;
      y = y;
    }
  }
}

Nature of Code: Week 01 from Matt London on Vimeo.

Cooking With Sound: Final

For my final presentation, I created a musical composition device that allows the user to create multi-instrument music in the Unity 3D digital game design interface. By generating numerous pads, or gates, the user is able to create physics objects that pass through or bounce off of these block, which in turn generate the instrument’s tones. The game’s physics engine is what creates rhythm and tempo.

In this example, I used springy blocks to create a perpetual motion machine. This soundscape will play indefinitely, as long as the game is running.

Inspired by Rube Goldberg devices, and musical ball machines popular in children’s museums, like the one in the video below, gave me the original idea for my project.

Here is my attempt at a similar contraption.