diff --git a/examples/impulses.html b/examples/impulses.html index b53f6da13..4b8cc62a6 100644 --- a/examples/impulses.html +++ b/examples/impulses.html @@ -30,20 +30,15 @@ const world = setupWorld(demo) const shape = new CANNON.Sphere(radius) - const body = new CANNON.Body({ - mass, - position: new CANNON.Vec3(0, 1, 0), - }) + const body = new CANNON.Body({ mass }) body.addShape(shape) body.linearDamping = damping body.angularDamping = damping world.addBody(body) demo.addVisual(body) - // Add an impulse to the center - const worldPoint = new CANNON.Vec3(0, 0, 0) const impulse = new CANNON.Vec3(-strength * dt, 0, 0) - body.applyImpulse(impulse, worldPoint) + body.applyImpulse(impulse) }) // Add impulse to the top of the sphere @@ -51,20 +46,17 @@ const world = setupWorld(demo) const shape = new CANNON.Sphere(radius) - const body = new CANNON.Body({ - mass, - position: new CANNON.Vec3(0, 1, 0), - }) + const body = new CANNON.Body({ mass }) body.addShape(shape) body.linearDamping = damping body.angularDamping = damping world.addBody(body) demo.addVisual(body) - // Add an impulse to the center - const worldPoint = new CANNON.Vec3(0, radius, 0) + // The top of the sphere, relative to the sphere center + const topPoint = new CANNON.Vec3(0, radius / 2, 0) const impulse = new CANNON.Vec3(-strength * dt, 0, 0) - body.applyImpulse(impulse, worldPoint) + body.applyImpulse(impulse, topPoint) }) // Add force to the body center @@ -72,20 +64,15 @@ const world = setupWorld(demo) const shape = new CANNON.Sphere(radius) - const body = new CANNON.Body({ - mass, - position: new CANNON.Vec3(0, 1, 0), - }) + const body = new CANNON.Body({ mass }) body.addShape(shape) body.linearDamping = damping body.angularDamping = damping world.addBody(body) demo.addVisual(body) - // Add an force to the center - const worldPoint = new CANNON.Vec3(0, 0, 0) const force = new CANNON.Vec3(-strength, 0, 0) - body.applyForce(force, worldPoint) + body.applyForce(force) }) // Add force to the top of the sphere @@ -93,20 +80,37 @@ const world = setupWorld(demo) const shape = new CANNON.Sphere(radius) - const body = new CANNON.Body({ - mass, - position: new CANNON.Vec3(0, 1, 0), - }) + const body = new CANNON.Body({ mass }) body.addShape(shape) body.linearDamping = damping body.angularDamping = damping world.addBody(body) demo.addVisual(body) - // Add an force to the center - const worldPoint = new CANNON.Vec3(0, radius, 0) + // The top of the sphere, relative to the sphere center + const topPoint = new CANNON.Vec3(0, radius / 2, 0) const force = new CANNON.Vec3(-strength, 0, 0) - body.applyForce(force, worldPoint) + body.applyForce(force, topPoint) + }) + + // Apply a force in the local space + demo.addScene('Local force', () => { + const world = setupWorld(demo) + + const shape = new CANNON.Sphere(radius) + const body = new CANNON.Body({ mass }) + body.addShape(shape) + body.linearDamping = damping + body.angularDamping = damping + body.quaternion.setFromEuler(0, 0, Math.PI) + world.addBody(body) + demo.addVisual(body) + + // it's the top point, but since the sphere is rotated + // by 180 degrees, it is the bottom point to the right + const topPoint = new CANNON.Vec3(0, radius / 2, 0) + const force = new CANNON.Vec3(-strength, 0, 0) + body.applyLocalForce(force, topPoint) }) demo.start() diff --git a/examples/sleep.html b/examples/sleep.html index 96e09173d..944f39a60 100644 --- a/examples/sleep.html +++ b/examples/sleep.html @@ -49,7 +49,7 @@ }) // Wake up demo - demo.addScene('Wake up', () => { + demo.addScene('Wake up when hit', () => { const world = setupWorld(demo) // Create sphere @@ -89,6 +89,41 @@ }) }) + // Wake up demo + demo.addScene('Wake up with impulse', () => { + const world = setupWorld(demo) + + // Create sphere + const size = 2 + const sphere = new CANNON.Sphere(size) + const sphereBody = new CANNON.Body({ mass: 1 }) + sphereBody.addShape(sphere) + sphereBody.position.set(0, size, 0) + world.addBody(sphereBody) + demo.addVisual(sphereBody) + + // Force it to sleep + sphereBody.sleep() + + // Allow sleeping + world.allowSleep = true + sphereBody.allowSleep = true + + // Sleep parameters + sphereBody.sleepSpeedLimit = 0.5 + sphereBody.sleepTimeLimit = 1 + + // Apply an impulse after a bit + setTimeout(() => { + sphereBody.applyLocalImpulse(new CANNON.Vec3(5, 0, 0), new CANNON.Vec3()) + }, 1000) + + // The body wakes up when it gets a new contact + sphereBody.addEventListener('wakeup', (event) => { + console.log('The sphere woke up!') + }) + }) + demo.start() function setupWorld(demo) { diff --git a/readme.md b/readme.md index 0a129d46b..0f52c8a03 100644 --- a/readme.md +++ b/readme.md @@ -11,6 +11,7 @@ These minor changes and improvements were also made: - The `Cylinder` is now oriented on the Y axis. [#30](https://github.com/pmndrs/cannon-es/pull/30) - The `type` property of the `Cylinder` is now equal to `Shape.types.CYLINDER`. [#59](https://github.com/pmndrs/cannon-es/pull/59) - `Body.applyImpulse()` and `Body.applyForce()` are now relative to the center of the body instead of the center of the world [86b0444](https://github.com/schteppe/cannon.js/commit/86b0444c93356aeaa25dd1af795fa162574c6f4b) +- Sleeping bodies now wake up if a force or an impulse is applied to them [#61](https://github.com/pmndrs/cannon-es/pull/61) - Added a property `World.hasActiveBodies: boolean` which will be false when all physics bodies are sleeping. This allows for invalidating frames when physics aren't active for increased performance. - Deprecated properties and methods have been removed. - The [original cannon.js debugger](https://github.com/schteppe/cannon.js/blob/master/tools/threejs/CannonDebugRenderer.js), which shows the wireframes of each body, has been moved to its own repo [cannon-es-debugger](https://github.com/pmndrs/cannon-es-debugger). diff --git a/src/objects/Body.ts b/src/objects/Body.ts index 521e54011..5b1f1cd58 100644 --- a/src/objects/Body.ts +++ b/src/objects/Body.ts @@ -484,12 +484,23 @@ export class Body extends EventTarget { } } - applyForce(force: Vec3, relativePoint: Vec3): void { + /** + * Apply force to a point of the body. This could for example be a point on the Body surface. + * Applying force this way will add to Body.force and Body.torque. + * @method applyForce + * @param {Vec3} force The amount of force to add. + * @param {Vec3} [relativePoint] A point relative to the center of mass to apply the force on. + */ + applyForce(force: Vec3, relativePoint: Vec3 = new Vec3()): void { + // Needed? if (this.type !== Body.DYNAMIC) { - // Needed? return } + if (this.sleepState === Body.SLEEPING) { + this.wakeUp() + } + // Compute produced rotational force const rotForce = Body_applyForce_rotForce relativePoint.cross(force, rotForce) @@ -501,7 +512,13 @@ export class Body extends EventTarget { this.torque.vadd(rotForce, this.torque) } - applyLocalForce(localForce: Vec3, localPoint: Vec3): void { + /** + * Apply force to a local point in the body. + * @method applyLocalForce + * @param {Vec3} force The force vector to apply, defined locally in the body frame. + * @param {Vec3} [localPoint] A local point in the body to apply the force on. + */ + applyLocalForce(localForce: Vec3, localPoint: Vec3 = new Vec3()): void { if (this.type !== Body.DYNAMIC) { return } @@ -516,11 +533,23 @@ export class Body extends EventTarget { this.applyForce(worldForce, relativePointWorld) } - applyImpulse(impulse: Vec3, relativePoint: Vec3): void { + /** + * Apply impulse to a point of the body. This could for example be a point on the Body surface. + * An impulse is a force added to a body during a short period of time (impulse = force * time). + * Impulses will be added to Body.velocity and Body.angularVelocity. + * @method applyImpulse + * @param {Vec3} impulse The amount of impulse to add. + * @param {Vec3} relativePoint A point relative to the center of mass to apply the force on. + */ + applyImpulse(impulse: Vec3, relativePoint: Vec3 = new Vec3()): void { if (this.type !== Body.DYNAMIC) { return } + if (this.sleepState === Body.SLEEPING) { + this.wakeUp() + } + // Compute point position relative to the body center const r = relativePoint @@ -547,7 +576,13 @@ export class Body extends EventTarget { this.angularVelocity.vadd(rotVelo, this.angularVelocity) } - applyLocalImpulse(localImpulse: Vec3, localPoint: Vec3): void { + /** + * Apply locally-defined impulse to a local point in the body. + * @method applyLocalImpulse + * @param {Vec3} force The force vector to apply, defined locally in the body frame. + * @param {Vec3} localPoint A local point in the body to apply the force on. + */ + applyLocalImpulse(localImpulse: Vec3, localPoint: Vec3 = new Vec3()): void { if (this.type !== Body.DYNAMIC) { return } @@ -738,38 +773,14 @@ const uiw_m1 = new Mat3() const uiw_m2 = new Mat3() const uiw_m3 = new Mat3() -/** - * Apply force to a world point. This could for example be a point on the Body surface. Applying force this way will add to Body.force and Body.torque. - * @method applyForce - * @param {Vec3} force The amount of force to add. - * @param {Vec3} relativePoint A point relative to the center of mass to apply the force on. - */ const Body_applyForce_rotForce = new Vec3() -/** - * Apply force to a local point in the body. - * @method applyLocalForce - * @param {Vec3} force The force vector to apply, defined locally in the body frame. - * @param {Vec3} localPoint A local point in the body to apply the force on. - */ const Body_applyLocalForce_worldForce = new Vec3() const Body_applyLocalForce_relativePointWorld = new Vec3() -/** - * Apply impulse to a world point. This could for example be a point on the Body surface. An impulse is a force added to a body during a short period of time (impulse = force * time). Impulses will be added to Body.velocity and Body.angularVelocity. - * @method applyImpulse - * @param {Vec3} impulse The amount of impulse to add. - * @param {Vec3} relativePoint A point relative to the center of mass to apply the force on. - */ const Body_applyImpulse_velo = new Vec3() const Body_applyImpulse_rotVelo = new Vec3() -/** - * Apply locally-defined impulse to a local point in the body. - * @method applyLocalImpulse - * @param {Vec3} force The force vector to apply, defined locally in the body frame. - * @param {Vec3} localPoint A local point in the body to apply the force on. - */ const Body_applyLocalImpulse_worldImpulse = new Vec3() const Body_applyLocalImpulse_relativePoint = new Vec3()