* */ 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) });