# RigidBody

> Talos next · Since 0.6; changed in next

Present on `ctx.body` when the entity has a physics body — a `rigidbody` component, or a `collider`, which makes a static one.

For a flight model, a vehicle, wind, a blast or a projectile: push a dynamic body with forces and impulses and let the solver move it. **Which tick a force acts on.** Physics steps at the top of every tick, before behaviours run. A force or torque added in `update` is summed with every other one added before the next step, acts through the whole of that step (every substep of it), and is then cleared. So a force acts on exactly one tick, the next, and a thrust that lasts is added again every tick — which is what `update` does anyway. An impulse is not summed: it changes the velocity at once, and {@link RigidBody.velocity} reads the change back on the next line. **A body that cannot move.** Only a `"dynamic"` body is moved. A push on a kinematic or static body (or through a handle kept after its body was removed) changes nothing, does not throw, and is counted on `GET /perf` → `unwired.body_push`. A NaN or infinite vector, or a `space` other than `"world"` or `"local"`, throws a `RangeError`. A sleeping body is woken. A body held with `ctx.world.hold` takes forces, but the hold sets its velocity before each step, so an impulse on one is overwritten. `ts // Hover: thrust equal to weight (m·g, with the default meta.gravity of [0, -9.81, 0]), every tick. update(ctx) { const body = ctx.body! body.addForce([0, body.mass * 9.81, 0]) } ```

## Signature

```ts
export interface RigidBody {
  /** Adds `force`, newtons, at the centre of mass, for the next physics step. Calls in one tick add up. */
  addForce(force: Vec3, space?: ForceSpace): void
  /**
   * Adds `force` at `point`, both in `space`, for the next physics step: the force, plus the torque
   * `(point − centerOfMass) × force`, taken from where the body is now. Four of these at the rotor hubs,
   * in `"local"`, are a quadcopter.
   */
  addForceAtPoint(force: Vec3, point: Vec3, space?: ForceSpace): void
  /** Adds `torque`, N·m, about the centre of mass, for the next physics step (right-hand rule: +Y turns left). */
  addTorque(torque: Vec3, space?: ForceSpace): void
  /**
   * Changes the velocity by `impulse / mass` now, N·s — a kick, a blast, a launch. At a `point` (in
   * `space`; null or omitted for the centre of mass) it changes the spin too.
   */
  applyImpulse(impulse: Vec3, point?: Vec3 | null, space?: ForceSpace): void
  /** Changes the spin now by the inverse inertia times `impulse`, N·m·s. */
  applyTorqueImpulse(impulse: Vec3, space?: ForceSpace): void
  /** How the solver treats the body; null once the body is gone. */
  readonly kind: RigidBodyKind | null
  /**
   * Linear velocity, m/s, world axes. A kinematic body reports the velocity it is driven at.
   *
   * Assignable on a **dynamic** body: it applies the impulse
   * `mass × (v − velocity)` now, so the next line reads `v` back and the spin is untouched. On a kinematic
   * or static body it throws `body.velocity-not-dynamic` — move those by writing `entity.position`.
   */
  velocity: Vec3
  /** Angular velocity, rad/s, world axes. */
  readonly angularVelocity: Vec3
  /** kg. A static or kinematic body reports what its collider would weigh. */
  readonly mass: number
  /** World position of the centre of mass — where {@link RigidBody.addForce} acts. */
  readonly centerOfMass: Vec3
  /**
   * Principal moments of inertia, kg·m², about the centre of mass. The axes are the body's own for a box, a
   * sphere or a capsule. An angular acceleration about one of them is `torque / inertia`.
   */
  readonly inertia: Vec3
  /** The `wheel` entities riding on this body — its vehicle's and its own — each as its {@link Wheel}. Empty when it has none. */
  readonly wheels: Wheel[]
}
```

Import: `import type { RigidBody } from "@argus/api"`

## Members

| Member | Signature | Description |
|---|---|---|
| `addForce` | `addForce(force: Vec3, space?: ForceSpace): void` | Adds `force`, newtons, at the centre of mass, for the next physics step. Calls in one tick add up. |
| `addForceAtPoint` | `addForceAtPoint(force: Vec3, point: Vec3, space?: ForceSpace): void` | Adds `force` at `point`, both in `space`, for the next physics step: the force, plus the torque `(point − centerOfMass) × force`, taken from where the body is now. Four of these at the rotor hubs, in `"local"`, are a quadcopter. |
| `addTorque` | `addTorque(torque: Vec3, space?: ForceSpace): void` | Adds `torque`, N·m, about the centre of mass, for the next physics step (right-hand rule: +Y turns left). |
| `applyImpulse` | `applyImpulse(impulse: Vec3, point?: Vec3 \| null, space?: ForceSpace): void` | Changes the velocity by `impulse / mass` now, N·s — a kick, a blast, a launch. At a `point` (in `space`; null or omitted for the centre of mass) it changes the spin too. |
| `applyTorqueImpulse` | `applyTorqueImpulse(impulse: Vec3, space?: ForceSpace): void` | Changes the spin now by the inverse inertia times `impulse`, N·m·s. |
| `kind` | `readonly kind: RigidBodyKind \| null` | How the solver treats the body; null once the body is gone. |
| `velocity` | `velocity: Vec3` | Linear velocity, m/s, world axes. A kinematic body reports the velocity it is driven at. Assignable on a **dynamic** body: it applies the impulse `mass × (v − velocity)` now, so the next line reads `v` back and the spin is untouched. On a kinematic or static body it throws `body.velocity-not-dynamic` — move those by writing `entity.position`. |
| `angularVelocity` | `readonly angularVelocity: Vec3` | Angular velocity, rad/s, world axes. |
| `mass` | `readonly mass: number` | kg. A static or kinematic body reports what its collider would weigh. |
| `centerOfMass` | `readonly centerOfMass: Vec3` | World position of the centre of mass — where {@link RigidBody.addForce} acts. |
| `inertia` | `readonly inertia: Vec3` | Principal moments of inertia, kg·m², about the centre of mass. The axes are the body's own for a box, a sphere or a capsule. An angular acceleration about one of them is `torque / inertia`. |
| `wheels` | `readonly wheels: Wheel[]` | The `wheel` entities riding on this body — its vehicle's and its own — each as its {@link Wheel}. Empty when it has none. |

## Example

The tested fixture `fixtures/host/hover.ts`.

```ts
import type { Behavior, Ctx, Vec3 } from "@argus/api"
// docs/API.md, "Forces, torques and impulses": a body that hovers (thrust = m·g), and the same lift
// as four rotors in the airframe's own frame plus a yaw torque. Typechecked by packages/api's tests.
const HUBS: Vec3[] = [[0.3, 0, 0.3], [-0.3, 0, 0.3], [0.3, 0, -0.3], [-0.3, 0, -0.3]]

function hover(ctx: Ctx) {
  const body = ctx.body
  if (!body) return
  if (ctx.props["rotors"] !== true) {
    body.addForce([0, body.mass * 9.81, 0])
    return
  }
  for (const h of HUBS) body.addForceAtPoint([0, (body.mass * 9.81) / 4, 0], h, "local")
  body.addTorque([0, (ctx.props["yaw"] as number | undefined) ?? 0, 0], "local")
}

export default {
  // The first physics step runs before the first update; this is its thrust.
  init(ctx) { hover(ctx) },
  update(ctx) { hover(ctx) },
} satisfies Behavior
```
