• fullscreen
  • Boundary.pde
  • Box.pde
  • UPhysicsBox2D03.pde
  • build.pde
  • gui.pde
  • // 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));
    
      }
    
    }
    
    
    
    
    
    /**
     * 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();
      }
    }
    
    
    
    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();
    }
    

    code

    tweaks (0)

    about this sketch

    This sketch is running as Java applet, exported from Processing.

    license

    advertisement

    Marius Watz plus+

    UPhysicsBox2D03

    Add to Faves Me Likey@! 9
    You must login/register to add this sketch to your favorites.

    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.

    polar
    11 Nov 2012
    Great! Is there a PBox3D for 3D? Then I could make a marble machine with tracks...
    Marius Watz plus+
    27 Nov 2012
    PBox2D is based on the famous Box2D engine, for a 3D version you'd have to look elsewhere.
    You need to login/register to comment.