import type { PhysicsWorld } from "./physicsWorld.js"; import type { AxisInput } from "../input/axisInput.js"; export interface GripCurve { points: readonly (readonly [number, number])[]; } /** * Piecewise-linear tire-grip curve: normalized lateral slip → available grip (0..1). Grip peaks near * the breakaway slip then falls off as the tire slides — the shape that separates a planted corner * from a drift. Points are read in ascending slip order; ends clamp. */ export declare function sampleGripCurve(curve: GripCurve, slip: number): number; export declare const DEFAULT_GRIP_CURVE: GripCurve; export interface WheelSpec { offset: readonly [number, number, number]; radius?: number; restLength?: number; steered?: boolean; powered?: boolean; handbrakeLocks?: boolean; } export interface WheelState { worldX: number; worldY: number; worldZ: number; grounded: boolean; compression: number; steerAngle: number; } export interface VehicleBodyConfig { position: readonly [number, number, number]; heading?: number; chassisHalfExtents?: readonly [number, number, number]; mass?: number; wheels?: readonly WheelSpec[]; engineAccel?: number; brakeAccel?: number; topSpeed?: number; reverseSpeed?: number; turnRate?: number; turnSpeedRef?: number; grip?: GripCurve; gripStrength?: number; handbrakeGrip?: number; rollingResistance?: number; suspensionRest?: number; suspensionStiffness?: number; suspensionDamping?: number; groundHeight?: (x: number, z: number) => number; surfaceFriction?: (x: number, z: number) => number; } /** * Arcade vehicle over the {@link PhysicsWorld} rigid-body sim. The chassis is a single box body driven * by an {@link AxisInput}: per-wheel suspension is a spring-damper held with G3's `springJoint` against * the sampled ground, drive/brake push along the heading, and a tire-grip curve bleeds lateral velocity * (cornering, and drift under handbrake). Because the chassis is a physics body it still collides — that * contact feeds crash damage. Call `update(dt, input)` before the shared `world.step(dt)`. */ export declare class VehicleBody { heading: number; readonly chassis: number; private readonly world; private readonly wheels; private readonly springs; private readonly wheelStates; private readonly engineAccel; private readonly brakeAccel; private readonly topSpeed; private readonly reverseSpeed; private readonly turnRate; private readonly turnSpeedRef; private readonly grip; private readonly gripStrength; private readonly handbrakeGrip; private readonly rollingResistance; private readonly suspensionRest; private readonly groundHeight; private readonly surfaceFriction; private groundedCount; constructor(world: PhysicsWorld, config: VehicleBodyConfig); /** * A wheel's local offset rotated by the current heading — the ground-side mount and the * chassis-side spring anchor both derive from this, so the suspension axis stays vertical (not a * mix of rotated and unrotated ends) as the chassis turns. */ private rotateOffset; private wheelMount; get position(): [number, number, number]; get forward(): [number, number]; /** Signed forward speed along the heading (negative = reversing). */ get speed(): number; get grounded(): boolean; wheelState(index: number): WheelState | null; get wheelCount(): number; resetTo(position: readonly [number, number, number], heading: number): void; update(dt: number, input: AxisInput): void; private updateSuspension; remove(): void; } export declare function createVehicleBody(world: PhysicsWorld, config: VehicleBodyConfig): VehicleBody;