Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merge pull request #8 from ricardoquesada/buoyancy

Buoyancy test
  • Loading branch information...
commit 190f84c1fee4298e6e22cfd9997d0de016397d48 2 parents c19d6d6 + 3641be2
@josephg authored
View
14 cp.js
@@ -708,6 +708,8 @@ var Shape = cp.Shape = function(body) {
Shape.prototype.setElasticity = function(e) { this.e = e; };
Shape.prototype.setFriction = function(u) { this.body.activate(); this.u = u; };
Shape.prototype.setLayers = function(layers) { this.body.activate(); this.layers = layers; };
+Shape.prototype.setSensor = function(sensor) { this.body.activate(); this.sensor = sensor; };
+Shape.prototype.setCollisionType = function(collision_type) { this.body.activate(); this.collision_type = collision_type; };
Shape.prototype.active = function()
{
@@ -965,7 +967,7 @@ SegmentShape.prototype.segmentQuery = function(a, b)
if(ad*bd < 0){
return new SegmentQueryInfo(this, ad/(ad - bd), flipped_n);
}
- } else if(r != 0){
+ } else if(r !== 0){
var info1 = circleSegmentQuery(this, this.ta, this.r, a, b);
var info2 = circleSegmentQuery(this, this.tb, this.r, a, b);
@@ -1487,6 +1489,12 @@ Body.prototype.setVelocity = function(velocity)
this.vy = velocity.y;
};
+Body.prototype.setAngularVelocity = function(w)
+{
+ this.activate();
+ this.w = w;
+};
+
Body.prototype.setAngleInternal = function(angle)
{
assert(!isNaN(angle), "Internal Error: Attempting to set body's angle to NaN");
@@ -1502,7 +1510,7 @@ Body.prototype.setAngle = function(angle)
this.activate();
this.sanityCheck();
this.setAngleInternal(angle);
-}
+};
Body.prototype.velocity_func = function(gravity, damping, dt)
{
@@ -1575,7 +1583,7 @@ Body.prototype.getVelAtWorldPoint = function(point)
Body.prototype.getVelAtLocalPoint = function(point)
{
return this.getVelAtPoint(vrotate(point, body.rot));
-}
+};
Body.prototype.eachShape = function(func)
{
View
4 cp.min.js
2 additions, 2 deletions not shown
View
7 demo/buoyancy.html
@@ -0,0 +1,7 @@
+<canvas></canvas>
+<script src="../cp.js"></script>
+<script src="demo.js"></script>
+<script src="buoyancy.js"></script>
+<script>
+(new Buoyancy()).run();
+</script>
View
177 demo/buoyancy.js
@@ -0,0 +1,177 @@
+var FLUID_DENSITY = 0.00014;
+var FLUID_DRAG = 2.0;
+
+var Buoyancy = function() {
+ Demo.call(this);
+
+ var space = this.space;
+ space.iterations = 30;
+ space.gravity = cp.v(0,-500);
+// cpSpaceSetDamping(space, 0.5);
+ space.sleepTimeThreshold = 0.5;
+ space.collisionSlop = 0.5;
+
+ var staticBody = space.staticBody;
+
+ // Create segments around the edge of the screen.
+ var shape = space.addShape( new cp.SegmentShape(staticBody, cp.v(0,0), cp.v(0,480), 0.0));
+ shape.setElasticity(1.0);
+ shape.setFriction(1.0);
+ shape.setLayers(NOT_GRABABLE_MASK);
+
+ shape = space.addShape( new cp.SegmentShape(staticBody, cp.v(640,0), cp.v(640,480), 0.0));
+ shape.setElasticity(1.0);
+ shape.setFriction(1.0);
+ shape.setLayers(NOT_GRABABLE_MASK);
+
+ shape = space.addShape( new cp.SegmentShape(staticBody, cp.v(0,0), cp.v(640,0), 0.0));
+ shape.setElasticity(1.0);
+ shape.setFriction(1.0);
+ shape.setLayers(NOT_GRABABLE_MASK);
+
+ shape = space.addShape( new cp.SegmentShape(staticBody, cp.v(0,480), cp.v(640,480), 0.0));
+ shape.setElasticity(1.0);
+ shape.setFriction(1.0);
+ shape.setLayers(NOT_GRABABLE_MASK);
+
+ // {
+ // Add the edges of the bucket
+ var bb = new cp.BB(20, 40, 420, 240);
+ var radius = 5.0;
+
+ shape = space.addShape( new cp.SegmentShape(staticBody, cp.v(bb.l, bb.b), cp.v(bb.l, bb.t), radius));
+ shape.setElasticity(1.0);
+ shape.setFriction(1.0);
+ shape.setLayers(NOT_GRABABLE_MASK);
+
+ shape = space.addShape( new cp.SegmentShape(staticBody, cp.v(bb.r, bb.b), cp.v(bb.r, bb.t), radius));
+ shape.setElasticity(1.0);
+ shape.setFriction(1.0);
+ shape.setLayers(NOT_GRABABLE_MASK);
+
+ shape = space.addShape( new cp.SegmentShape(staticBody, cp.v(bb.l, bb.b), cp.v(bb.r, bb.b), radius));
+ shape.setElasticity(1.0);
+ shape.setFriction(1.0);
+ shape.setLayers(NOT_GRABABLE_MASK);
+
+ // Add the sensor for the water.
+ shape = space.addShape( new cp.BoxShape2(staticBody, bb) );
+ shape.setSensor(true);
+ shape.setCollisionType(1);
+ // }
+
+
+ // {
+ var width = 200.0;
+ var height = 50.0;
+ var mass = 0.3*FLUID_DENSITY*width*height;
+ var moment = cp.momentForBox(mass, width, height);
+
+ body = space.addBody( new cp.Body(mass, moment));
+ body.setPos( cp.v(270, 140));
+ body.setVelocity( cp.v(0, -100));
+ body.setAngularVelocity( 1 );
+
+ shape = space.addShape( new cp.BoxShape(body, width, height));
+ shape.setFriction(0.8);
+ // }
+
+ // {
+ width = 40.0;
+ height = width*2;
+ mass = 0.3*FLUID_DENSITY*width*height;
+ moment = cp.momentForBox(mass, width, height);
+
+ body = space.addBody( new cp.Body(mass, moment));
+ body.setPos(cp.v(120, 190));
+ body.setVelocity(cp.v(0, -100));
+ body.setAngularVelocity(1);
+
+ shape = space.addShape(new cp.BoxShape(body, width, height));
+ shape.setFriction(0.8);
+ // }
+
+ space.addCollisionHandler( 1, 0, null, this.waterPreSolve, null, null);
+};
+
+Buoyancy.prototype = Object.create(Demo.prototype);
+
+Buoyancy.prototype.update = function(dt)
+{
+ var steps = 3;
+ dt /= steps;
+ for (var i = 0; i < 3; i++){
+ this.space.step(dt);
+ }
+};
+
+Buoyancy.prototype.waterPreSolve = function(arb, space, ptr) {
+
+ var shapes = arb.getShapes();
+ var water = shapes[0];
+ var poly = shapes[1];
+
+ var body = poly.getBody();
+
+ // Get the top of the water sensor bounding box to use as the water level.
+ var level = water.getBB().t;
+
+ // Clip the polygon against the water level
+ var count = poly.getNumVerts();
+
+ var clipped = [];
+
+ var j=count-1;
+ for(var i=0; i<count; i++) {
+ var a = body.local2World( poly.getVert(j));
+ var b = body.local2World( poly.getVert(i));
+
+ if(a.y < level){
+ clipped.push( a.x );
+ clipped.push( a.y );
+ }
+
+ var a_level = a.y - level;
+ var b_level = b.y - level;
+
+ if(a_level*b_level < 0.0){
+ var t = Math.abs(a_level)/(Math.abs(a_level) + Math.abs(b_level));
+
+ var v = cp.v.lerp(a, b, t);
+ clipped.push(v.x);
+ clipped.push(v.y);
+ }
+ j=i;
+ }
+
+ // Calculate buoyancy from the clipped polygon area
+ var clippedArea = cp.areaForPoly(clipped);
+
+ var displacedMass = clippedArea*FLUID_DENSITY;
+ var centroid = cp.centroidForPoly(clipped);
+ var r = cp.v.sub(centroid, body.getPos());
+
+ var dt = space.getCurrentTimeStep();
+ var g = space.gravity;
+
+ // Apply the buoyancy force as an impulse.
+ body.applyImpulse( cp.v.mult(g, -displacedMass*dt), r);
+
+ // Apply linear damping for the fluid drag.
+ var v_centroid = cp.v.add(body.v, cp.v.mult(cp.v.perp(r), body.w));
+ var k = 1; //k_scalar_body(body, r, cp.v.normalize_safe(v_centroid));
+ var damping = clippedArea*FLUID_DRAG*FLUID_DENSITY;
+ var v_coef = Math.exp(-damping*dt*k); // linear drag
+// var v_coef = 1.0/(1.0 + damping*dt*cp.v.len(v_centroid)*k); // quadratic drag
+ body.applyImpulse( cp.v.mult(cp.v.sub(cp.v.mult(v_centroid, v_coef), v_centroid), 1.0/k), r);
+
+ // Apply angular damping for the fluid drag.
+ var w_damping = cp.momentForPoly(FLUID_DRAG*FLUID_DENSITY*clippedArea, clipped, cp.v.neg(body.p));
+ body.w *= Math.exp(-w_damping*dt* (1/body.i));
+
+ return true;
+};
+Buoyancy.prototype = Object.create(Demo.prototype);
+
+addDemo('Buoyancy', Buoyancy);
+
View
10 lib/cpBody.js
@@ -211,6 +211,12 @@ Body.prototype.setVelocity = function(velocity)
this.vy = velocity.y;
};
+Body.prototype.setAngularVelocity = function(w)
+{
+ this.activate();
+ this.w = w;
+};
+
Body.prototype.setAngleInternal = function(angle)
{
assert(!isNaN(angle), "Internal Error: Attempting to set body's angle to NaN");
@@ -226,7 +232,7 @@ Body.prototype.setAngle = function(angle)
this.activate();
this.sanityCheck();
this.setAngleInternal(angle);
-}
+};
Body.prototype.velocity_func = function(gravity, damping, dt)
{
@@ -299,7 +305,7 @@ Body.prototype.getVelAtWorldPoint = function(point)
Body.prototype.getVelAtLocalPoint = function(point)
{
return this.getVelAtPoint(vrotate(point, body.rot));
-}
+};
Body.prototype.eachShape = function(func)
{
View
4 lib/cpShape.js
@@ -82,6 +82,8 @@ var Shape = cp.Shape = function(body) {
Shape.prototype.setElasticity = function(e) { this.e = e; };
Shape.prototype.setFriction = function(u) { this.body.activate(); this.u = u; };
Shape.prototype.setLayers = function(layers) { this.body.activate(); this.layers = layers; };
+Shape.prototype.setSensor = function(sensor) { this.body.activate(); this.sensor = sensor; };
+Shape.prototype.setCollisionType = function(collision_type) { this.body.activate(); this.collision_type = collision_type; };
Shape.prototype.active = function()
{
@@ -339,7 +341,7 @@ SegmentShape.prototype.segmentQuery = function(a, b)
if(ad*bd < 0){
return new SegmentQueryInfo(this, ad/(ad - bd), flipped_n);
}
- } else if(r != 0){
+ } else if(r !== 0){
var info1 = circleSegmentQuery(this, this.ta, this.r, a, b);
var info2 = circleSegmentQuery(this, this.tb, this.r, a, b);
Please sign in to comment.
Something went wrong with that request. Please try again.