-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
1a948b4
commit 1e4f467
Showing
3 changed files
with
406 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
// usually one would probably make a generic Shape class and subclass different types (circle, polygon), but that | ||
// would mean at least 3 instead of 1 class, so for this tutorial it's a combi-class CustomShape for all types of shapes | ||
// to save some space and keep the code as concise as possible I took a few shortcuts to prevent repeating the same code | ||
class CustomShape { | ||
// to hold the box2d body | ||
Body body; | ||
// to hold the Toxiclibs polygon shape | ||
Polygon2D toxiPoly; | ||
// custom color for each shape | ||
color col; | ||
// radius (also used to distinguish between circles and polygons in this combi-class | ||
float r; | ||
|
||
CustomShape(float x, float y, float r) { | ||
this.r = r; | ||
// create a body (polygon or circle based on the r) | ||
makeBody(x, y); | ||
// get a random color | ||
col = getRandomColor(); | ||
} | ||
|
||
void makeBody(float x, float y) { | ||
// define a dynamic body positioned at xy in box2d world coordinates, | ||
// create it and set the initial values for this box2d body's speed and angle | ||
BodyDef bd = new BodyDef(); | ||
bd.type = BodyType.DYNAMIC; | ||
bd.position.set(box2d.coordPixelsToWorld(new Vec2(x, y))); | ||
body = box2d.createBody(bd); | ||
body.setLinearVelocity(new Vec2(random(-8, 8), random(2, 8))); | ||
body.setAngularVelocity(random(-5, 5)); | ||
|
||
// depending on the r this combi-code creates either a box2d polygon or a circle | ||
if (r == -1) { | ||
// box2d polygon shape | ||
PolygonShape sd = new PolygonShape(); | ||
// toxiclibs polygon creator (triangle, square, etc) | ||
toxiPoly = new Circle(random(5, 20)).toPolygon2D(int(random(3, 6))); | ||
// place the toxiclibs polygon's vertices into a vec2d array | ||
Vec2[] vertices = new Vec2[toxiPoly.getNumPoints()]; | ||
for (int i=0; i<vertices.length; i++) { | ||
Vec2D v = toxiPoly.vertices.get(i); | ||
vertices[i] = box2d.vectorPixelsToWorld(new Vec2(v.x, v.y)); | ||
} | ||
// put the vertices into the box2d shape | ||
sd.set(vertices, vertices.length); | ||
// create the fixture from the shape (deflect things based on the actual polygon shape) | ||
body.createFixture(sd, 1); | ||
} else { | ||
// box2d circle shape of radius r | ||
CircleShape cs = new CircleShape(); | ||
cs.m_radius = box2d.scalarPixelsToWorld(r); | ||
// tweak the circle's fixture def a little bit | ||
FixtureDef fd = new FixtureDef(); | ||
fd.shape = cs; | ||
fd.density = 1; | ||
fd.friction = 0.01; | ||
fd.restitution = 0.3; | ||
// create the fixture from the shape's fixture def (deflect things based on the actual circle shape) | ||
body.createFixture(fd); | ||
} | ||
} | ||
|
||
// method to loosely move shapes outside a person's polygon | ||
// (alternatively you could allow or remove shapes inside a person's polygon) | ||
void update() { | ||
// get the screen position from this shape (circle of polygon) | ||
Vec2 posScreen = box2d.getBodyPixelCoord(body); | ||
// turn it into a toxiclibs Vec2D | ||
Vec2D toxiScreen = new Vec2D(posScreen.x, posScreen.y); | ||
// check if this shape's position is inside the person's polygon | ||
boolean inBody = poly.containsPoint(toxiScreen); | ||
// if a shape is inside the person | ||
if (inBody) { | ||
// find the closest point on the polygon to the current position | ||
Vec2D closestPoint = toxiScreen; | ||
float closestDistance = 9999999; | ||
for (Vec2D v : poly.vertices) { | ||
float distance = v.distanceTo(toxiScreen); | ||
if (distance < closestDistance) { | ||
closestDistance = distance; | ||
closestPoint = v; | ||
} | ||
} | ||
// create a box2d position from the closest point on the polygon | ||
Vec2 contourPos = new Vec2(closestPoint.x, closestPoint.y); | ||
Vec2 posWorld = box2d.coordPixelsToWorld(contourPos); | ||
float angle = body.getAngle(); | ||
// set the box2d body's position of this CustomShape to the new position (use the current angle) | ||
body.setTransform(posWorld, angle); | ||
} | ||
} | ||
|
||
// display the customShape | ||
void display() { | ||
// get the pixel coordinates of the body | ||
Vec2 pos = box2d.getBodyPixelCoord(body); | ||
pushMatrix(); | ||
// translate to the position | ||
translate(pos.x, pos.y); | ||
noStroke(); | ||
// use the shape's custom color | ||
fill(col); | ||
// depending on the r this combi-code displays either a polygon or a circle | ||
if (r == -1) { | ||
// rotate by the body's angle | ||
float a = body.getAngle(); | ||
rotate(-a); // minus! | ||
gfx.polygon2D(toxiPoly); | ||
} else { | ||
ellipse(0, 0, r*2, r*2); | ||
} | ||
popMatrix(); | ||
} | ||
|
||
// if the shape moves off-screen, destroy the box2d body (important!) | ||
// and return true (which will lead to the removal of this CustomShape object) | ||
boolean done() { | ||
Vec2 posScreen = box2d.getBodyPixelCoord(body); | ||
boolean offscreen = posScreen.y > height; | ||
if (offscreen) { | ||
box2d.destroyBody(body); | ||
return true; | ||
} | ||
return false; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
// an extended polygon class quite similar to the earlier PolygonBlob class (but extending Toxiclibs' Polygon2D class instead) | ||
// The main difference is that this one is able to create (and destroy) a box2d body from it's own shape | ||
class PolygonBlob extends Polygon2D { | ||
// to hold the box2d body | ||
Body body; | ||
|
||
// the createPolygon() method is nearly identical to the one presented earlier | ||
// see the Kinect Flow Example for a more detailed description of this method (again, feel free to improve it) | ||
void createPolygon() { | ||
ArrayList<ArrayList<PVector>> contours = new ArrayList<ArrayList<PVector>>(); | ||
int selectedContour = 0; | ||
int selectedPoint = 0; | ||
|
||
// create contours from blobs | ||
for (int n=0 ; n<theBlobDetection.getBlobNb(); n++) { | ||
Blob b = theBlobDetection.getBlob(n); | ||
if (b != null && b.getEdgeNb() > 100) { | ||
ArrayList<PVector> contour = new ArrayList<PVector>(); | ||
for (int m=0; m<b.getEdgeNb(); m++) { | ||
EdgeVertex eA = b.getEdgeVertexA(m); | ||
EdgeVertex eB = b.getEdgeVertexB(m); | ||
if (eA != null && eB != null) { | ||
EdgeVertex fn = b.getEdgeVertexA((m+1) % b.getEdgeNb()); | ||
EdgeVertex fp = b.getEdgeVertexA((max(0, m-1))); | ||
float dn = dist(eA.x*kinectWidth, eA.y*kinectHeight, fn.x*kinectWidth, fn.y*kinectHeight); | ||
float dp = dist(eA.x*kinectWidth, eA.y*kinectHeight, fp.x*kinectWidth, fp.y*kinectHeight); | ||
if (dn > 15 || dp > 15) { | ||
if (contour.size() > 0) { | ||
contour.add(new PVector(eB.x*kinectWidth, eB.y*kinectHeight)); | ||
contours.add(contour); | ||
contour = new ArrayList<PVector>(); | ||
} else { | ||
contour.add(new PVector(eA.x*kinectWidth, eA.y*kinectHeight)); | ||
} | ||
} else { | ||
contour.add(new PVector(eA.x*kinectWidth, eA.y*kinectHeight)); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
while (contours.size() > 0) { | ||
|
||
// find next contour | ||
float distance = 999999999; | ||
if (getNumPoints() > 0) { | ||
Vec2D vecLastPoint = vertices.get(getNumPoints()-1); | ||
PVector lastPoint = new PVector(vecLastPoint.x, vecLastPoint.y); | ||
for (int i=0; i<contours.size(); i++) { | ||
ArrayList<PVector> c = contours.get(i); | ||
PVector fp = c.get(0); | ||
PVector lp = c.get(c.size()-1); | ||
if (fp.dist(lastPoint) < distance) { | ||
distance = fp.dist(lastPoint); | ||
selectedContour = i; | ||
selectedPoint = 0; | ||
} | ||
if (lp.dist(lastPoint) < distance) { | ||
distance = lp.dist(lastPoint); | ||
selectedContour = i; | ||
selectedPoint = 1; | ||
} | ||
} | ||
} else { | ||
PVector closestPoint = new PVector(width, height); | ||
for (int i=0; i<contours.size(); i++) { | ||
ArrayList<PVector> c = contours.get(i); | ||
PVector fp = c.get(0); | ||
PVector lp = c.get(c.size()-1); | ||
if (fp.y > kinectHeight-5 && fp.x < closestPoint.x) { | ||
closestPoint = fp; | ||
selectedContour = i; | ||
selectedPoint = 0; | ||
} | ||
if (lp.y > kinectHeight-5 && lp.x < closestPoint.y) { | ||
closestPoint = lp; | ||
selectedContour = i; | ||
selectedPoint = 1; | ||
} | ||
} | ||
} | ||
|
||
// add contour to polygon | ||
ArrayList<PVector> contour = contours.get(selectedContour); | ||
if (selectedPoint > 0) { Collections.reverse(contour); } | ||
for (PVector p : contour) { | ||
add(new Vec2D(p.x, p.y)); | ||
} | ||
contours.remove(selectedContour); | ||
} | ||
} | ||
|
||
// creates a shape-deflecting physics chain in the box2d world from this polygon | ||
void createBody() { | ||
// for stability the body is always created (and later destroyed) | ||
BodyDef bd = new BodyDef(); | ||
body = box2d.createBody(bd); | ||
// if there are more than 0 points (aka a person on screen)... | ||
if (getNumPoints() > 0) { | ||
// create a vec2d array of vertices in box2d world coordinates from this polygon | ||
Vec2[] verts = new Vec2[getNumPoints()]; | ||
for (int i=0; i<getNumPoints(); i++) { | ||
Vec2D v = vertices.get(i); | ||
verts[i] = box2d.coordPixelsToWorld(v.x, v.y); | ||
} | ||
// create a chain from the array of vertices | ||
ChainShape chain = new ChainShape(); | ||
chain.createChain(verts, verts.length); | ||
// create fixture in body from the chain (this makes it actually deflect other shapes) | ||
body.createFixture(chain, 1); | ||
} | ||
} | ||
|
||
// destroy the box2d body (important!) | ||
void destroyBody() { | ||
box2d.destroyBody(body); | ||
} | ||
} |
Oops, something went wrong.