Skip to content

Commit

Permalink
Merge pull request #61 from pmndrs/wakeup-force-impulse
Browse files Browse the repository at this point in the history
Wakeup a body if a force is applied to it
  • Loading branch information
marcofugaro authored Dec 24, 2020
2 parents 65a7391 + ed94909 commit 286d756
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 58 deletions.
60 changes: 32 additions & 28 deletions examples/impulses.html
Original file line number Diff line number Diff line change
Expand Up @@ -30,83 +30,87 @@
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
demo.addScene('Top impulse', () => {
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
demo.addScene('Center force', () => {
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
demo.addScene('Top force', () => {
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()
Expand Down
37 changes: 36 additions & 1 deletion examples/sleep.html
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
})

// Wake up demo
demo.addScene('Wake up', () => {
demo.addScene('Wake up when hit', () => {
const world = setupWorld(demo)

// Create sphere
Expand Down Expand Up @@ -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) {
Expand Down
1 change: 1 addition & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -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).
Expand Down
69 changes: 40 additions & 29 deletions src/objects/Body.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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
}
Expand All @@ -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

Expand All @@ -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
}
Expand Down Expand Up @@ -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()

Expand Down

0 comments on commit 286d756

Please sign in to comment.