### Getting Started with Bounce Physics Simulation Source: https://codeberg.org/perplexdotgg/bounce/src/branch/main/docs/documentation Demonstrates the basic setup for the Bounce physics library. It involves creating a World instance, adding ground and ball bodies with specified shapes and properties, and then simulating the physics for a duration. The example highlights how to define shapes, static and dynamic bodies, and step the simulation. ```typescript import { World } from '@perplexdotgg/bounce'; const world = new World({ gravity: { x: 0, y: -9.81, z: 0 }, }); // ground const groundShape = world.createBox({ width: 10, height: 2, depth: 10, }); const ground = world.createStaticBody({ shape: groundShape, position: { x: 0, y: 10, z: 0 }, orientation: { x: 0, y: 0, z: 0, w: 1 }, // if w is omitted, this is treated as an euler (radians) input friction: 0.4, restitution: 0.3, }); // ball const ballShape = world.createSphere({ radius: 0.5 }); const ball = world.createDynamicBody({ shape: ballShape, position: [0, -1, 0], // vec3 can be specified as an array, see note below orientation: [0, Math.PI, 0], // euler (radians) or quaternion as input, based on the presence of 3 or 4 numbers friction: 0.4, restitution: 0.3, mass: 0.5, }); // simulate 10 seconds const timeStepSizeSeconds = 1 / 60; for (let i = 0; i < 600; i++) { world.takeOneStep(timeStepSizeSeconds); } ``` -------------------------------- ### Install Bounce Physics Library using npm Source: https://codeberg.org/perplexdotgg/bounce/src/branch/main/docs/documentation This command installs the Bounce physics library using npm. Ensure you have Node.js and npm installed on your system. This is the first step to using Bounce in your TypeScript or JavaScript project. ```bash npm i @perplexdotgg/bounce ``` -------------------------------- ### Iterate Over Bodies Source: https://codeberg.org/perplexdotgg/bounce/src/branch/main/docs/documentation Provides examples of iterating through bodies in the simulation world. It covers iterating over bodies of a specific type (e.g., `dynamicBodies`) and iterating over all bodies using the `world.bodies()` method, displaying their positions and types. ```javascript const boxShape = world.createBox({ width: 1, height: 1, depth: 1 }); const body1 = world.createDynamicBody({ shape: boxShape, position: [0, 0, 0] }); const body2 = world.createDynamicBody({ shape: boxShape, position: [0, 5, 0] }); const body3 = world.createDynamicBody({ shape: boxShape, position: [0, 20, 0], }); // iterate by type for (const body of world.dynamicBodies) { console.log(body.position); } // also available: world.kinematicBodies, world.staticBodies // or iterate all bodies at once for (const body of world.bodies()) { console.log(body.position, body.type); } ``` -------------------------------- ### Translate Shapes in Bounce Local Space Source: https://codeberg.org/perplexdotgg/bounce/src/branch/main/docs/documentation_display=source Explains how to translate shapes in local space within the Bounce physics engine. By default, shapes are centered at the origin, but this example shows how to offset a shape's center of mass relative to the body's position. ```javascript // default: centered at origin const sphere1 = world.createSphere({ radius: 1.0 }); const body1 = world.createDynamicBody({ shape: sphere1 }); // translated from origin const sphere2 = world.createSphere({ radius: 1.0, position: [3, 0, 0] }); const body2 = world.createDynamicBody({ shape: sphere2 }); // character controller capsule: bottom at origin const radius = 1.0; const height = 2.0; const halfCapsuleHeight = radius + height / 2; const shape = world.createCapsule({ radius, height, position: [0, -halfCapsuleHeight, 0], }); const body = world.createDynamicBody({ shape: shape }); ``` -------------------------------- ### Configure Bounce World Simulation Parameters Source: https://codeberg.org/perplexdotgg/bounce/src/branch/main/docs/documentation Shows how to configure various simulation parameters when creating a new Bounce `World`. This includes setting gravity, time step size, solver iterations, damping, and other stability-related options. It also demonstrates how to set limits for contact manifolds and pairs. ```typescript const world = new World({ gravity: [0, -9.80665, 0], timeStepSizeSeconds: 1 / 60, // more is higher fidelity, but uses more CPU solveVelocityIterations: 6, solvePositionIterations: 2, // most of these options are for stability linearDamping: 0.05, angularDamping: 0.05, baumgarte: 0.2, penetrationSlop: 0.02, maxPenetrationDistance: 0.2, speculativeContactDistance: 0.02, collisionTolerance: 1e-4, maxLinearSpeed: 30.0, maxAngularSpeed: 30.0, isWarmStartingEnabled: true, // contact manifold limits // by default since v1.3.0, these are unlimited // if set to a finite amount, an error is thrown when an allocation is attempted past the limit // this may be desired during development to stay within a strict memory budget, for example // 1024 is a reasonable limit for many use cases (it was the default prior to v1.3.0) contactManifoldOptions: { maxContactManifolds: Infinity, maxContactPairs: Infinity, }, }); ``` -------------------------------- ### Bounce World Configuration Options Source: https://codeberg.org/perplexdotgg/bounce/src/branch/main/docs/documentation_display=source Shows how to configure the 'World' object in Bounce with various physics parameters. This includes gravity, time step, solver iterations, damping, and collision-related settings. ```typescript const world = new World({ gravity: [0, -9.80665, 0], timeStepSizeSeconds: 1 / 60, // more is higher fidelity, but uses more CPU solveVelocityIterations: 6, solvePositionIterations: 2, // most of these options are for stability linearDamping: 0.05, angularDamping: 0.05, baumgarte: 0.2, penetrationSlop: 0.02, maxPenetrationDistance: 0.2, speculativeContactDistance: 0.02, collisionTolerance: 1e-4, maxLinearSpeed: 30.0, maxAngularSpeed: 30.0, isWarmStartingEnabled: true, // contact manifold limits // by default since v1.3.0, these are unlimited // if set to a finite amount, an error is thrown when an allocation is attempted past the limit // this may be desired during development to stay within a strict memory budget, for example // 1024 is a reasonable limit for many use cases (it was the default prior to v1.3.0) contactManifoldOptions: { maxContactManifolds: Infinity, maxContactPairs: Infinity, }, }); ``` -------------------------------- ### Serialize and Restore Single Body State in Bounce Source: https://codeberg.org/perplexdotgg/bounce/src/branch/main/docs/documentation Details how to serialize and deserialize the state of a single physics body in Bounce using its `toArray` and `fromArray` methods. This is useful for managing individual object states. The example shows creating a body, serializing it, simulating steps, and then restoring the body to its initial state. ```javascript const world = new World({ gravity: [0, 0, 0] }); const body = world.createDynamicBody({ linearVelocity: [5, 0, 0], position: [0, 0, 0], shape: world.createSphere({ radius: 1.5 }), }); const bodyArray = []; body.toArray(bodyArray); world.takeOneStep(1); console.log(body.position); // [5, 0, 0] world.takeOneStep(1); console.log(body.position); // [10, 0, 0] body.fromArray(bodyArray); // restore console.log(body.position); // [0, 0, 0] ``` -------------------------------- ### Create Different Body Types Source: https://codeberg.org/perplexdotgg/bounce/src/branch/main/docs/documentation Illustrates the creation of various body types within the simulation world: dynamic, static, and kinematic. It shows both direct creation methods and explicit type specification using `BodyType.dynamic`. ```javascript const sphere = world.createSphere({ radius: 1.5 }); const dynamicBody = world.createDynamicBody({ shape: sphere }); const staticBody = world.createStaticBody({ shape: sphere }); const kinematicBody = world.createKinematicBody({ shape: sphere }); // or specify type explicitly const dynamicBody2 = world.createBody({ shape: sphere, type: BodyType.dynamic, }); ``` -------------------------------- ### Apply Forces and Impulses to Bodies Source: https://codeberg.org/perplexdotgg/bounce/src/branch/main/docs/documentation Demonstrates how to apply forces and impulses to dynamic bodies in the simulation. It covers linear and angular impulses for instant velocity changes, and linear and angular forces for gradual acceleration, including options for specifying application points and coordinate frames. ```javascript const world = new World(); const shape = world.createCapsule({ radius: 5.0, height: 2.0 }); const body = world.createDynamicBody({ shape, position: [0, 5, 0] }); // Impulses (instant velocity change) body.applyLinearImpulse({ x: 0, y: 1000, z: 0 }); // at center of mass body.applyAngularImpulse({ x: 0, y: 0, z: 1000 }); // around local axis body.applyImpulse({ x: 0, y: 1000, z: 0 }, { x: 0, y: 7, z: 0 }); // at world point body.applyImpulse({ x: 0, y: 1000, z: 0 }, { x: 0, y: 3, z: 0 }, false); // useLocalFrame // Forces (gradual acceleration over time) body.applyLinearForce({ x: 0, y: 1000, z: 0 }); // at center of mass body.applyAngularForce({ x: 0, y: 0, z: 1000 }); // around local axis body.applyForce({ x: 0, y: 1000, z: 0 }, { x: 0, y: 7, z: 0 }); // at world point body.applyForce({ x: 0, y: 1000, z: 0 }, { x: 0, y: 7, z: 0 }, false); // useLocalFrame body.clearForces(); // forces persist, clear if needed ``` -------------------------------- ### Create Different Body Types in Bounce Source: https://codeberg.org/perplexdotgg/bounce/src/branch/main/docs/documentation_display=source Shows how to create different types of bodies (dynamic, static, kinematic) in the Bounce physics engine. It demonstrates using convenience functions like `createDynamicBody` and explicitly setting the `type` property. ```javascript const sphere = world.createSphere({ radius: 1.5 }); const dynamicBody = world.createDynamicBody({ shape: sphere }); const staticBody = world.createStaticBody({ shape: sphere }); const kinematicBody = world.createKinematicBody({ shape: sphere }); // or specify type explicitly const dynamicBody2 = world.createBody({ shape: sphere, type: BodyType.dynamic, }); ``` -------------------------------- ### Applying Forces and Impulses in Bounce Source: https://codeberg.org/perplexdotgg/bounce/src/branch/main/docs/documentation_display=source Shows how to apply forces (gradual acceleration) and impulses (instant velocity changes) to dynamic bodies in the Bounce physics engine. This includes linear, angular, and point-based applications, as well as clearing persistent forces. ```javascript const world = new World(); const shape = world.createCapsule({ radius: 5.0, height: 2.0 }); const body = world.createDynamicBody({ shape, position: [0, 5, 0] }); // Impulses (instant velocity change) body.applyLinearImpulse({ x: 0, y: 1000, z: 0 }); // at center of mass body.applyAngularImpulse({ x: 0, y: 0, z: 1000 }); // around local axis body.applyImpulse({ x: 0, y: 1000, z: 0 }, { x: 0, y: 7, z: 0 }); // at world point body.applyImpulse({ x: 0, y: 1000, z: 0 }, { x: 0, y: 3, z: 0 }, false); // useLocalFrame // Forces (gradual acceleration over time) body.applyLinearForce({ x: 0, y: 1000, z: 0 }); // at center of mass body.applyAngularForce({ x: 0, y: 0, z: 1000 }); // around local axis body.applyForce({ x: 0, y: 1000, z: 0 }, { x: 0, y: 7, z: 0 }); // at world point body.applyForce({ x: 0, y: 1000, z: 0 }, { x: 0, y: 7, z: 0 }, false); // useLocalFrame body.clearForces(); // forces persist, clear if needed ``` -------------------------------- ### Rollback All Dynamic Bodies in Bounce Source: https://codeberg.org/perplexdotgg/bounce/src/branch/main/docs/documentation_display=source Demonstrates how to serialize only the dynamic bodies in a Bounce physics world for efficient rollback. Multiple states can be stored in buffers, allowing the simulation to revert to previous positions and velocities. This is useful for implementing rewind features. ```javascript const world = new World({ gravity: [0, 0, 0] }); const shape = world.createSphere({ radius: 1.5 }); const body1 = world.createDynamicBody({ shape, position: [0, 0, 10], linearVelocity: [1, 0, 0], }); const body2 = world.createDynamicBody({ shape, position: [0, 0, 20], linearVelocity: [2, 0, 0], }); const body3 = world.createDynamicBody({ shape, position: [0, 0, 30], linearVelocity: [4, 0, 0], }); let bufferIndex = 0; const rollbackBuffers = [ new Float32Array(1000), new Float32Array(1000), new Float32Array(1000), new Float32Array(1000), new Float32Array(1000), ]; for (const body of world.dynamicBodies) { console.log(body.position); // [0, 0, 10], [0, 0, 20], [0, 0, 30] } for (let i = 0; i < rollbackBuffers.length; i++) { world.dynamicBodies.toArray(rollbackBuffers[bufferIndex]); bufferIndex++; world.takeOneStep(1); // 1 second per step } for (const body of world.dynamicBodies) { console.log(body.position); // [10, 0, 10], [20, 0, 20], [40, 0, 30] } ``` -------------------------------- ### Create and Reuse Shapes in Bounce Source: https://codeberg.org/perplexdotgg/bounce/src/branch/main/docs/documentation_display=source Demonstrates how to create shapes and bodies in the Bounce physics engine. It shows both creating a unique shape for each body and efficiently reusing a single shape for multiple bodies to optimize performance. ```javascript const shape = world.createBox({ width: 1, height: 1, depth: 1 }); const body = world.createDynamicBody({ shape: shape }); } // efficient - share one shape: const shape = world.createBox({ width: 1, height: 1, depth: 1 }); for (let i = 0; i < 100; i++) { const body = world.createDynamicBody({ shape: shape }); } ``` -------------------------------- ### Serializing and Restoring a World in Bounce Source: https://codeberg.org/perplexdotgg/bounce/src/branch/main/docs/documentation_display=source Demonstrates how to serialize the entire state of a Bounce physics world into an array and then restore it into another world instance. This is useful for save/load functionality or networking. It involves creating a world, adding bodies, serializing to an array, and deserializing. ```javascript const world1 = new World(); const shape = world.createSphere({ radius: 1.5 }); const body = world.createDynamicBody({ shape, position: [0, 5, 0], }); const world2 = new World(); for (const body of world2.dynamicBodies) { console.log(body.position.y); // no bodies yet } const array = new Float32Array(10000); world1.toArray(array); world2.fromArray(array); for (const body of world2.dynamicBodies) { console.log(body.position.y); // 5 } ``` -------------------------------- ### Raycasting in Bounce Physics Engine Source: https://codeberg.org/perplexdotgg/bounce/src/branch/main/docs/documentation_display=source Shows how to cast rays through the physics scene to detect collisions. It covers different precision levels and options for returning closest hits or all hits. ```javascript import { Ray } from "@perplexdotgg/bounce"; const boxShape = world.createBox({ width: 1, height: 1, depth: 1 }); const body1 = world.createDynamicBody({ shape: boxShape, position: [0, 0, 0] }); const body2 = world.createDynamicBody({ shape: boxShape, position: [0, 5, 0] }); const body3 = world.createDynamicBody({ shape: boxShape, position: [0, 20, 0], }); const ray = Ray.create({ origin: [0, -10, 0], direction: [0, 1, 0], length: 100, }); world.castRay( (result) => console.log(result.body.position, result.pointA), ray, { returnClosestOnly: false, precision: QueryPrecision.preciseWithContacts, } ); // logs 3 hits (unsorted) world.castRay( (result) => console.log(result.body.position, result.pointA), ray, { returnClosestOnly: true, precision: QueryPrecision.preciseWithContacts, } ); // logs 1 hit (closest) world.castRay((result) => console.log(result.body.position), ray, { returnClosestOnly: false, precision: QueryPrecision.approximate, // AABB only, faster }); // logs 3 hits (unsorted) ``` -------------------------------- ### Serialize and Restore a World Source: https://codeberg.org/perplexdotgg/bounce/src/branch/main/docs/documentation Serializes the entire world state to an array and can restore it from an array. ```APIDOC ## Serialize and Restore a World ### Description Serializes the current state of the physics world into a `Float32Array` and can restore the world state from such an array. ### Method `world.toArray(array: Float32Array)` `world.fromArray(array: Float32Array)` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - `array` (Float32Array) - The array to store the serialized world state in, or to restore from. ### Request Example ```javascript const world1 = new World(); // ... add bodies to world1 ... const array = new Float32Array(10000); world1.toArray(array); const world2 = new World(); world2.fromArray(array); ``` ### Response #### Success Response (void) These methods modify the world state or the provided array in place. They do not return a value. #### Response Example ```json // No direct response, state is modified or array is populated. ``` ``` -------------------------------- ### Primitive Shapes Source: https://codeberg.org/perplexdotgg/bounce/src/branch/main/docs/documentation_display=source Demonstrates how to create basic geometric shapes like spheres, boxes, capsules, and cylinders using the world's factory methods. ```APIDOC ## Primitive Shapes Create shapes using the world's factory methods: ```js const sphere = world.createSphere({ radius: 1.5 }); const box = world.createBox({ width: 1, height: 1, depth: 1 }); const capsule = world.createCapsule({ radius: 1.0, height: 2.0 }); const cylinder = world.createCylinder({ halfHeight: 1, radius: 0.5 }); ``` ``` -------------------------------- ### Rollback Dynamic Bodies in Bounce Physics Source: https://codeberg.org/perplexdotgg/bounce/src/branch/main/docs/documentation Demonstrates how to serialize and deserialize dynamic bodies for rollback functionality in the Bounce physics engine. It involves creating bodies, simulating steps, storing states in buffers, and restoring a previous state. ```javascript const world = new World({ gravity: [0, 0, 0] }); const shape = world.createSphere({ radius: 1.5 }); const body1 = world.createDynamicBody({ shape, position: [0, 0, 10], linearVelocity: [1, 0, 0], }); const body2 = world.createDynamicBody({ shape, position: [0, 0, 20], linearVelocity: [2, 0, 0], }); const body3 = world.createDynamicBody({ shape, position: [0, 0, 30], linearVelocity: [4, 0, 0], }); let bufferIndex = 0; const rollbackBuffers = [ new Float32Array(1000), new Float32Array(1000), new Float32Array(1000), new Float32Array(1000), new Float32Array(1000), ]; for (const body of world.dynamicBodies) { console.log(body.position); // [0, 0, 10], [0, 0, 20], [0, 0, 30] } for (let i = 0; i < rollbackBuffers.length; i++) { world.dynamicBodies.toArray(rollbackBuffers[bufferIndex]); bufferIndex++; world.takeOneStep(1); // 1 second per step } for (const body of world.dynamicBodies) { console.log(body.position); // [10, 0, 10], [20, 0, 20], [40, 0, 30] } world.dynamicBodies.fromArray(rollbackBuffers[2]); // restore step 3 for (const body of world.dynamicBodies) { console.log(body.position); // [2, 0, 10], [4, 0, 20], [8, 0, 30] } ``` -------------------------------- ### Query Sphere Intersection with Bounce Physics Source: https://codeberg.org/perplexdotgg/bounce/src/branch/main/docs/documentation_display=source Demonstrates how to query for bodies intersecting with a specified sphere shape within the physics world. It involves defining a sphere and a callback function to handle intersection results. ```javascript const intersectionShape = Sphere.create({ radius: 5 }); const intersectingBodies = []; function onHit(result) { intersectingBodies.push(result.body); return false; // return true to stop early } world.intersectShape(onHit, intersectionShape, { position: { x: 20, y: 7, z: -30 }, }); for (const body of intersectingBodies) { console.log(body.position); } ``` -------------------------------- ### Contact Manifolds Source: https://codeberg.org/perplexdotgg/bounce/src/branch/main/docs/documentation_display=source Query contact manifolds after stepping the simulation to determine which bodies are in contact. ```APIDOC ## Contact Manifolds ### Description After stepping the simulation, you can query contact manifolds to determine which bodies are currently in contact with each other. ### Check if Two Bodies Collided #### Method `world.didBodiesCollide(body1, body2)` #### Endpoint `world.didBodiesCollide` #### Parameters - **body1** (Body) - The first body to check. - **body2** (Body) - The second body to check. #### Request Example ```js const boxShape = world.createBox({ width: 1, height: 2, depth: 1 }); const body1 = world.createDynamicBody({ shape: boxShape, position: [0, 0, 0] }); const body2 = world.createDynamicBody({ shape: boxShape, position: [0, 0.5, 0], }); const body3 = world.createDynamicBody({ shape: boxShape, position: [0, 20, 0], }); world.takeOneStep(1 / 60); console.log(world.didBodiesCollide(body1, body2)); // true console.log(world.didBodiesCollide(body1, body3)); // false ``` #### Response - **boolean** - Returns `true` if the bodies are colliding, `false` otherwise. ### Iterate Over Contact Manifolds #### Method `world.getContacts(body)` or `world.getContacts()` #### Endpoint `world.getContacts` #### Parameters - **body** (Body, optional) - If provided, returns contacts involving this specific body. If omitted, returns all contacts in the world. #### Request Example ```js const boxShape = world.createBox({ width: 1, height: 2, depth: 1 }); const body1 = world.createDynamicBody({ shape: boxShape, position: [0, 0, 0] }); const body2 = world.createDynamicBody({ shape: boxShape, position: [0, 0.5, 0], }); const body3 = world.createDynamicBody({ shape: boxShape, position: [0, -1.5, 0], }); const body4 = world.createDynamicBody({ shape: boxShape, position: [0, 20, 0], }); const body5 = world.createDynamicBody({ shape: boxShape, position: [0, 20.5, 0], }); world.takeOneStep(1 / 60); // Get contacts for body1 const contactsBody1 = world.getContacts(body1); console.log(contactsBody1.length); // Should be 1 (contact with body2) // Get all contacts in the world const allContacts = world.getContacts(); console.log(allContacts.length); // Should be 1 (contact between body1 and body2) ``` #### Response - **Array** - An array of `ContactManifold` objects. Each object represents a contact between two bodies and contains information about the contact points, normals, and penetration depths. #### Response Example ```json [ { "body": { /* Body object details */ }, "contactPoints": [ { "pointA": {"x": 0, "y": 0.5, "z": 0}, "pointB": {"x": 0, "y": 0, "z": 0}, "normal": {"x": 0, "y": 1, "z": 0}, "penetration": 0.5 } ] } ] ``` ``` -------------------------------- ### Iterating Contact Manifolds in Bounce Source: https://codeberg.org/perplexdotgg/bounce/src/branch/main/docs/documentation_display=source Demonstrates how to iterate through contact manifolds in the Bounce physics engine. This includes iterating all manifolds in the world, manifolds involving a specific body, and manifolds between two specific bodies. Assumes a 'world' object and 'body1', 'body2' are defined. ```javascript world.takeOneStep(1 / 60); // all manifolds involving body1 for (const manifold of world.iterateContactManifolds(body1)) { console.log([manifold.bodyA, manifold.bodyB]); } // manifolds between body1 and body2 for (const manifold of world.iterateContactManifolds(body1, body2)) { console.log([manifold.bodyA, manifold.bodyB]); } // all manifolds in world for (const manifold of world.iterateContactManifolds()) { console.log([manifold.bodyA, manifold.bodyB]); } ``` -------------------------------- ### Efficiently Reuse Shapes Across Bodies (JavaScript) Source: https://codeberg.org/perplexdotgg/bounce/src/branch/main/docs/documentation Demonstrates the efficiency of reusing a single shape instance across multiple bodies instead of creating a new shape for each body. This approach significantly reduces memory and computational overhead. ```javascript // inefficient - new shape per body: for (let i = 0; i < 100; i++) { const shape = world.createBox({ width: 1, height: 1, depth: 1 }); const body = world.createDynamicBody({ shape: shape }); } // efficient - share one shape: const shape = world.createBox({ width: 1, height: 1, depth: 1 }); for (let i = 0; i < 100; i++) { const body = world.createDynamicBody({ shape: shape }); } ``` -------------------------------- ### Estimate Collision Response in Bounce Source: https://codeberg.org/perplexdotgg/bounce/src/branch/main/docs/documentation Demonstrates how to estimate the velocity changes resulting from a collision without actually applying them using `estimateCollisionResponse`. This is useful for predictive physics. It requires importing `Body`, `BodyType`, and `Sphere` from `@perplexdotgg/bounce`. ```javascript const boxShape = world.createBox({ width: 1, height: 1, depth: 1 }); const boxBody = world.createDynamicBody({ shape: boxShape, position: [0, 0, 0], mass: 5.0, }); // body created outside world import { Body, BodyType, Sphere } from "@perplexdotgg/bounce"; const sphereShape = Sphere.create({ radius: 1.5 }); const sphereBody = Body.create({ shape: sphereShape, position: [2, 0, 0], mass: 10.0, linearVelocity: [5, 0, 0], type: BodyType.dynamic, }); // estimate velocity change (query only, doesn't apply) // Note: EstimateCollisionResponseResult may need internal import const result = { deltaLinearVelocityA: null, deltaAngularVelocityA: null, deltaLinearVelocityB: null, deltaAngularVelocityB: null, }; world.estimateCollisionResponse(result, sphereBody, boxBody); console.log(result.deltaLinearVelocityA, result.deltaAngularVelocityA); console.log(result.deltaLinearVelocityB, result.deltaAngularVelocityB); ``` -------------------------------- ### Create Hinge Constraint in Bounce Source: https://codeberg.org/perplexdotgg/bounce/src/branch/main/docs/documentation Demonstrates how to create a Hinge Constraint in Bounce, allowing rotation around a single axis. It includes optional parameters for limits, motor, and various constraint parts. ```javascript const hinge = world.createHingeConstraint({ // required bodyA: bodyA, bodyB: bodyB, // everything below is optional, default values are shown here referenceFrame: ReferenceFrame.local, pointA: { x: 0, y: 0, z: 0 }, // pivot point in bodyA pointB: { x: 0, y: 0, z: 0 }, // pivot point in bodyB hingeA: { x: 1, y: 0, z: 0 }, // hinge axis in bodyA hingeB: { x: 1, y: 0, z: 0 }, // hinge axis in bodyB normalA: { x: 0, y: 1, z: 0 }, // normal direction normalB: { x: 0, y: 1, z: 0 }, // normal direction minHingeAngle: -Math.PI / 2, // optional maxHingeAngle: Math.PI / 2, // optional maxFrictionTorque: 0, targetAngularSpeed: 0, targetAngle: 0, motor: { mode: MotorMode.Off, minForce: -Infinity, maxForce: +Infinity, minTorque: -Infinity, maxTorque: +Infinity, spring: { mode: SpringMode.UseFrequency, damping: 1.0, frequency: 2.0, stiffness: 2.0, }, }, pointConstraintPart: { options: { positionBaumgarte: 0.8, velocityBaumgarte: 1.0, strength: 1.0, }, }, rotationConstraintPart: { options: { positionBaumgarte: 0.8, velocityBaumgarte: 1.0, strength: 1.0, }, }, rotationLimitsConstraintPart: { options: { positionBaumgarte: 0.8, velocityBaumgarte: 1.0, strength: 1.0, }, }, motorConstraintPart: { options: { positionBaumgarte: 0.8, velocityBaumgarte: 1.0, strength: 1.0, }, }, }); ``` -------------------------------- ### Update Body Properties and Commit Changes Source: https://codeberg.org/perplexdotgg/bounce/src/branch/main/docs/documentation Demonstrates how to update a body's properties, such as its position, and the importance of calling `commitChanges()` for the world to recognize these modifications. This is crucial for ensuring that subsequent physics queries, like shape intersections, reflect the updated state. ```javascript import { Sphere } from "@perplexdotgg/bounce"; function onHit(result) { console.log("hit"); } const queryShape = Sphere.create({ radius: 5 }); const world = new World(); const shape = world.createSphere({ radius: 2 }); const body = world.createKinematicBody({ shape: shape, position: [0, 0, 0] }); console.log(body.position); // [0, 0, 0] world.intersectShape(onHit, queryShape, { position: { x: 0, y: 10, z: 0 } }); // no hit body.position.set([0, 5, 0]); console.log(body.position); // [0, 5, 0] world.intersectShape(onHit, queryShape, { position: { x: 0, y: 10, z: 0 } }); // still no hit! (stale) body.commitChanges(); // update world world.intersectShape(onHit, queryShape, { position: { x: 0, y: 10, z: 0 } }); // hit! (updated) ``` -------------------------------- ### Configuring Collision Filtering in Bounce Source: https://codeberg.org/perplexdotgg/bounce/src/branch/main/docs/documentation_display=source Explains how to control which bodies interact using collision groups and masks. It demonstrates creating bit flags for groups and assigning them to bodies using `belongsToGroups` and `collidesWithGroups` properties. ```javascript import { CollisionFilter } from '@perplexdotgg/bounce'; const flags = CollisionFilter.createBitFlags(["Player", "Monster", "Ghost"] as const); const shape = world.createSphere({ radius: 2.0 }); const player = world.createKinematicBody({ shape: shape, position: [0, 0, 0], belongsToGroups: flags.Player, collidesWithGroups: flags.Monster, }); const ghost = world.createKinematicBody({ shape: shape, position: [-1.5, 0, 0], belongsToGroups: flags.Ghost, collidesWithGroups: flags.None, // collides with nothing }); const monster1 = world.createKinematicBody({ shape: shape, position: [+1.5, 0, 0], belongsToGroups: flags.Monster, collidesWithGroups: flags.Player | flags.Monster, }); const monster2 = world.createKinematicBody({ shape: shape, position: [+2.5, 0, 0], belongsToGroups: flags.Monster, collidesWithGroups: flags.Player | flags.Monster, }); // Result: player↔monster1, monster1↔monster2 ``` -------------------------------- ### Iterate Over Contact Manifolds in Bounce Physics Source: https://codeberg.org/perplexdotgg/bounce/src/branch/main/docs/documentation_display=source Demonstrates how to iterate through contact manifolds in the physics world. This allows detailed inspection of all contacts involving specific bodies or the entire world. ```javascript const boxShape = world.createBox({ width: 1, height: 2, depth: 1 }); const body1 = world.createDynamicBody({ shape: boxShape, position: [0, 0, 0] }); const body2 = world.createDynamicBody({ shape: boxShape, position: [0, 0.5, 0], }); const body3 = world.createDynamicBody({ shape: boxShape, position: [0, -1.5, 0], }); const body4 = world.createDynamicBody({ shape: boxShape, position: [0, 20, 0], }); const body5 = world.createDynamicBody({ ``` -------------------------------- ### Translate Shape Centers in Local Space (JavaScript) Source: https://codeberg.org/perplexdotgg/bounce/src/branch/main/docs/documentation Explains how to offset a shape's center of mass relative to the body's origin using the 'position' property during shape creation. This allows for precise placement and orientation of shapes, such as aligning a capsule's bottom at the origin. ```javascript // default: centered at origin const sphere1 = world.createSphere({ radius: 1.0 }); const body1 = world.createDynamicBody({ shape: sphere1 }); // translated from origin const sphere2 = world.createSphere({ radius: 1.0, position: [3, 0, 0] }); const body2 = world.createDynamicBody({ shape: sphere2 }); // character controller capsule: bottom at origin const radius = 1.0; const height = 2.0; const halfCapsuleHeight = radius + height / 2; const shape = world.createCapsule({ radius, height, position: [0, -halfCapsuleHeight, 0], }); const body = world.createDynamicBody({ shape: shape }); ``` -------------------------------- ### Triangle Mesh Creation Source: https://codeberg.org/perplexdotgg/bounce/src/branch/main/docs/documentation Creates a triangle mesh shape from vertex positions and face indices. Useful for complex static geometry. An optional `forceCreateConvexHull` parameter can be set. ```APIDOC ## POST /world/createTriangleMesh ### Description Creates a triangle mesh shape from vertex positions and face indices. Useful for complex static geometry like terrain or building interiors. ### Method POST ### Endpoint /world/createTriangleMesh ### Parameters #### Request Body - **vertexPositions** (Float32Array) - Required - An array of vertex positions (x, y, z triplets). - **faceIndices** (Uint32Array) - Required - An array of face indices defining the triangles. - **forceCreateConvexHull** (boolean) - Optional - If true, forces convex hull creation. Defaults to false. ### Request Example ```json { "vertexPositions": [0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0], "faceIndices": [0, 1, 2, 1, 3, 2], "forceCreateConvexHull": false } ``` ### Response #### Success Response (200) - **shape** (object) - The created triangle mesh shape object. #### Response Example ```json { "shape": "" } ``` ``` -------------------------------- ### Serializing a Single Body in Bounce Source: https://codeberg.org/perplexdotgg/bounce/src/branch/main/docs/documentation_display=source Explains how to serialize the state of a single body in the Bounce physics engine to an array and then restore it. This allows for individual body state management, useful for specific rollback or replication scenarios. It involves creating a body, serializing it, simulating steps, and then restoring. ```javascript const world = new World({ gravity: [0, 0, 0] }); const body = world.createDynamicBody({ linearVelocity: [5, 0, 0], position: [0, 0, 0], shape: world.createSphere({ radius: 1.5 }), }); const bodyArray = []; body.toArray(bodyArray); world.takeOneStep(1); console.log(body.position); // [5, 0, 0] world.takeOneStep(1); console.log(body.position); // [10, 0, 0] body.fromArray(bodyArray); // restore console.log(body.position); // [0, 0, 0] ``` -------------------------------- ### Performing Overlap Tests in Bounce Source: https://codeberg.org/perplexdotgg/bounce/src/branch/main/docs/documentation_display=source Illustrates how to use scene queries to find bodies that overlap with a given shape at a specific position without advancing the simulation. This is useful for detecting collisions or interactions in a static scene. ```javascript import { World, Sphere } from "@perplexdotgg/bounce"; const world = new World(); const ground = world.createStaticBody({ position: { x: 0, y: 0, z: 0 }, orientation: { x: 0, y: 0, z: 0, w: 1 }, shape: world.createBox({ width: 100, height: 5, depth: 100 }), }); const capsuleShape = world.createCapsule({ radius: 1.0, height: 2.0 }); // 100 random capsules for (let i = 0; i < 100; i++) { const x = (Math.random() - 0.5) * 100; const y = 15 + (Math.random() - 0.5) * 10; const z = (Math.random() - 0.5) * 100; const body = world.createDynamicBody({ ``` -------------------------------- ### Shape Reuse Source: https://codeberg.org/perplexdotgg/bounce/src/branch/main/docs/documentation Demonstrates efficient shape reuse by creating a single shape and applying it to multiple bodies, rather than creating a new shape for each body. ```APIDOC ## Efficient Shape Reuse ### Description Shapes can be shared across multiple bodies for efficiency. This example shows how to create one shape and reuse it for multiple dynamic bodies. ### Code Example ```javascript // Create a single shape const sharedShape = world.createBox({ width: 1, height: 1, depth: 1 }); // Reuse the shape for multiple bodies for (let i = 0; i < 100; i++) { const body = world.createDynamicBody({ shape: sharedShape }); } ``` ``` -------------------------------- ### Perform Raycasting Queries in the Scene Source: https://codeberg.org/perplexdotgg/bounce/src/branch/main/docs/documentation Cast a ray through the scene to detect collisions. The `castRay` method can return all hits or only the closest hit, and supports different precision levels for performance optimization. The callback function receives detailed hit information, including the body and the point of contact. ```typescript import { Ray } from "@perplexdotgg/bounce"; const boxShape = world.createBox({ width: 1, height: 1, depth: 1 }); const body1 = world.createDynamicBody({ shape: boxShape, position: [0, 0, 0] }); const body2 = world.createDynamicBody({ shape: boxShape, position: [0, 5, 0] }); const body3 = world.createDynamicBody({ shape: boxShape, position: [0, 20, 0], }); const ray = Ray.create({ origin: [0, -10, 0], direction: [0, 1, 0], length: 100, }); world.castRay( (result) => console.log(result.body.position, result.pointA), ray, { returnClosestOnly: false, precision: QueryPrecision.preciseWithContacts, } ); // logs 3 hits (unsorted) world.castRay( (result) => console.log(result.body.position, result.pointA), ray, { returnClosestOnly: true, precision: QueryPrecision.preciseWithContacts, } ); // logs 1 hit (closest) world.castRay((result) => console.log(result.body.position), ray, { returnClosestOnly: false, precision: QueryPrecision.approximate, // AABB only, faster }); // logs 3 hits (unsorted) ``` -------------------------------- ### Create Convex Hull from Point Cloud (JavaScript) Source: https://codeberg.org/perplexdotgg/bounce/src/branch/main/docs/documentation Generates a convex hull shape from a flat array of vertex positions. Optional parameters include convexRadius, hullTolerance, maxPoints, and maxVertexIndices to control the hull generation process. This shape can then be used to create dynamic bodies. ```javascript const vertexPositions = new Float32Array([0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1]); const shape = world.createConvexHull( vertexPositions, // Float32Array of vertex positions 0.02, // convexRadius (optional, default 0.02) 1e-3, // hullTolerance (optional, default 1e-3 = 0.001) 1000, // maxPoints (optional, default 1000) 1000 // maxVertexIndices (optional, default 1000) ); const body = world.createDynamicBody({ shape: shape, position: [0, 0, 5] }); ``` -------------------------------- ### Create Primitive Shapes in Bounce Physics Source: https://codeberg.org/perplexdotgg/bounce/src/branch/main/docs/documentation Illustrates how to create different primitive shapes for collision geometry within the Bounce physics engine using the `world` object's factory methods. Supported shapes include spheres, boxes, capsules, and cylinders, each with their specific creation parameters. ```typescript const sphere = world.createSphere({ radius: 1.5 }); const box = world.createBox({ width: 1, height: 1, depth: 1 }); const capsule = world.createCapsule({ radius: 1.0, height: 2.0 }); const cylinder = world.createCylinder({ halfHeight: 1, radius: 0.5 }); ```