// The Nature of Code
// <http://www.shiffman.net/teaching/nature>
// Spring 2010
// PBox2D example
// A fixed boundary class (now incorporates angle)
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_, float angle) {
x = x_;
y = y_;
w = w_;
h = h_;
// Figure out the box2d coordinates
float box2dW = box2d.scalarPixelsToWorld(w/2);
float box2dH = box2d.scalarPixelsToWorld(h/2);
Vec2 center = new Vec2(x,y);
// Define the polygon
PolygonDef sd = new PolygonDef();
sd.setAsBox(box2dW, box2dH);
sd.density = 0; // No density means it won't move!
sd.friction = 0.3f;
// Create the body
BodyDef bd = new BodyDef();
bd.position.set(box2d.coordPixelsToWorld(center));
bd.angle = angle;
b = box2d.createBody(bd);
b.createShape(sd);
}
// Draw the boundary, if it were at an angle we'd have to do something fancier
void display() {
fill(0);
rectMode(CENTER);
float a = b.getAngle();
pushMatrix();
translate(x,y);
rotate(-a);
rect(0,0,w,h);
popMatrix();
}
}
// The Nature of Code
// <http://www.shiffman.net/teaching/nature>
// Spring 2010
// PBox2D example
// A rectangular box
class Box {
// We need to keep track of a Body and a width and height
Body body;
float w;
float h;
int col;
int notMovedCnt;
Vec2 pos,lastPos;
// Constructor
Box(float x, float y,float ww,float hh) {
w = ww;
h = hh;
// Add the box to the box2d world
makeBody(new Vec2(x,y),w,h);
col=UColorTool.interpolate(random(1),"FF0099","FF6600");
}
// 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
if(lastPos!=null && dist(lastPos.x,lastPos.y,pos.x,pos.y)<0.1)
notMovedCnt++;
else notMovedCnt=0;
// Does it not move? Kill if we've deleted <5 this frame
if (notMovedCnt>100 && deletedThisFrame<5) {
deletedThisFrame++;
killBody();
return true;
}
if (pos.y > height+w) {
killBody();
return true;
}
return false;
}
// Drawing the box
void display() {
// We look at each body and get its screen position
lastPos=pos;
pos = box2d.getBodyPixelCoord(body);
// Get its angle of rotation
float a = body.getAngle();
if(drawTrails) {
stroke(col, 50);
if(lastPos!=null) line(pos.x,pos.y,
lastPos.x,lastPos.y);
noFill();
ellipse(pos.x,pos.y,w,w);
return;
}
rectMode(CENTER);
pushMatrix();
translate(pos.x,pos.y);
rotate(-a);
fill(col);
stroke(0);
ellipse(0,0,w,w);
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)
PolygonDef sd = new PolygonDef();
CircleDef cd= new CircleDef();
cd.radius=box2d.scalarPixelsToWorld(w/2);
float box2dW = box2d.scalarPixelsToWorld(w_/2);
float box2dH = box2d.scalarPixelsToWorld(h_/2);
sd.setAsBox(box2dW, box2dH);
// Parameters that affect physics
cd.density = 1.0f;
cd.friction = 0.3f;
cd.restitution = 0.5f;
// Define the body and make it from the shape
BodyDef bd = new BodyDef();
bd.position.set(box2d.coordPixelsToWorld(center));
body = box2d.createBody(bd);
body.createShape(cd);
body.setMassFromShapes();
// Give it some initial random velocity
body.setLinearVelocity(new Vec2(random(-5,5),random(2,5)));
body.setAngularVelocity(random(-5,5));
}
}
void buildBoundaries() {
boundaries = new ArrayList<Boundary>();
w=step;
float nx=(int)((float)width/w);
float ny=(int)((float)height/w);
float xd=(float)width/nx;
float yd=(float)height/ny;
float angle=0,lastAngle,diff;
for(float y=0; y<ny; y++) {
for(float x=0; x<nx; x++) {
// make sure an angle doesn't repeat immediately
lastAngle=angle;
do {
angle=60*(int)random(6);
diff=abs(angle-lastAngle);
// println(x+" "+y+" "+diff +" "+((180-diff)<10));
} while(diff<10 || (180-diff)<10);
boundaries.add(
new Boundary((x+0.5)*xd,(y+0.5)*yd, w*0.75,3, radians(angle+15)));
}
}
}
USimpleGUI gui;
void initGUI() {
gui=new USimpleGUI(this);
step=100;
gui.addSlider("step",step,40,400);
gui.addButton("reinit");
gui.addToggle("drawTrails",drawTrails);
gui.setLayout(false);
}
public void reinit() {
trailFrameCnt=0;
box2d = new PBox2D(this);
box2d.createWorld();
// We are setting a custom gravity
box2d.setGravity(0, -25);
boxes = new ArrayList<Box>();
buildBoundaries();
}
/**
* UPhysicsBox2D03.pde - Marius Watz, 2012
* http://workshop.evolutionzone.com
*
* Creates a maze of boundaries for particles to
* bounce off. Has semi-smart logic for detecting and
* removing stuck elements.
*
* Code for Boundary and Box are taken from Daniel
* Shiffman's "Boxes" demo, with some modifications.
*
*/
import controlP5.*;
import unlekker.util.*;
import pbox2d.*;
import org.jbox2d.collision.shapes.*;
import org.jbox2d.common.*;
import org.jbox2d.dynamics.*;
// Box2D instance
PBox2D box2d;
ArrayList<Boundary> boundaries;
ArrayList<Box> boxes;
public float step,w; // step size of barrier grid
public float nx,ny; // resolution of barrier grid
long lastDropped;
int deletedThisFrame=0;
public boolean drawTrails=false;
int trailFrameCnt=0;
void setup() {
size(800,600);
smooth();
initGUI();
reinit();
}
void draw() {
// update box2d
box2d.step();
// used to make sure we only kill one static piece
// per frame
deletedThisFrame=0;
if(!drawTrails || trailFrameCnt==0) {
// draw everything normally
background(255);
// show boundaries
for (Boundary wall: boundaries) {
wall.display();
}
}
if(drawTrails) trailFrameCnt++;
else trailFrameCnt=0;
// draw boxes
for (Box b: boxes) {
b.display();
}
removeDeadBoxes();
// handle continous mousePressed
if(mousePressed) mousePressed();
rectMode(CORNER);
gui.draw();
}
// once they are "done" (i.e. they are off screen),
// boxes can be deleted
void removeDeadBoxes() {
// note that we are deleting elements as we go, so the
// value of boxes.size()will change on the fly
for (int i = 0; i<boxes.size(); i++) {
Box b = boxes.get(i);
if (b.done()) boxes.remove(b);
}
// reset notMovedCnt if an element has been deleted
if(deletedThisFrame>0)
for(Box b:boxes) b.notMovedCnt=0;
}
void mousePressed() {
if(gui.isMouseOver()) return;
// 30 msec time constraint on dropping new elements
if((millis()-lastDropped)>30) {
float r=step*random(1,5)/10;
Box p = new Box(mouseX,mouseY,r,r);
boxes.add(p);
lastDropped=millis();
}
}
PBox2D demo. Creates a maze of boundaries for particles to bounce off. Has timeout logic for detecting and removing stuck elements. Toggle "drawTrails" to see the trails of elements as they move through the grid.
Code for Boundary and Box are taken from Daniel Shiffman's "Boxes" demo, with some modifications.