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);
}
}