RigidBody
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
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.
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