Files
pelpanagiotis a7c53a08a0 Initial commit: Unity Needle AR Menu project with MenuScene and SampleScene web apps
Add root .gitignore for Unity Library/Temp/Logs, IDE folders, and node_modules.
Include Assets, Needle TypeScript (MenuController, asset picker, WebXR), and project configuration.

Made-with: Cursor
2026-04-19 22:41:05 +03:00

98 lines
4.7 KiB
Markdown

# Needle Engine — Physics Reference
Needle Engine uses Rapier (WASM) for physics. The Rapier physics backend is registered automatically at engine startup — no manual initialization needed. The WASM binary loads lazily on first use (when a collider or rigidbody component is created), so there's no upfront cost if physics aren't used.
`NEEDLE_ENGINE_MODULES.RAPIER_PHYSICS.load()` and `.ready()` exist for advanced use cases (e.g. accessing the raw Rapier API directly) but are **not required** for normal physics usage — just add `Rigidbody` and collider components and they work.
## Colliders
Pick the shape that best fits the object — don't default to BoxCollider for everything.
```ts
import { BoxCollider, SphereCollider, CapsuleCollider, MeshCollider } from "@needle-tools/engine";
// Quick setup — auto-fits to mesh bounds, optionally adds rigidbody:
BoxCollider.add(myMesh, { rigidbody: true });
SphereCollider.add(myMesh, { rigidbody: true });
// Or add manually and configure:
const box = myObject.addComponent(BoxCollider);
// box.size, box.center
const sphere = myObject.addComponent(SphereCollider);
// sphere.radius (default: 0.5), sphere.center
const capsule = myObject.addComponent(CapsuleCollider);
// capsule.radius (default: 0.5), capsule.height (default: 2) — use for characters, poles, bottles
const mesh = myObject.addComponent(MeshCollider);
// mesh.convex = true for dynamic objects (required with Rigidbody)
// mesh.convex = false for static concave geometry (walls, terrain)
```
Use `SphereCollider` for balls, `CapsuleCollider` for characters/cylinders, `MeshCollider` for complex static geometry. Set `isTrigger = true` for trigger volumes.
## Rigidbody
```ts
import { Rigidbody } from "@needle-tools/engine";
const rb = myObject.getComponent(Rigidbody);
rb.useGravity = true;
rb.mass = 2.0;
rb.isKinematic = false; // true = not affected by forces
// Forces and impulses
rb.applyForce(new Vector3(0, 10, 0)); // continuous force (acceleration, applied over time)
rb.setForce(new Vector3(0, 10, 0)); // reset + apply new force in one call
rb.applyImpulse(new Vector3(5, 0, 0)); // instant velocity change (use for jumps, hits, explosions)
// Velocity — read and write directly (ALWAYS use these instead of accessing internals)
const vel = rb.getVelocity(); // current linear velocity (Vector3)
rb.setVelocity(new Vector3(0, 0, 0)); // set linear velocity directly
rb.setVelocity(0, 0, 0); // also accepts x, y, z args
const angVel = rb.getAngularVelocity(); // current angular velocity
rb.setAngularVelocity(new Vector3(0, 0, 0));
rb.smoothedVelocity; // averaged over ~10 frames (useful for UI/predictions)
// Stopping / resetting motion
rb.resetVelocities(); // zero out both linear and angular velocity
rb.resetForces(); // cancel all applied forces
rb.resetTorques(); // cancel all applied torques
rb.resetForcesAndTorques(); // cancel both forces and torques
// Positioning
rb.teleport({ x: 0, y: 5, z: 0 }); // move without physics (resets velocities/forces)
// Sleep state
rb.wakeUp(); // wake a sleeping body
rb.isSleeping; // check if body is asleep
```
**Force vs Impulse:** `applyForce()` is for continuous effects (thrusters, wind) — call every frame. `applyImpulse()` is for instant one-shot velocity changes (jumps, hits, button press) — call once.
**Never access `rb._body` or internal Rapier handles directly.** All velocity and force control is available through the public methods above. For example, to brake a rolling ball on key release, use `rb.getVelocity()` + `rb.setVelocity()` — not `(rb as any)._body.linvel()`.
Key properties: `mass`, `autoMass`, `useGravity`, `gravityScale` (multiplier, 0 = no gravity), `drag` (linear damping), `angularDrag`, `isKinematic`, `lockPositionX/Y/Z`, `lockRotationX/Y/Z`, `sleepThreshold`, `dominanceGroup`, `collisionDetectionMode` (Discrete or Continuous).
API reference: https://engine.needle.tools/docs/api/Rigidbody
## Physics callbacks
Defined on components (require a Collider on the same GameObject):
```ts
onCollisionEnter(col: Collision) { /* hit something */ }
onCollisionStay(col: Collision) { /* still touching */ }
onCollisionExit(col: Collision) { /* separated */ }
onTriggerEnter(col: Collision) { /* entered trigger */ }
onTriggerStay(col: Collision)
onTriggerExit(col: Collision)
```
## Raycasting
```ts
// Visual raycast (hits any visible geometry, no collider needed, BVH-accelerated)
const hits = this.context.physics.raycast();
// Physics engine raycast (hits Rapier colliders only)
const hit = this.context.physics.engine?.raycast(origin, direction);
```