*
*/
if(typeof P2_ARRAY_TYPE !== 'undefined') {
Utils.ARRAY_TYPE = P2_ARRAY_TYPE;
} else if (typeof Float32Array !== 'undefined'){
Utils.ARRAY_TYPE = Float32Array;
} else {
Utils.ARRAY_TYPE = Array;
}
/**
* Extend an object with the properties of another
* @static
* @method extend
* @param {object} a
* @param {object} b
*/
Utils.extend = function(a,b){
for(var key in b){
a[key] = b[key];
}
};
/**
* Extend an options object with default values.
* @static
* @method defaults
* @param {object} options The options object. May be falsy: in this case, a new object is created and returned.
* @param {object} defaults An object containing default values.
* @return {object} The modified options object.
*/
Utils.defaults = function(options, defaults){
options = options || {};
for(var key in defaults){
if(!(key in options)){
options[key] = defaults[key];
}
}
return options;
};
},{}],58:[function(_dereq_,module,exports){
var Body = _dereq_('../objects/Body');
module.exports = Island;
/**
* An island of bodies connected with equations.
* @class Island
* @constructor
*/
function Island(){
/**
* Current equations in this island.
* @property equations
* @type {Array}
*/
this.equations = [];
/**
* Current bodies in this island.
* @property bodies
* @type {Array}
*/
this.bodies = [];
}
/**
* Clean this island from bodies and equations.
* @method reset
*/
Island.prototype.reset = function(){
this.equations.length = this.bodies.length = 0;
};
var bodyIds = [];
/**
* Get all unique bodies in this island.
* @method getBodies
* @return {Array} An array of Body
*/
Island.prototype.getBodies = function(result){
var bodies = result || [],
eqs = this.equations;
bodyIds.length = 0;
for(var i=0; i!==eqs.length; i++){
var eq = eqs[i];
if(bodyIds.indexOf(eq.bodyA.id)===-1){
bodies.push(eq.bodyA);
bodyIds.push(eq.bodyA.id);
}
if(bodyIds.indexOf(eq.bodyB.id)===-1){
bodies.push(eq.bodyB);
bodyIds.push(eq.bodyB.id);
}
}
return bodies;
};
/**
* Check if the entire island wants to sleep.
* @method wantsToSleep
* @return {Boolean}
*/
Island.prototype.wantsToSleep = function(){
for(var i=0; i= dt && substeps < maxSubSteps) {
// Do fixed steps to catch up
this.internalStep(dt);
this.time += dt;
this.accumulator -= dt;
substeps++;
}
var t = (this.accumulator % dt) / dt;
for(var j=0; j!==this.bodies.length; j++){
var b = this.bodies[j];
vec2.lerp(b.interpolatedPosition, b.previousPosition, b.position, t);
b.interpolatedAngle = b.previousAngle + t * (b.angle - b.previousAngle);
}
}
};
var endOverlaps = [];
/**
* Make a fixed step.
* @method internalStep
* @param {number} dt
* @private
*/
World.prototype.internalStep = function(dt){
this.stepping = true;
var that = this,
Nsprings = this.springs.length,
springs = this.springs,
bodies = this.bodies,
g = this.gravity,
solver = this.solver,
Nbodies = this.bodies.length,
broadphase = this.broadphase,
np = this.narrowphase,
constraints = this.constraints,
t0, t1,
fhMinv = step_fhMinv,
velodt = step_velodt,
mg = step_mg,
scale = vec2.scale,
add = vec2.add,
rotate = vec2.rotate,
islandManager = this.islandManager;
this.overlapKeeper.tick();
this.lastTimeStep = dt;
// Update approximate friction gravity.
if(this.useWorldGravityAsFrictionGravity){
var gravityLen = vec2.length(this.gravity);
if(!(gravityLen === 0 && this.useFrictionGravityOnZeroGravity)){
// Nonzero gravity. Use it.
this.frictionGravity = gravityLen;
}
}
// Add gravity to bodies
if(this.applyGravity){
for(var i=0; i!==Nbodies; i++){
var b = bodies[i],
fi = b.force;
if(b.type !== Body.DYNAMIC || b.sleepState === Body.SLEEPING){
continue;
}
vec2.scale(mg,g,b.mass*b.gravityScale); // F=m*g
add(fi,fi,mg);
}
}
// Add spring forces
if(this.applySpringForces){
for(var i=0; i!==Nsprings; i++){
var s = springs[i];
s.applyForce();
}
}
if(this.applyDamping){
for(var i=0; i!==Nbodies; i++){
var b = bodies[i];
if(b.type === Body.DYNAMIC){
b.applyDamping(dt);
}
}
}
// Broadphase
var result = broadphase.getCollisionPairs(this);
// Remove ignored collision pairs
var ignoredPairs = this.disabledBodyCollisionPairs;
for(var i=ignoredPairs.length-2; i>=0; i-=2){
for(var j=result.length-2; j>=0; j-=2){
if( (ignoredPairs[i] === result[j] && ignoredPairs[i+1] === result[j+1]) ||
(ignoredPairs[i+1] === result[j] && ignoredPairs[i] === result[j+1])){
result.splice(j,2);
}
}
}
// Remove constrained pairs with collideConnected == false
var Nconstraints = constraints.length;
for(i=0; i!==Nconstraints; i++){
var c = constraints[i];
if(!c.collideConnected){
for(var j=result.length-2; j>=0; j-=2){
if( (c.bodyA === result[j] && c.bodyB === result[j+1]) ||
(c.bodyB === result[j] && c.bodyA === result[j+1])){
result.splice(j,2);
}
}
}
}
// postBroadphase event
this.postBroadphaseEvent.pairs = result;
this.emit(this.postBroadphaseEvent);
this.postBroadphaseEvent.pairs = null;
// Narrowphase
np.reset(this);
for(var i=0, Nresults=result.length; i!==Nresults; i+=2){
var bi = result[i],
bj = result[i+1];
// Loop over all shapes of body i
for(var k=0, Nshapesi=bi.shapes.length; k!==Nshapesi; k++){
var si = bi.shapes[k],
xi = si.position,
ai = si.angle;
// All shapes of body j
for(var l=0, Nshapesj=bj.shapes.length; l!==Nshapesj; l++){
var sj = bj.shapes[l],
xj = sj.position,
aj = sj.angle;
var cm = this.defaultContactMaterial;
if(si.material && sj.material){
var tmp = this.getContactMaterial(si.material,sj.material);
if(tmp){
cm = tmp;
}
}
this.runNarrowphase(np,bi,si,xi,ai,bj,sj,xj,aj,cm,this.frictionGravity);
}
}
}
// Wake up bodies
for(var i=0; i!==Nbodies; i++){
var body = bodies[i];
if(body._wakeUpAfterNarrowphase){
body.wakeUp();
body._wakeUpAfterNarrowphase = false;
}
}
// Emit end overlap events
if(this.has('endContact')){
this.overlapKeeper.getEndOverlaps(endOverlaps);
var e = this.endContactEvent;
var l = endOverlaps.length;
while(l--){
var data = endOverlaps[l];
e.shapeA = data.shapeA;
e.shapeB = data.shapeB;
e.bodyA = data.bodyA;
e.bodyB = data.bodyB;
this.emit(e);
}
endOverlaps.length = 0;
}
var preSolveEvent = this.preSolveEvent;
preSolveEvent.contactEquations = np.contactEquations;
preSolveEvent.frictionEquations = np.frictionEquations;
this.emit(preSolveEvent);
preSolveEvent.contactEquations = preSolveEvent.frictionEquations = null;
// update constraint equations
var Nconstraints = constraints.length;
for(i=0; i!==Nconstraints; i++){
constraints[i].update();
}
if(np.contactEquations.length || np.frictionEquations.length || Nconstraints){
if(this.islandSplit){
// Split into islands
islandManager.equations.length = 0;
Utils.appendArray(islandManager.equations, np.contactEquations);
Utils.appendArray(islandManager.equations, np.frictionEquations);
for(i=0; i!==Nconstraints; i++){
Utils.appendArray(islandManager.equations, constraints[i].equations);
}
islandManager.split(this);
for(var i=0; i!==islandManager.islands.length; i++){
var island = islandManager.islands[i];
if(island.equations.length){
solver.solveIsland(dt,island);
}
}
} else {
// Add contact equations to solver
solver.addEquations(np.contactEquations);
solver.addEquations(np.frictionEquations);
// Add user-defined constraint equations
for(i=0; i!==Nconstraints; i++){
solver.addEquations(constraints[i].equations);
}
if(this.solveConstraints){
solver.solve(dt,this);
}
solver.removeAllEquations();
}
}
// Step forward
for(var i=0; i!==Nbodies; i++){
var body = bodies[i];
// if(body.sleepState !== Body.SLEEPING && body.type !== Body.STATIC){
body.integrate(dt);
// }
}
// Reset force
for(var i=0; i!==Nbodies; i++){
bodies[i].setZeroForce();
}
// Emit impact event
if(this.emitImpactEvent && this.has('impact')){
var ev = this.impactEvent;
for(var i=0; i!==np.contactEquations.length; i++){
var eq = np.contactEquations[i];
if(eq.firstImpact){
ev.bodyA = eq.bodyA;
ev.bodyB = eq.bodyB;
ev.shapeA = eq.shapeA;
ev.shapeB = eq.shapeB;
ev.contactEquation = eq;
this.emit(ev);
}
}
}
// Sleeping update
if(this.sleepMode === World.BODY_SLEEPING){
for(i=0; i!==Nbodies; i++){
bodies[i].sleepTick(this.time, false, dt);
}
} else if(this.sleepMode === World.ISLAND_SLEEPING && this.islandSplit){
// Tell all bodies to sleep tick but dont sleep yet
for(i=0; i!==Nbodies; i++){
bodies[i].sleepTick(this.time, true, dt);
}
// Sleep islands
for(var i=0; i 0;
np.frictionCoefficient = cm.friction;
var reducedMass;
if(bi.type === Body.STATIC || bi.type === Body.KINEMATIC){
reducedMass = bj.mass;
} else if(bj.type === Body.STATIC || bj.type === Body.KINEMATIC){
reducedMass = bi.mass;
} else {
reducedMass = (bi.mass*bj.mass)/(bi.mass+bj.mass);
}
np.slipForce = cm.friction*glen*reducedMass;
np.restitution = cm.restitution;
np.surfaceVelocity = cm.surfaceVelocity;
np.frictionStiffness = cm.frictionStiffness;
np.frictionRelaxation = cm.frictionRelaxation;
np.stiffness = cm.stiffness;
np.relaxation = cm.relaxation;
np.contactSkinSize = cm.contactSkinSize;
np.enabledEquations = bi.collisionResponse && bj.collisionResponse && si.collisionResponse && sj.collisionResponse;
var resolver = np[si.type | sj.type],
numContacts = 0;
if (resolver) {
var sensor = si.sensor || sj.sensor;
var numFrictionBefore = np.frictionEquations.length;
if (si.type < sj.type) {
numContacts = resolver.call(np, bi,si,xiw,aiw, bj,sj,xjw,ajw, sensor);
} else {
numContacts = resolver.call(np, bj,sj,xjw,ajw, bi,si,xiw,aiw, sensor);
}
var numFrictionEquations = np.frictionEquations.length - numFrictionBefore;
if(numContacts){
if( bi.allowSleep &&
bi.type === Body.DYNAMIC &&
bi.sleepState === Body.SLEEPING &&
bj.sleepState === Body.AWAKE &&
bj.type !== Body.STATIC
){
var speedSquaredB = vec2.squaredLength(bj.velocity) + Math.pow(bj.angularVelocity,2);
var speedLimitSquaredB = Math.pow(bj.sleepSpeedLimit,2);
if(speedSquaredB >= speedLimitSquaredB*2){
bi._wakeUpAfterNarrowphase = true;
}
}
if( bj.allowSleep &&
bj.type === Body.DYNAMIC &&
bj.sleepState === Body.SLEEPING &&
bi.sleepState === Body.AWAKE &&
bi.type !== Body.STATIC
){
var speedSquaredA = vec2.squaredLength(bi.velocity) + Math.pow(bi.angularVelocity,2);
var speedLimitSquaredA = Math.pow(bi.sleepSpeedLimit,2);
if(speedSquaredA >= speedLimitSquaredA*2){
bj._wakeUpAfterNarrowphase = true;
}
}
this.overlapKeeper.setOverlapping(bi, si, bj, sj);
if(this.has('beginContact') && this.overlapKeeper.isNewOverlap(si, sj)){
// Report new shape overlap
var e = this.beginContactEvent;
e.shapeA = si;
e.shapeB = sj;
e.bodyA = bi;
e.bodyB = bj;
// Reset contact equations
e.contactEquations.length = 0;
if(typeof(numContacts)==="number"){
for(var i=np.contactEquations.length-numContacts; i 1){ // Why divide by 1?
for(var i=np.frictionEquations.length-numFrictionEquations; i=0; i--){
this.removeConstraint(cs[i]);
}
// Remove all bodies
var bodies = this.bodies;
for(var i=bodies.length-1; i>=0; i--){
this.removeBody(bodies[i]);
}
// Remove all springs
var springs = this.springs;
for(var i=springs.length-1; i>=0; i--){
this.removeSpring(springs[i]);
}
// Remove all contact materials
var cms = this.contactMaterials;
for(var i=cms.length-1; i>=0; i--){
this.removeContactMaterial(cms[i]);
}
World.apply(this);
};
var hitTest_tmp1 = vec2.create(),
hitTest_zero = vec2.fromValues(0,0),
hitTest_tmp2 = vec2.fromValues(0,0);
/**
* Test if a world point overlaps bodies
* @method hitTest
* @param {Array} worldPoint Point to use for intersection tests
* @param {Array} bodies A list of objects to check for intersection
* @param {Number} precision Used for matching against particles and lines. Adds some margin to these infinitesimal objects.
* @return {Array} Array of bodies that overlap the point
* @todo Should use an api similar to the raycast function
* @todo Should probably implement a .containsPoint method for all shapes. Would be more efficient
* @todo Should use the broadphase
*/
World.prototype.hitTest = function(worldPoint,bodies,precision){
precision = precision || 0;
// Create a dummy particle body with a particle shape to test against the bodies
var pb = new Body({ position:worldPoint }),
ps = new Particle(),
px = worldPoint,
pa = 0,
x = hitTest_tmp1,
zero = hitTest_zero,
tmp = hitTest_tmp2;
pb.addShape(ps);
var n = this.narrowphase,
result = [];
// Check bodies
for(var i=0, N=bodies.length; i!==N; i++){
var b = bodies[i];
for(var j=0, NS=b.shapes.length; j!==NS; j++){
var s = b.shapes[j];
// Get shape world position + angle
vec2.rotate(x, s.position, b.angle);
vec2.add(x, x, b.position);
var a = s.angle + b.angle;
if( (s instanceof Circle && n.circleParticle (b,s,x,a, pb,ps,px,pa, true)) ||
(s instanceof Convex && n.particleConvex (pb,ps,px,pa, b,s,x,a, true)) ||
(s instanceof Plane && n.particlePlane (pb,ps,px,pa, b,s,x,a, true)) ||
(s instanceof Capsule && n.particleCapsule (pb,ps,px,pa, b,s,x,a, true)) ||
(s instanceof Particle && vec2.squaredLength(vec2.sub(tmp,x,worldPoint)) < precision*precision)
){
result.push(b);
}
}
}
return result;
};
/**
* Set the stiffness for all equations and contact materials.
* @method setGlobalStiffness
* @param {Number} stiffness
*/
World.prototype.setGlobalStiffness = function(stiffness){
// Set for all constraints
var constraints = this.constraints;
for(var i=0; i !== constraints.length; i++){
var c = constraints[i];
for(var j=0; j !== c.equations.length; j++){
var eq = c.equations[j];
eq.stiffness = stiffness;
eq.needsUpdate = true;
}
}
// Set for all contact materials
var contactMaterials = this.contactMaterials;
for(var i=0; i !== contactMaterials.length; i++){
var c = contactMaterials[i];
c.stiffness = c.frictionStiffness = stiffness;
}
// Set for default contact material
var c = this.defaultContactMaterial;
c.stiffness = c.frictionStiffness = stiffness;
};
/**
* Set the relaxation for all equations and contact materials.
* @method setGlobalRelaxation
* @param {Number} relaxation
*/
World.prototype.setGlobalRelaxation = function(relaxation){
// Set for all constraints
for(var i=0; i !== this.constraints.length; i++){
var c = this.constraints[i];
for(var j=0; j !== c.equations.length; j++){
var eq = c.equations[j];
eq.relaxation = relaxation;
eq.needsUpdate = true;
}
}
// Set for all contact materials
for(var i=0; i !== this.contactMaterials.length; i++){
var c = this.contactMaterials[i];
c.relaxation = c.frictionRelaxation = relaxation;
}
// Set for default contact material
var c = this.defaultContactMaterial;
c.relaxation = c.frictionRelaxation = relaxation;
};
var tmpAABB = new AABB();
var tmpArray = [];
/**
* Ray cast against all bodies in the world.
* @method raycast
* @param {RaycastResult} result
* @param {Ray} ray
* @return {boolean} True if any body was hit.
*
* @example
* var ray = new Ray({
* mode: Ray.CLOSEST, // or ANY
* from: [0, 0],
* to: [10, 0],
* });
* var result = new RaycastResult();
* world.raycast(result, ray);
*
* // Get the hit point
* var hitPoint = vec2.create();
* result.getHitPoint(hitPoint, ray);
* console.log('Hit point: ', hitPoint[0], hitPoint[1], ' at distance ' + result.getHitDistance(ray));
*
* @example
* var ray = new Ray({
* mode: Ray.ALL,
* from: [0, 0],
* to: [10, 0],
* callback: function(result){
*
* // Print some info about the hit
* console.log('Hit body and shape: ', result.body, result.shape);
*
* // Get the hit point
* var hitPoint = vec2.create();
* result.getHitPoint(hitPoint, ray);
* console.log('Hit point: ', hitPoint[0], hitPoint[1], ' at distance ' + result.getHitDistance(ray));
*
* // If you are happy with the hits you got this far, you can stop the traversal here:
* result.stop();
* }
* });
* var result = new RaycastResult();
* world.raycast(result, ray);
*/
World.prototype.raycast = function(result, ray){
// Get all bodies within the ray AABB
ray.getAABB(tmpAABB);
this.broadphase.aabbQuery(this, tmpAABB, tmpArray);
ray.intersectBodies(result, tmpArray);
tmpArray.length = 0;
return result.hasHit();
};
},{"../../package.json":6,"../collision/AABB":7,"../collision/Broadphase":8,"../collision/Narrowphase":10,"../collision/Ray":11,"../collision/SAPBroadphase":13,"../constraints/Constraint":14,"../constraints/DistanceConstraint":15,"../constraints/GearConstraint":16,"../constraints/LockConstraint":17,"../constraints/PrismaticConstraint":18,"../constraints/RevoluteConstraint":19,"../events/EventEmitter":26,"../material/ContactMaterial":27,"../material/Material":28,"../math/vec2":30,"../objects/Body":31,"../objects/LinearSpring":32,"../objects/RotationalSpring":33,"../shapes/Capsule":38,"../shapes/Circle":39,"../shapes/Convex":40,"../shapes/Line":42,"../shapes/Particle":43,"../shapes/Plane":44,"../shapes/Shape":45,"../solver/GSSolver":46,"../solver/Solver":47,"../utils/OverlapKeeper":52,"../utils/Utils":57,"./IslandManager":59}]},{},[36])
(36)
});