Penny Door
There’s a little door in Doherty that can only be opened with the use of a coin. Coins clank off the sides of the door and each other, giving passerbys hints as to how to get in. Originally, I wanted to do a double projection that had glowing particles slipping in and out of the door, but that would’ve required multiple projectors + connecting multiple sketches together via osc, and I didn’t have the time to work it all out. I ended up having projection issues anyways–the projector I was using was too small and too weak to project onto the space!
I’d love to do more projection mapping work, perhaps next time with a little pico projector + RPi combo. I found it’s ridiculously difficult to line up the projectors, even with Keystone–I’d like to try my hand at computer vision next time.
import ddf.minim.spi.*;
import ddf.minim.signals.*;
import ddf.minim.*;
import ddf.minim.analysis.*;
import ddf.minim.ugens.*;
import ddf.minim.effects.*;
import pbox2d.*;
import org.jbox2d.collision.shapes.*;
import org.jbox2d.common.*;
import org.jbox2d.dynamics.*;
import org.jbox2d.dynamics.contacts.*;
import org.jbox2d.dynamics.joints.*;
import org.jbox2d.collision.shapes.Shape;
PImage penny;
Minim minim;
AudioSample clang;
AudioSample bigClang;
//door size
float door = 60.5 * 5 * 1.5;
float lastHit;
boolean caliDoor;
//box2D world
PBox2D box2d;
//stuff
ArrayList movers;
Boundary[] walls = new Boundary[4];
import deadpixel.keystone.*;
Keystone ks;
CornerPinSurface surface;
PGraphics offscreen;
void setup() {
size(640*2, 360*2, P3D);
ks = new Keystone(this);
surface = ks.createCornerPinSurface(int(640*1.5), int(360*1.5), 20);
offscreen = createGraphics(int(640*1.5), int(360*1.5), P3D);
smooth();
// http://en.wikipedia.org/wiki/Penny_(United_States_coin)
penny = loadImage("2010_cent_obverse.png");
minim = new Minim(this);
// http://www.freesound.org/people/timgormly/sounds/170958/
clang = minim.loadSample("clang.wav", 512);
// http://www.freesound.org/people/DJ%20Chronos/sounds/123587/
bigClang = minim.loadSample("loud_clang.aiff", 512);
box2d = new PBox2D(this);
box2d.createWorld();
box2d.listenForCollisions();
// No global gravity force
box2d.setGravity(0, -2);
movers = new ArrayList ();
for (int i = 0; i < 8; i++) {
movers.add(new Mover(random(30, 60), offscreen.width/2, offscreen.height/2));
}
float cx = offscreen.width/2;
float cy = offscreen.height/2;
walls[0] = new Boundary((cx - door/2), cy, 1, offscreen.height);
walls[1] = new Boundary(cx + door/2, cy, 1, offscreen.height);
walls[2] = new Boundary(cx, cy - door/2, offscreen.width, 1);
walls[3] = new Boundary(cx, cy + door/2, offscreen.width, 1);
}
void draw() {
PVector surfaceMouse = surface.getTransformedMouse();
offscreen.beginDraw();
offscreen.background(0);
// We must always step through time!
box2d.step();
for (Mover m : movers) {
m.display();
}
for (int i = 0; i < 4; i++) {
walls[i].display();
}
if (caliDoor == true) {
offscreen.noFill();
offscreen.strokeWeight(3);
offscreen.stroke(255);
offscreen.rect(width/2, height/2, door, door);
} else {offscreen.stroke(0);}
offscreen.endDraw();
background(0);
surface.render(offscreen);
}
// Collision event functions!
void beginContact(Contact cp) {
clang.trigger();
}
// Objects stop touching each other
void endContact(Contact cp) {
}
void keyPressed() {
switch(key) {
case 'c':
// enter/leave calibration mode, where surfaces can be warped
// and moved
ks.toggleCalibration();
if (caliDoor == false) {
caliDoor = true;
}
else {
caliDoor = false;
}
break;
case 'l':
// loads the saved layout
ks.load();
break;
case 's':
// saves the layout
ks.save();
break;
}
}
// The Nature of Code
//
// Spring 2012
// PBox2D example
// 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);
b.setUserData(this);
}
// Draw the boundary, if it were at an angle we'd have to do something fancier
void display() {
fill(0);
stroke(0);
rectMode(CENTER);
offscreen.rect(x,y,w,h);
}
}
// The Nature of Code
//
// Spring 2011
// PBox2D example
// Showing how to use applyForce() with box2d
class Mover {
// We need to keep track of a Body and a radius
Body body;
float r;
Mover(float r_, float x, float y) {
r = r_;
// Define a body
BodyDef bd = new BodyDef();
bd.type = BodyType.DYNAMIC;
// Set its position
bd.position = box2d.coordPixelsToWorld(x, y);
body = box2d.world.createBody(bd);
// Make the body's shape a circle
CircleShape cs = new CircleShape();
cs.m_radius = box2d.scalarPixelsToWorld(r);
// Define a fixture
FixtureDef fd = new FixtureDef();
fd.shape = cs;
// Parameters that affect physics
fd.density = 0.8;
fd.friction = 0.3;
fd.restitution = 1.1;
body.createFixture(fd);
body.setLinearVelocity(new Vec2(random(-5, 5), random(-5, -5)));
body.setAngularVelocity(random(-1, 1));
}
void applyForce(Vec2 v) {
body.applyForce(v, body.getWorldCenter());
}
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();
offscreen.pushMatrix();
offscreen.translate(pos.x, pos.y);
offscreen.rotate(a);
offscreen.image(penny,-r,-r,r*2, r*2);
offscreen.popMatrix();
}
}