diff --git a/bodies/Ellipse.js b/bodies/Ellipse.js new file mode 100644 index 0000000..652a3b2 --- /dev/null +++ b/bodies/Ellipse.js @@ -0,0 +1,61 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Owner: david@famo.us + * @license MPL 2.0 + * @copyright Famous Industries, Inc. 2014 + */ + +define(function(require, exports, module) { + var Body = require('./Body'); + var Matrix = require('famous/math/Matrix'); + + /** + * Implements a circle, or spherical, geometry for an Body with + * radius. + * + * @class Circle + * @extends Body + * @constructor + */ + function Circle(options) { + options = options || {}; + this.setRadius(options.radius || 0); + Body.call(this, options); + } + + Circle.prototype = Object.create(Body.prototype); + Circle.prototype.constructor = Circle; + + /** + * Basic setter for radius. + * @method setRadius + * @param r {Number} radius + */ + Circle.prototype.setRadius = function setRadius(r) { + this.radius = r; + this.size = [2*this.radius, 2*this.radius]; + this.setMomentsOfInertia(); + }; + + Circle.prototype.setMomentsOfInertia = function setMomentsOfInertia() { + var m = this.mass; + var r = this.radius; + + this.inertia = new Matrix([ + [0.25 * m * r * r, 0, 0], + [0, 0.25 * m * r * r, 0], + [0, 0, 0.5 * m * r * r] + ]); + + this.inverseInertia = new Matrix([ + [4 / (m * r * r), 0, 0], + [0, 4 / (m * r * r), 0], + [0, 0, 2 / (m * r * r)] + ]); + }; + + module.exports = Circle; + +}); diff --git a/bodies/Square.js b/bodies/Square.js new file mode 100644 index 0000000..f4b3067 --- /dev/null +++ b/bodies/Square.js @@ -0,0 +1,44 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Owner: david@famo.us + * @license MPL 2.0 + * @copyright Famous Industries, Inc. 2014 + */ + +define(function(require, exports, module) { + var Body = require('./Rectangle'); + var Matrix = require('famous/math/Matrix'); + + /** + * Implements a square geometry for an Body with + * size = length. + * + * @class Square + * @extends Rectangle + * @constructor + */ + function Square(options) { + options = options || {}; + this.size = options.size || [0,0]; + Rectangle.call(this, options); + } + + Square.prototype = Object.create(Rectangle.prototype); + Square.prototype.constructor = Square; + + /** + * Basic setter for size. + * @method setSize + * @param length + */ + Square.prototype.setSize = function setSize(length) { + var size = [length, length]; + this.size = size; + this.setMomentsOfInertia(); + }; + + module.exports = Square; + +}); diff --git a/constraints/Collision.js b/constraints/Collision.js index 7026936..0bca52b 100644 --- a/constraints/Collision.js +++ b/constraints/Collision.js @@ -33,6 +33,8 @@ define(function(require, exports, module) { this.vDiff = new Vector(); this.impulse1 = new Vector(); this.impulse2 = new Vector(); + this.torque1 = new Vector(); + this.torque2 = new Vector(); Constraint.call(this); } @@ -74,7 +76,15 @@ define(function(require, exports, module) { var v1 = source.velocity; var p1 = source.position; var w1 = source.inverseMass; - var r1 = source.radius; + + if (source instanceof Circle) { + var r1 = source.radius; + } + else if (source instanceof Ellipse) { + } + else if (source instanceof Rectangle) { + var o1 = source.orientation; + } var options = this.options; var drift = options.drift; @@ -86,6 +96,8 @@ define(function(require, exports, module) { var vDiff = this.vDiff; var impulse1 = this.impulse1; var impulse2 = this.impulse2; + var torque1 = this.torque1; + var torque2 = this.torque2; for (var i = 0; i < targets.length; i++) { var target = targets[i]; @@ -95,19 +107,48 @@ define(function(require, exports, module) { var v2 = target.velocity; var p2 = target.position; var w2 = target.inverseMass; - var r2 = target.radius; + + if (target instanceof Rectangle) { + var o2 = target.orientation; + } pDiff.set(p2.sub(p1)); vDiff.set(v2.sub(v1)); var dist = pDiff.norm(); - var overlap = dist - (r1 + r2); var effMass = 1/(w1 + w2); var gamma = 0; + if (target instanceof Circle) { + var r1 = target.radius; + } + else if (target instanceof Ellispe) { + } + else if (target instanceof Square) { + var theta = Math.atan(pDiff.y/pDiff.x); + if (source instanceof Square) { + var r1 = source.size[0]/2 * Math.cos(theta); + } + var r2 = target.size[0]/2 * Math.cos(theta); + } + else if (target instanceof Rectangle) { + } + + var overlap = dist - (r1 + r2); + if (overlap < 0) { - n.set(pDiff.normalize()); + if ((source instanceof Circle) && (target instanceof Circle)) { + n.set(pDiff.normalize()); + } + if ((source instanceof Square) && (target instanceof Square)) { + if ((theta < Math.PI/4) && theta > -1*Math.PI/4) { + n.set(1); + } + if ((theta > Math.PI/4) && theta < -1*Math.PI/4) { + n.set([0,1,0]); + } + } if (this._eventOutput) { var collisionData = { @@ -121,9 +162,17 @@ define(function(require, exports, module) { this._eventOutput.emit('collision', collisionData); } - var lambda = (overlap <= slop) - ? ((1 + restitution) * n.dot(vDiff) + drift/dt * (overlap - slop)) / (gamma + dt/effMass) - : ((1 + restitution) * n.dot(vDiff)) / (gamma + dt/effMass); + //if ((source instanceof Circle) && (target instanceof Circle)) { + var lambda = (overlap <= slop) + ? ((1 + restitution) * n.dot(vDiff) + drift/dt * (overlap - slop)) / (gamma + dt/effMass) + : ((1 + restitution) * n.dot(vDiff)) / (gamma + dt/effMass); + //} + //if ((source instanceof Square) && (target instanceof Square)) { + // var vtheta = Math.atan(vDiff.y/vDiff.x); + // var lambda = (overlap <= slop) + // ? ((1 + restitution) * n.dot(vDiff) + drift/dt * (overlap - slop)) / (gamma + dt/effMass) + // : ((1 + restitution) * n.dot(vDiff)) / (gamma + dt/effMass); + //} n.mult(dt*lambda).put(impulse1); impulse1.mult(-1).put(impulse2); @@ -131,6 +180,20 @@ define(function(require, exports, module) { source.applyImpulse(impulse1); target.applyImpulse(impulse2); + // Calculate the torque for off center collisions of Rectangular bodies. + // Normal orientation and same size of source and target. + else if (target instanceof Rectangle) { + var fdist = pDiff.y.mult(0.5); + var torque1 = (overlap <= slop) + ? (vDiff.cross(fdist).mult(1 + restitution) + drift/dt * (overlap - slop)) / (gamma + dt/effMass) + : vDiff.cross(fdist).mult((1 + restitution)/(gamma + dt/effMass)); + //vDiff.cross(fdist).put(torque1); + torque1.mult(-1).put(torque2); + source.applyTorque(torque1); + target.applyTorque(torque2); + } + + //source.setPosition(p1.add(n.mult(overlap/2))); //target.setPosition(p2.sub(n.mult(overlap/2))); diff --git a/forces/Repulsion.js b/forces/Repulsion.js index efd7365..834ba3f 100644 --- a/forces/Repulsion.js +++ b/forces/Repulsion.js @@ -78,7 +78,7 @@ define(function(require, exports, module) { /** * An inverse squared distance decay function - * @attribute INVERSE + * @attribute GRAVITY * @type Function * @param {Number} r distance from the source body * @param {Number} cutoff a distance shift to avoid singularities