UNPKG

cannon

Version:

A lightweight 3D physics engine written in JavaScript.

194 lines (168 loc) 5.29 kB
var Vec3 = require('../math/Vec3'); module.exports = Spring; /** * A spring, connecting two bodies. * * @class Spring * @constructor * @param {Body} bodyA * @param {Body} bodyB * @param {Object} [options] * @param {number} [options.restLength] A number > 0. Default: 1 * @param {number} [options.stiffness] A number >= 0. Default: 100 * @param {number} [options.damping] A number >= 0. Default: 1 * @param {Vec3} [options.worldAnchorA] Where to hook the spring to body A, in world coordinates. * @param {Vec3} [options.worldAnchorB] * @param {Vec3} [options.localAnchorA] Where to hook the spring to body A, in local body coordinates. * @param {Vec3} [options.localAnchorB] */ function Spring(bodyA,bodyB,options){ options = options || {}; /** * Rest length of the spring. * @property restLength * @type {number} */ this.restLength = typeof(options.restLength) === "number" ? options.restLength : 1; /** * Stiffness of the spring. * @property stiffness * @type {number} */ this.stiffness = options.stiffness || 100; /** * Damping of the spring. * @property damping * @type {number} */ this.damping = options.damping || 1; /** * First connected body. * @property bodyA * @type {Body} */ this.bodyA = bodyA; /** * Second connected body. * @property bodyB * @type {Body} */ this.bodyB = bodyB; /** * Anchor for bodyA in local bodyA coordinates. * @property localAnchorA * @type {Vec3} */ this.localAnchorA = new Vec3(); /** * Anchor for bodyB in local bodyB coordinates. * @property localAnchorB * @type {Vec3} */ this.localAnchorB = new Vec3(); if(options.localAnchorA){ this.localAnchorA.copy(options.localAnchorA); } if(options.localAnchorB){ this.localAnchorB.copy(options.localAnchorB); } if(options.worldAnchorA){ this.setWorldAnchorA(options.worldAnchorA); } if(options.worldAnchorB){ this.setWorldAnchorB(options.worldAnchorB); } } /** * Set the anchor point on body A, using world coordinates. * @method setWorldAnchorA * @param {Vec3} worldAnchorA */ Spring.prototype.setWorldAnchorA = function(worldAnchorA){ this.bodyA.pointToLocalFrame(worldAnchorA,this.localAnchorA); }; /** * Set the anchor point on body B, using world coordinates. * @method setWorldAnchorB * @param {Vec3} worldAnchorB */ Spring.prototype.setWorldAnchorB = function(worldAnchorB){ this.bodyB.pointToLocalFrame(worldAnchorB,this.localAnchorB); }; /** * Get the anchor point on body A, in world coordinates. * @method getWorldAnchorA * @param {Vec3} result The vector to store the result in. */ Spring.prototype.getWorldAnchorA = function(result){ this.bodyA.pointToWorldFrame(this.localAnchorA,result); }; /** * Get the anchor point on body B, in world coordinates. * @method getWorldAnchorB * @param {Vec3} result The vector to store the result in. */ Spring.prototype.getWorldAnchorB = function(result){ this.bodyB.pointToWorldFrame(this.localAnchorB,result); }; var applyForce_r = new Vec3(), applyForce_r_unit = new Vec3(), applyForce_u = new Vec3(), applyForce_f = new Vec3(), applyForce_worldAnchorA = new Vec3(), applyForce_worldAnchorB = new Vec3(), applyForce_ri = new Vec3(), applyForce_rj = new Vec3(), applyForce_ri_x_f = new Vec3(), applyForce_rj_x_f = new Vec3(), applyForce_tmp = new Vec3(); /** * Apply the spring force to the connected bodies. * @method applyForce */ Spring.prototype.applyForce = function(){ var k = this.stiffness, d = this.damping, l = this.restLength, bodyA = this.bodyA, bodyB = this.bodyB, r = applyForce_r, r_unit = applyForce_r_unit, u = applyForce_u, f = applyForce_f, tmp = applyForce_tmp; var worldAnchorA = applyForce_worldAnchorA, worldAnchorB = applyForce_worldAnchorB, ri = applyForce_ri, rj = applyForce_rj, ri_x_f = applyForce_ri_x_f, rj_x_f = applyForce_rj_x_f; // Get world anchors this.getWorldAnchorA(worldAnchorA); this.getWorldAnchorB(worldAnchorB); // Get offset points worldAnchorA.vsub(bodyA.position,ri); worldAnchorB.vsub(bodyB.position,rj); // Compute distance vector between world anchor points worldAnchorB.vsub(worldAnchorA,r); var rlen = r.norm(); r_unit.copy(r); r_unit.normalize(); // Compute relative velocity of the anchor points, u bodyB.velocity.vsub(bodyA.velocity,u); // Add rotational velocity bodyB.angularVelocity.cross(rj,tmp); u.vadd(tmp,u); bodyA.angularVelocity.cross(ri,tmp); u.vsub(tmp,u); // F = - k * ( x - L ) - D * ( u ) r_unit.mult(-k*(rlen-l) - d*u.dot(r_unit), f); // Add forces to bodies bodyA.force.vsub(f,bodyA.force); bodyB.force.vadd(f,bodyB.force); // Angular force ri.cross(f,ri_x_f); rj.cross(f,rj_x_f); bodyA.torque.vsub(ri_x_f,bodyA.torque); bodyB.torque.vadd(rj_x_f,bodyB.torque); };