planck-js
Version:
2D JavaScript/TypeScript physics engine for cross-platform HTML5 game development
1,600 lines (1,599 loc) • 135 kB
TypeScript
// Generated by dts-bundle-generator v9.5.1
/** 2D vector */
export interface Vec2Value {
x: number;
y: number;
}
/** @hidden @deprecated Use new keyword. */
export function Vec2(x: number, y: number): Vec2;
/** @hidden @deprecated Use new keyword. */
export function Vec2(obj: Vec2Value): Vec2;
/** @hidden @deprecated Use new keyword. */
export function Vec2(): Vec2;
/** 2D vector */
export declare class Vec2 {
x: number;
y: number;
constructor(x: number, y: number);
constructor(obj: Vec2Value);
constructor();
static zero(): Vec2;
/** @hidden */
static neo(x: number, y: number): Vec2;
static clone(v: Vec2Value): Vec2;
/** @hidden */
toString(): string;
/**
* Does this vector contain finite coordinates?
*/
static isValid(obj: any): boolean;
static assert(o: any): void;
clone(): Vec2;
/**
* Set this vector to all zeros.
*
* @returns this
*/
setZero(): Vec2;
set(x: number, y: number): Vec2;
set(value: Vec2Value): Vec2;
/**
* Set this vector to some specified coordinates.
*
* @returns this
*/
setNum(x: number, y: number): this;
/**
* Set this vector to some specified coordinates.
*
* @returns this
*/
setVec2(value: Vec2Value): this;
/**
* Set linear combination of v and w: `a * v + b * w`
*/
setCombine(a: number, v: Vec2Value, b: number, w: Vec2Value): Vec2;
setMul(a: number, v: Vec2Value): Vec2;
/**
* Add a vector to this vector.
*
* @returns this
*/
add(w: Vec2Value): Vec2;
/**
* Add linear combination of v and w: `a * v + b * w`
*/
addCombine(a: number, v: Vec2Value, b: number, w: Vec2Value): Vec2;
addMul(a: number, v: Vec2Value): Vec2;
/**
* @deprecated Use subCombine or subMul
*/
wSub(a: number, v: Vec2Value, b?: number, w?: Vec2Value): Vec2;
/**
* Subtract linear combination of v and w: `a * v + b * w`
*/
subCombine(a: number, v: Vec2Value, b: number, w: Vec2Value): Vec2;
subMul(a: number, v: Vec2Value): Vec2;
/**
* Subtract a vector from this vector
*
* @returns this
*/
sub(w: Vec2Value): Vec2;
/**
* Multiply this vector by a scalar.
*
* @returns this
*/
mul(m: number): Vec2;
/**
* Get the length of this vector (the norm).
*
* For performance, use this instead of lengthSquared (if possible).
*/
length(): number;
/**
* Get the length squared.
*/
lengthSquared(): number;
/**
* Convert this vector into a unit vector.
*
* @returns old length
*/
normalize(): number;
/**
* Returns a new unit vector from the provided vector.
*
* @returns new unit vector
*/
static normalize(v: Vec2Value): Vec2;
/**
* Get the length of this vector (the norm).
*
* For performance, use this instead of lengthSquared (if possible).
*/
static lengthOf(v: Vec2Value): number;
/**
* Get the length squared.
*/
static lengthSquared(v: Vec2Value): number;
static distance(v: Vec2Value, w: Vec2Value): number;
static distanceSquared(v: Vec2Value, w: Vec2Value): number;
static areEqual(v: Vec2Value, w: Vec2Value): boolean;
/**
* Get the skew vector such that dot(skew_vec, other) == cross(vec, other)
*/
static skew(v: Vec2Value): Vec2;
/** Dot product on two vectors */
static dot(v: Vec2Value, w: Vec2Value): number;
/** Cross product between two vectors */
static cross(v: Vec2Value, w: Vec2Value): number;
/** Cross product between a vector and a scalar */
static cross(v: Vec2Value, w: number): Vec2;
/** Cross product between a scalar and a vector */
static cross(v: number, w: Vec2Value): Vec2;
/** Cross product on two vectors */
static crossVec2Vec2(v: Vec2Value, w: Vec2Value): number;
/** Cross product on a vector and a scalar */
static crossVec2Num(v: Vec2Value, w: number): Vec2;
/** Cross product on a vector and a scalar */
static crossNumVec2(v: number, w: Vec2Value): Vec2;
/** Returns `a + (v x w)` */
static addCross(a: Vec2Value, v: Vec2Value, w: number): Vec2;
/** Returns `a + (v x w)` */
static addCross(a: Vec2Value, v: number, w: Vec2Value): Vec2;
/**
* Returns `a + (v x w)`
*/
static addCrossVec2Num(a: Vec2Value, v: Vec2Value, w: number): Vec2;
/**
* Returns `a + (v x w)`
*/
static addCrossNumVec2(a: Vec2Value, v: number, w: Vec2Value): Vec2;
static add(v: Vec2Value, w: Vec2Value): Vec2;
/** @hidden @deprecated */
static wAdd(a: number, v: Vec2Value, b: number, w: Vec2Value): Vec2;
static combine(a: number, v: Vec2Value, b: number, w: Vec2Value): Vec2;
static sub(v: Vec2Value, w: Vec2Value): Vec2;
static mul(a: Vec2Value, b: number): Vec2;
static mul(a: number, b: Vec2Value): Vec2;
static mulVec2Num(a: Vec2Value, b: number): Vec2;
static mulNumVec2(a: number, b: Vec2Value): Vec2;
neg(): Vec2;
static neg(v: Vec2Value): Vec2;
static abs(v: Vec2Value): Vec2;
static mid(v: Vec2Value, w: Vec2Value): Vec2;
static upper(v: Vec2Value, w: Vec2Value): Vec2;
static lower(v: Vec2Value, w: Vec2Value): Vec2;
clamp(max: number): Vec2;
static clamp(v: Vec2Value, max: number): Vec2;
/** @hidden */
static clampVec2(v: Vec2Value, min?: Vec2Value, max?: Vec2Value): Vec2Value;
/** @hidden @deprecated */
static scaleFn(x: number, y: number): (v: Vec2Value) => Vec2;
/** @hidden @deprecated */
static translateFn(x: number, y: number): (v: Vec2Value) => Vec2;
}
export interface RotValue {
/** sin(angle) */
s: number;
/** cos(angle) */
c: number;
}
/** @hidden @deprecated Use new keyword. */
export function Rot(angle: number): Rot;
/** @hidden @deprecated Use new keyword. */
export function Rot(obj: RotValue): Rot;
/** @hidden @deprecated Use new keyword. */
export function Rot(): Rot;
/** Rotation */
export declare class Rot {
/** sin(angle) */
s: number;
/** cos(angle) */
c: number;
/** Initialize from an angle in radians. */
constructor(angle?: number | RotValue);
/** @hidden */
static neo(angle: number): Rot;
static clone(rot: RotValue): Rot;
static identity(): Rot;
static isValid(obj: any): boolean;
static assert(o: any): void;
/** Set to the identity rotation. */
setIdentity(): void;
set(angle: number | RotValue): void;
setRot(angle: RotValue): void;
/** Set using an angle in radians. */
setAngle(angle: number): void;
/** Get the angle in radians. */
getAngle(): number;
/** Get the x-axis. */
getXAxis(): Vec2;
/** Get the y-axis. */
getYAxis(): Vec2;
/** Multiply two rotations: q * r */
static mul(rot: RotValue, m: RotValue): Rot;
/** Rotate a vector */
static mul(rot: RotValue, m: Vec2Value): Vec2;
/** Multiply two rotations: q * r */
static mulRot(rot: RotValue, m: RotValue): Rot;
/** Rotate a vector */
static mulVec2(rot: RotValue, m: Vec2Value): Vec2;
static mulSub(rot: RotValue, v: Vec2Value, w: Vec2Value): Vec2;
/** Transpose multiply two rotations: qT * r */
static mulT(rot: RotValue, m: RotValue): Rot;
/** Inverse rotate a vector */
static mulT(rot: RotValue, m: Vec2Value): Vec2;
/** Transpose multiply two rotations: qT * r */
static mulTRot(rot: RotValue, m: RotValue): Rot;
/** Inverse rotate a vector */
static mulTVec2(rot: RotValue, m: Vec2Value): Vec2;
}
export type TransformValue = {
p: Vec2Value;
q: RotValue;
};
/** @hidden @deprecated Use new keyword. */
export function Transform(position?: Vec2Value, rotation?: number): Transform;
/**
* A transform contains translation and rotation. It is used to represent the
* position and orientation of rigid frames. Initialize using a position vector
* and a rotation.
*/
export declare class Transform {
/** position */
p: Vec2;
/** rotation */
q: Rot;
constructor(position?: Vec2Value, rotation?: number);
static clone(xf: Transform): Transform;
/** @hidden */
static neo(position: Vec2Value, rotation: Rot): Transform;
static identity(): Transform;
/** Set this to the identity transform */
setIdentity(): void;
/** Set position and angle */
set(position: Vec2Value, rotation: number): void;
/** Copy from another transform */
set(xf: TransformValue): void;
/** Set position and angle */
setNum(position: Vec2Value, rotation: number): void;
setTransform(xf: TransformValue): void;
static isValid(obj: any): boolean;
static assert(o: any): void;
static mul(a: TransformValue, b: Vec2Value): Vec2;
static mul(a: TransformValue, b: TransformValue): Transform;
static mulAll(a: Transform, b: Vec2Value[]): Vec2[];
static mulAll(a: Transform, b: Transform[]): Transform[];
/** @hidden @deprecated */
static mulFn(a: TransformValue): (b: Vec2Value) => Vec2;
static mulVec2(a: TransformValue, b: Vec2Value): Vec2;
static mulXf(a: TransformValue, b: TransformValue): Transform;
static mulT(a: TransformValue, b: Vec2Value): Vec2;
static mulT(a: TransformValue, b: TransformValue): Transform;
static mulTVec2(a: TransformValue, b: Vec2Value): Vec2;
static mulTXf(a: TransformValue, b: TransformValue): Transform;
}
/**
* Ray-cast input data. The ray extends from `p1` to `p1 + maxFraction * (p2 - p1)`.
*/
export interface RayCastInput {
p1: Vec2Value;
p2: Vec2Value;
maxFraction: number;
}
export type RayCastCallback = (subInput: RayCastInput, id: number) => number;
/**
* Ray-cast output data. The ray hits at `p1 + fraction * (p2 - p1)`,
* where `p1` and `p2` come from RayCastInput.
*/
export interface RayCastOutput {
normal: Vec2;
fraction: number;
}
/** Axis-aligned bounding box */
export interface AABBValue {
lowerBound: Vec2Value;
upperBound: Vec2Value;
}
/** @hidden @deprecated Use new keyword. */
export function AABB(lower?: Vec2Value, upper?: Vec2Value): AABB;
/** Axis-aligned bounding box */
export declare class AABB {
lowerBound: Vec2;
upperBound: Vec2;
constructor(lower?: Vec2Value, upper?: Vec2Value);
/**
* Verify that the bounds are sorted.
*/
isValid(): boolean;
static isValid(obj: any): boolean;
static assert(o: any): void;
/**
* Get the center of the AABB.
*/
getCenter(): Vec2;
/**
* Get the extents of the AABB (half-widths).
*/
getExtents(): Vec2;
/**
* Get the perimeter length.
*/
getPerimeter(): number;
/**
* Combine one or two AABB into this one.
*/
combine(a: AABBValue, b?: AABBValue): void;
combinePoints(a: Vec2Value, b: Vec2Value): void;
set(aabb: AABBValue): void;
contains(aabb: AABBValue): boolean;
extend(value: number): AABB;
static extend(out: AABBValue, value: number): AABBValue;
static testOverlap(a: AABBValue, b: AABBValue): boolean;
static areEqual(a: AABBValue, b: AABBValue): boolean;
static diff(a: AABBValue, b: AABBValue): number;
rayCast(output: RayCastOutput, input: RayCastInput): boolean;
/** @hidden */
toString(): string;
static combinePoints(out: AABBValue, a: Vec2Value, b: Vec2Value): AABBValue;
static combinedPerimeter(a: AABBValue, b: AABBValue): number;
}
/**
* Input for Distance. You have to option to use the shape radii in the
* computation. Even
*/
export declare class DistanceInput {
readonly proxyA: DistanceProxy;
readonly proxyB: DistanceProxy;
readonly transformA: Transform;
readonly transformB: Transform;
useRadii: boolean;
recycle(): void;
}
/**
* Output for Distance.
*/
export declare class DistanceOutput {
/** closest point on shapeA */
pointA: Vec2Value;
/** closest point on shapeB */
pointB: Vec2Value;
distance: number;
/** iterations number of GJK iterations used */
iterations: number;
recycle(): void;
}
/**
* Used to warm start Distance. Set count to zero on first call.
*/
export declare class SimplexCache {
/** length or area */
metric: number;
/** vertices on shape A */
indexA: number[];
/** vertices on shape B */
indexB: number[];
count: number;
recycle(): void;
}
/**
* Compute the closest points between two shapes. Supports any combination of:
* CircleShape, PolygonShape, EdgeShape. The simplex cache is input/output. On
* the first call set SimplexCache.count to zero.
*/
export declare const Distance: {
(output: DistanceOutput, cache: SimplexCache, input: DistanceInput): void;
testOverlap: (shapeA: Shape, indexA: number, shapeB: Shape, indexB: number, xfA: TransformValue, xfB: TransformValue) => boolean;
Input: typeof DistanceInput;
Output: typeof DistanceOutput;
Proxy: typeof DistanceProxy;
Cache: typeof SimplexCache;
};
/**
* A distance proxy is used by the GJK algorithm. It encapsulates any shape.
*/
export declare class DistanceProxy {
recycle(): void;
/**
* Get the vertex count.
*/
getVertexCount(): number;
/**
* Get a vertex by index. Used by Distance.
*/
getVertex(index: number): Vec2Value;
/**
* Get the supporting vertex index in the given direction.
*/
getSupport(d: Vec2Value): number;
/**
* Get the supporting vertex in the given direction.
*/
getSupportVertex(d: Vec2Value): Vec2Value;
/**
* Initialize the proxy using the given shape. The shape must remain in scope
* while the proxy is in use.
*/
set(shape: Shape, index: number): void;
/**
* Initialize the proxy using a vertex cloud and radius. The vertices
* must remain in scope while the proxy is in use.
*/
setVertices(vertices: Vec2Value[], count: number, radius: number): void;
}
/**
* Determine if two generic shapes overlap.
*/
export declare const testOverlap: (shapeA: Shape, indexA: number, shapeB: Shape, indexB: number, xfA: TransformValue, xfB: TransformValue) => boolean;
/**
* Input parameters for ShapeCast
*/
export declare class ShapeCastInput {
readonly proxyA: DistanceProxy;
readonly proxyB: DistanceProxy;
readonly transformA: Transform;
readonly transformB: Transform;
readonly translationB: Vec2;
recycle(): void;
}
/**
* Output results for b2ShapeCast
*/
export declare class ShapeCastOutput {
point: Vec2;
normal: Vec2;
lambda: number;
iterations: number;
}
/**
* Perform a linear shape cast of shape B moving and shape A fixed. Determines
* the hit point, normal, and translation fraction.
*
* @returns true if hit, false if there is no hit or an initial overlap
*/
export declare const ShapeCast: (output: ShapeCastOutput, input: ShapeCastInput) => boolean;
/**
* A joint edge is used to connect bodies and joints together in a joint graph
* where each body is a node and each joint is an edge. A joint edge belongs to
* a doubly linked list maintained in each attached body. Each joint has two
* joint nodes, one for each attached body.
*/
export declare class JointEdge {
/**
* provides quick access to the other body attached.
*/
other: Body$1 | null;
/**
* the joint
*/
joint: Joint | null;
/**
* prev the previous joint edge in the body's joint list
*/
prev: JointEdge | null;
/**
* the next joint edge in the body's joint list
*/
next: JointEdge | null;
}
/**
* Joint definitions are used to construct joints.
*/
export interface JointOpt {
/**
* Use this to attach application specific data to your joints.
*/
userData?: any;
/**
* Set this flag to true if the attached bodies
* should collide.
*/
collideConnected?: boolean;
/** Styling for dev-tools. */
style?: Style;
}
/**
* Joint definitions are used to construct joints.
*/
export interface JointDef extends JointOpt {
/**
* The first attached body.
*/
bodyA: Body$1;
/**
* The second attached body.
*/
bodyB: Body$1;
}
/**
* The base joint class. Joints are used to constraint two bodies together in
* various fashions. Some joints also feature limits and motors.
*/
export declare abstract class Joint {
/** Styling for dev-tools. */
style: Style;
/** @hidden @experimental Similar to userData, but used by dev-tools or runtime environment. */
appData: Record<string, any>;
constructor(def: JointDef);
constructor(def: JointOpt, bodyA: Body$1, bodyB: Body$1);
/**
* Short-cut function to determine if either body is inactive.
*/
isActive(): boolean;
/**
* Get the type of the concrete joint.
*/
getType(): string;
/**
* Get the first body attached to this joint.
*/
getBodyA(): Body$1;
/**
* Get the second body attached to this joint.
*/
getBodyB(): Body$1;
/**
* Get the next joint the world joint list.
*/
getNext(): Joint;
getUserData(): unknown;
setUserData(data: unknown): void;
/**
* Get collide connected. Note: modifying the collide connect flag won't work
* correctly because the flag is only checked when fixture AABBs begin to
* overlap.
*/
getCollideConnected(): boolean;
/**
* Get the anchor point on bodyA in world coordinates.
*/
abstract getAnchorA(): Vec2;
/**
* Get the anchor point on bodyB in world coordinates.
*/
abstract getAnchorB(): Vec2;
/**
* Get the reaction force on bodyB at the joint anchor in Newtons.
*/
abstract getReactionForce(inv_dt: number): Vec2;
/**
* Get the reaction torque on bodyB in N*m.
*/
abstract getReactionTorque(inv_dt: number): number;
/**
* Shift the origin for any points stored in world coordinates.
*/
shiftOrigin(newOrigin: Vec2Value): void;
abstract initVelocityConstraints(step: TimeStep): void;
abstract solveVelocityConstraints(step: TimeStep): void;
/**
* This returns true if the position errors are within tolerance.
*/
abstract solvePositionConstraints(step: TimeStep): boolean;
/**
* @hidden @experimental
* Update joint with new props.
*/
abstract _reset(def: Partial<JointDef>): void;
}
export interface Style {
stroke?: string;
fill?: string;
lineWidth?: number;
}
export type KEY = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" | "J" | "K" | "L" | "M" | "N" | "O" | "P" | "Q" | "R" | "S" | "T" | "U" | "V" | "W" | "X" | "Y" | "Z" | "right" | "left" | "up" | "down" | "fire";
export type ActiveKeys = {
[key in KEY]?: boolean;
};
export type TestbedMountOptions = {
[key: string]: any;
};
export declare abstract class Testbed {
/**
* Mounts testbed. Call start with a world to start simulation and rendering.
*/
static mount(options?: TestbedMountOptions): Testbed;
/**
* Mounts testbed if needed, then starts simulation and rendering.
*
* If you need to customize testbed before starting, first run `const testbed = Testbed.mount()` and then `testbed.start()`.
*/
static start(world: World): Testbed;
/** World viewbox width. */
width: number;
/** World viewbox height. */
height: number;
/** World viewbox center vertical offset. */
x: number;
/** World viewbox center horizontal offset. */
y: number;
/** @hidden */
scaleY: number;
/** World simulation step frequency */
hz: number;
/** World simulation speed, default is 1 */
speed: number;
background: string;
mouseForce?: number;
activeKeys: ActiveKeys;
/** callback, to be implemented by user */
step: (dt: number, t: number) => void;
/** callback, to be implemented by user */
keydown: (keyCode: number, label: string) => void;
/** callback, to be implemented by user */
keyup: (keyCode: number, label: string) => void;
abstract status(name: string, value: any): void;
abstract status(value: object | string): void;
abstract info(text: string): void;
color(r: number, g: number, b: number): string;
abstract drawPoint(p: {
x: number;
y: number;
}, r: any, color: string): void;
abstract drawCircle(p: {
x: number;
y: number;
}, r: number, color: string): void;
abstract drawEdge(a: {
x: number;
y: number;
}, b: {
x: number;
y: number;
}, color: string): void;
abstract drawSegment(a: {
x: number;
y: number;
}, b: {
x: number;
y: number;
}, color: string): void;
abstract drawPolygon(points: Array<{
x: number;
y: number;
}>, color: string): void;
abstract drawAABB(aabb: AABBValue, color: string): void;
abstract start(world: World): void;
abstract findOne(query: string): (Body$1 | Joint | Fixture | null);
abstract findAll(query: string): (Body$1 | Joint | Fixture)[];
}
export type TestbedFactoryOptions = string | TestbedMountOptions;
/** @deprecated */
export type TestbedCallback = (testbed: Testbed) => (World | undefined);
/** @deprecated */
export declare function testbed(callback: TestbedCallback): void;
/** @deprecated */
export declare function testbed(options: TestbedFactoryOptions, callback: TestbedCallback): void;
/**
* A shape is used for collision detection. You can create a shape however you
* like. Shapes used for simulation in World are created automatically when a
* Fixture is created. Shapes may encapsulate one or more child shapes.
*/
export declare abstract class Shape {
/** @hidden */ m_type: ShapeType;
/**
* @hidden
* Radius of a shape. For polygonal shapes this must be b2_polygonRadius.
* There is no support for making rounded polygons.
*/
m_radius: number;
/** Styling for dev-tools. */
style: Style;
/** @hidden @experimental Similar to userData, but used by dev-tools or runtime environment. */
appData: Record<string, any>;
/** @hidden */
abstract _reset(): void;
static isValid(obj: any): boolean;
abstract getRadius(): number;
/**
* Get the type of this shape. You can use this to down cast to the concrete
* shape.
*
* @return the shape type.
*/
abstract getType(): ShapeType;
/**
* Get the number of child primitives.
*/
abstract getChildCount(): number;
/**
* Test a point for containment in this shape. This only works for convex
* shapes.
*
* @param xf The shape world transform.
* @param p A point in world coordinates.
*/
abstract testPoint(xf: TransformValue, p: Vec2Value): boolean;
/**
* Cast a ray against a child shape.
*
* @param output The ray-cast results.
* @param input The ray-cast input parameters.
* @param xf The transform to be applied to the shape.
* @param childIndex The child shape index
*/
abstract rayCast(output: RayCastOutput, input: RayCastInput, xf: Transform, childIndex: number): boolean;
/**
* Given a transform, compute the associated axis aligned bounding box for a
* child shape.
*
* @param aabb Returns the axis aligned box.
* @param xf The world transform of the shape.
* @param childIndex The child shape
*/
abstract computeAABB(aabb: AABBValue, xf: TransformValue, childIndex: number): void;
/**
* Compute the mass properties of this shape using its dimensions and density.
* The inertia tensor is computed about the local origin.
*
* @param massData Returns the mass data for this shape.
* @param density The density in kilograms per meter squared.
*/
abstract computeMass(massData: MassData, density?: number): void;
abstract computeDistanceProxy(proxy: DistanceProxy, childIndex: number): void;
}
export type ShapeType = "circle" | "edge" | "polygon" | "chain";
export type DynamicTreeQueryCallback = (nodeId: number) => boolean;
/**
* A node in the dynamic tree. The client does not interact with this directly.
*/
export declare class TreeNode<T> {
id: number;
/** Enlarged AABB */
aabb: AABB;
userData: T;
parent: TreeNode<T>;
child1: TreeNode<T>;
child2: TreeNode<T>;
/** 0: leaf, -1: free node */
height: number;
constructor(id?: number);
isLeaf(): boolean;
}
/**
* A dynamic AABB tree broad-phase, inspired by Nathanael Presson's btDbvt. A
* dynamic tree arranges data in a binary tree to accelerate queries such as
* volume queries and ray casts. Leafs are proxies with an AABB. In the tree we
* expand the proxy AABB by `aabbExtension` so that the proxy AABB is bigger
* than the client object. This allows the client object to move by small
* amounts without triggering a tree update.
*
* Nodes are pooled and relocatable, so we use node indices rather than
* pointers.
*/
export declare class DynamicTree<T> {
m_root: TreeNode<T>;
m_lastProxyId: number;
m_nodes: {
[id: number]: TreeNode<T>;
};
constructor();
/**
* Get proxy user data.
*
* @return the proxy user data or 0 if the id is invalid.
*/
getUserData(id: number): T;
/**
* Get the fat AABB for a node id.
*
* @return the proxy user data or 0 if the id is invalid.
*/
getFatAABB(id: number): AABB;
allocateNode(): TreeNode<T>;
freeNode(node: TreeNode<T>): void;
/**
* Create a proxy in the tree as a leaf node. We return the index of the node
* instead of a pointer so that we can grow the node pool.
*
* Create a proxy. Provide a tight fitting AABB and a userData pointer.
*/
createProxy(aabb: AABBValue, userData: T): number;
/**
* Destroy a proxy. This asserts if the id is invalid.
*/
destroyProxy(id: number): void;
/**
* Move a proxy with a swepted AABB. If the proxy has moved outside of its
* fattened AABB, then the proxy is removed from the tree and re-inserted.
* Otherwise the function returns immediately.
*
* @param d Displacement
*
* @return true if the proxy was re-inserted.
*/
moveProxy(id: number, aabb: AABBValue, d: Vec2Value): boolean;
insertLeaf(leaf: TreeNode<T>): void;
removeLeaf(leaf: TreeNode<T>): void;
/**
* Perform a left or right rotation if node A is imbalanced. Returns the new
* root index.
*/
balance(iA: TreeNode<T>): TreeNode<T>;
/**
* Compute the height of the binary tree in O(N) time. Should not be called
* often.
*/
getHeight(): number;
/**
* Get the ratio of the sum of the node areas to the root area.
*/
getAreaRatio(): number;
/**
* Compute the height of a sub-tree.
*/
computeHeight(id?: number): number;
validateStructure(node: TreeNode<T>): void;
validateMetrics(node: TreeNode<T>): void;
/**
* Validate this tree. For testing.
*/
validate(): void;
/**
* Get the maximum balance of an node in the tree. The balance is the difference
* in height of the two children of a node.
*/
getMaxBalance(): number;
/**
* Build an optimal tree. Very expensive. For testing.
*/
rebuildBottomUp(): void;
/**
* Shift the world origin. Useful for large worlds. The shift formula is:
* position -= newOrigin
*
* @param newOrigin The new origin with respect to the old origin
*/
shiftOrigin(newOrigin: Vec2Value): void;
/**
* Query an AABB for overlapping proxies. The callback class is called for each
* proxy that overlaps the supplied AABB.
*/
query(aabb: AABBValue, queryCallback: DynamicTreeQueryCallback): void;
/**
* Ray-cast against the proxies in the tree. This relies on the callback to
* perform a exact ray-cast in the case were the proxy contains a shape. The
* callback also performs the any collision filtering. This has performance
* roughly equal to k * log(n), where k is the number of collisions and n is the
* number of proxies in the tree.
*
* @param input The ray-cast input data. The ray extends from `p1` to `p1 + maxFraction * (p2 - p1)`.
* @param rayCastCallback A function that is called for each proxy that is hit by the ray. If the return value is a positive number it will update the maxFraction of the ray cast input, and if it is zero it will terminate they ray cast.
*/
rayCast(input: RayCastInput, rayCastCallback: RayCastCallback): void;
private inputPool;
private stackPool;
private iteratorPool;
}
/**
* The broad-phase wraps and extends a dynamic-tree to keep track of moved
* objects and query them on update.
*/
export declare class BroadPhase {
m_tree: DynamicTree<FixtureProxy>;
m_moveBuffer: number[];
m_callback: (userDataA: any, userDataB: any) => void;
m_queryProxyId: number;
/**
* Get user data from a proxy. Returns null if the id is invalid.
*/
getUserData(proxyId: number): FixtureProxy;
/**
* Test overlap of fat AABBs.
*/
testOverlap(proxyIdA: number, proxyIdB: number): boolean;
/**
* Get the fat AABB for a proxy.
*/
getFatAABB(proxyId: number): AABB;
/**
* Get the number of proxies.
*/
getProxyCount(): number;
/**
* Get the height of the embedded tree.
*/
getTreeHeight(): number;
/**
* Get the balance (integer) of the embedded tree.
*/
getTreeBalance(): number;
/**
* Get the quality metric of the embedded tree.
*/
getTreeQuality(): number;
/**
* Query an AABB for overlapping proxies. The callback class is called for each
* proxy that overlaps the supplied AABB.
*/
query: (aabb: AABBValue, queryCallback: DynamicTreeQueryCallback) => void;
/**
* Ray-cast against the proxies in the tree. This relies on the callback to
* perform a exact ray-cast in the case were the proxy contains a shape. The
* callback also performs the any collision filtering. This has performance
* roughly equal to k * log(n), where k is the number of collisions and n is the
* number of proxies in the tree.
*
* @param input The ray-cast input data. The ray extends from `p1` to `p1 + maxFraction * (p2 - p1)`.
* @param rayCastCallback A function that is called for each proxy that is hit by the ray. If the return value is a positive number it will update the maxFraction of the ray cast input, and if it is zero it will terminate they ray cast.
*/
rayCast(input: RayCastInput, rayCastCallback: RayCastCallback): void;
/**
* Shift the world origin. Useful for large worlds. The shift formula is:
* position -= newOrigin
*
* @param newOrigin The new origin with respect to the old origin
*/
shiftOrigin(newOrigin: Vec2Value): void;
/**
* Create a proxy with an initial AABB. Pairs are not reported until UpdatePairs
* is called.
*/
createProxy(aabb: AABBValue, userData: FixtureProxy): number;
/**
* Destroy a proxy. It is up to the client to remove any pairs.
*/
destroyProxy(proxyId: number): void;
/**
* Call moveProxy as many times as you like, then when you are done call
* UpdatePairs to finalized the proxy pairs (for your time step).
*/
moveProxy(proxyId: number, aabb: AABB, displacement: Vec2Value): void;
/**
* Call to trigger a re-processing of it's pairs on the next call to
* UpdatePairs.
*/
touchProxy(proxyId: number): void;
bufferMove(proxyId: number): void;
unbufferMove(proxyId: number): void;
/**
* Update the pairs. This results in pair callbacks. This can only add pairs.
*/
updatePairs(addPairCallback: (userDataA: FixtureProxy, userDataB: FixtureProxy) => void): void;
queryCallback: (proxyId: number) => boolean;
}
/**
* A fixture definition is used to create a fixture. This class defines an
* abstract fixture definition. You can reuse fixture definitions safely.
*/
export interface FixtureOpt {
userData?: unknown;
/**
* The friction coefficient, usually in the range [0,1]
*/
friction?: number;
/**
* The restitution (elasticity) usually in the range [0,1]
*/
restitution?: number;
/**
* The density, usually in kg/m^2
*/
density?: number;
/**
* A sensor shape collects contact information but never generates a collision response.
*/
isSensor?: boolean;
/**
* Zero, positive or negative collision group.
* Fixtures with same positive groupIndex always collide and fixtures with same negative groupIndex never collide.
*/
filterGroupIndex?: number;
/**
* Collision category bit or bits that this fixture belongs to.
* If groupIndex is zero or not matching, then at least one bit in this fixture categoryBits should match other fixture maskBits and vice versa.
*/
filterCategoryBits?: number;
/**
* Collision category bit or bits that this fixture accept for collision.
*/
filterMaskBits?: number;
/** Styling for dev-tools. */
style?: Style;
}
export interface FixtureDef extends FixtureOpt {
shape: Shape;
}
/**
* This proxy is used internally to connect shape children to the broad-phase.
*/
export declare class FixtureProxy {
aabb: AABB;
fixture: Fixture;
childIndex: number;
proxyId: number;
constructor(fixture: Fixture, childIndex: number);
}
/**
* A fixture is used to attach a shape to a body for collision detection. A
* fixture inherits its transform from its parent. Fixtures hold additional
* non-geometric data such as friction, collision filters, etc.
*
* To create a new Fixture use {@link Body.createFixture}.
*/
export declare class Fixture {
/** Styling for dev-tools. */
style: Style;
/** @hidden @experimental Similar to userData, but used by dev-tools or runtime environment. */
appData: Record<string, any>;
constructor(body: Body$1, def: FixtureDef);
constructor(body: Body$1, shape: Shape, def?: FixtureOpt);
constructor(body: Body$1, shape: Shape, density?: number);
/** @hidden Re-setup fixture. */
_reset(): void;
/**
* Get the type of the child shape. You can use this to down cast to the
* concrete shape.
*/
getType(): ShapeType;
/**
* Get the child shape. You can modify the child shape, however you should not
* change the number of vertices because this will crash some collision caching
* mechanisms. Manipulating the shape may lead to non-physical behavior.
*/
getShape(): Shape;
/**
* A sensor shape collects contact information but never generates a collision
* response.
*/
isSensor(): boolean;
/**
* Set if this fixture is a sensor.
*/
setSensor(sensor: boolean): void;
/**
* Get the user data that was assigned in the fixture definition. Use this to
* store your application specific data.
*/
getUserData(): unknown;
/**
* Set the user data. Use this to store your application specific data.
*/
setUserData(data: unknown): void;
/**
* Get the parent body of this fixture. This is null if the fixture is not
* attached.
*/
getBody(): Body$1;
/**
* Get the next fixture in the parent body's fixture list.
*/
getNext(): Fixture | null;
/**
* Get the density of this fixture.
*/
getDensity(): number;
/**
* Set the density of this fixture. This will _not_ automatically adjust the
* mass of the body. You must call Body.resetMassData to update the body's mass.
*/
setDensity(density: number): void;
/**
* Get the coefficient of friction, usually in the range [0,1].
*/
getFriction(): number;
/**
* Set the coefficient of friction. This will not change the friction of
* existing contacts.
*/
setFriction(friction: number): void;
/**
* Get the coefficient of restitution.
*/
getRestitution(): number;
/**
* Set the coefficient of restitution. This will not change the restitution of
* existing contacts.
*/
setRestitution(restitution: number): void;
/**
* Test a point in world coordinates for containment in this fixture.
*/
testPoint(p: Vec2Value): boolean;
/**
* Cast a ray against this shape.
*/
rayCast(output: RayCastOutput, input: RayCastInput, childIndex: number): boolean;
/**
* Get the mass data for this fixture. The mass data is based on the density and
* the shape. The rotational inertia is about the shape's origin. This operation
* may be expensive.
*/
getMassData(massData: MassData): void;
/**
* Get the fixture's AABB. This AABB may be enlarge and/or stale. If you need a
* more accurate AABB, compute it using the shape and the body transform.
*/
getAABB(childIndex: number): AABB;
/**
* These support body activation/deactivation.
*/
createProxies(broadPhase: BroadPhase, xf: TransformValue): void;
destroyProxies(broadPhase: BroadPhase): void;
/**
* Updates this fixture proxy in broad-phase (with combined AABB of current and
* next transformation).
*/
synchronize(broadPhase: BroadPhase, xf1: TransformValue, xf2: TransformValue): void;
/**
* Set the contact filtering data. This will not update contacts until the next
* time step when either parent body is active and awake. This automatically
* calls refilter.
*/
setFilterData(filter: {
groupIndex: number;
categoryBits: number;
maskBits: number;
}): void;
getFilterGroupIndex(): number;
setFilterGroupIndex(groupIndex: number): void;
getFilterCategoryBits(): number;
setFilterCategoryBits(categoryBits: number): void;
getFilterMaskBits(): number;
setFilterMaskBits(maskBits: number): void;
/**
* Call this if you want to establish collision that was previously disabled by
* ContactFilter.
*/
refilter(): void;
/**
* Implement this method to provide collision filtering, if you want finer
* control over contact creation.
*
* Return true if contact calculations should be performed between these two
* fixtures.
*
* Warning: for performance reasons this is only called when the AABBs begin to
* overlap.
*/
shouldCollide(that: Fixture): boolean;
}
export declare enum ManifoldType {
e_unset = -1,
e_circles = 0,
e_faceA = 1,
e_faceB = 2
}
export declare enum ContactFeatureType {
e_unset = -1,
e_vertex = 0,
e_face = 1
}
/**
* This is used for determining the state of contact points.
*/
export declare enum PointState {
/** Point does not exist */
nullState = 0,
/** Point was added in the update */
addState = 1,
/** Point persisted across the update */
persistState = 2,
/** Point was removed in the update */
removeState = 3
}
/**
* Used for computing contact manifolds.
*/
export declare class ClipVertex {
v: Vec2Value;
id: ContactID;
set(o: ClipVertex): void;
recycle(): void;
}
/**
* A manifold for two touching convex shapes. Manifolds are created in `evaluate`
* method of Contact subclasses.
*
* Supported manifold types are e_faceA or e_faceB for clip point versus plane
* with radius and e_circles point versus point with radius.
*
* We store contacts in this way so that position correction can account for
* movement, which is critical for continuous physics. All contact scenarios
* must be expressed in one of these types. This structure is stored across time
* steps, so we keep it small.
*/
export declare class Manifold {
type: ManifoldType;
/**
* Usage depends on manifold type:
* - circles: not used
* - faceA: the normal on polygonA
* - faceB: the normal on polygonB
*/
localNormal: Vec2Value;
/**
* Usage depends on manifold type:
* - circles: the local center of circleA
* - faceA: the center of faceA
* - faceB: the center of faceB
*/
localPoint: Vec2Value;
/** The points of contact */
points: ManifoldPoint[];
/** The number of manifold points */
pointCount: number;
set(that: Manifold): void;
recycle(): void;
/**
* Evaluate the manifold with supplied transforms. This assumes modest motion
* from the original state. This does not change the point count, impulses, etc.
* The radii must come from the shapes that generated the manifold.
*/
getWorldManifold(wm: WorldManifold | null, xfA: TransformValue, radiusA: number, xfB: TransformValue, radiusB: number): WorldManifold;
static clipSegmentToLine: typeof clipSegmentToLine;
static ClipVertex: typeof ClipVertex;
static getPointStates: typeof getPointStates;
static PointState: typeof PointState;
}
/**
* A manifold point is a contact point belonging to a contact manifold. It holds
* details related to the geometry and dynamics of the contact points.
*
* This structure is stored across time steps, so we keep it small.
*
* Note: impulses are used for internal caching and may not provide reliable
* contact forces, especially for high speed collisions.
*/
export declare class ManifoldPoint {
/**
* Usage depends on manifold type:
* - circles: the local center of circleB
* - faceA: the local center of circleB or the clip point of polygonB
* - faceB: the clip point of polygonA
*/
localPoint: Vec2Value;
/**
* The non-penetration impulse
*/
normalImpulse: number;
/**
* The friction impulse
*/
tangentImpulse: number;
/**
* Uniquely identifies a contact point between two shapes to facilitate warm starting
*/
readonly id: ContactID;
set(that: ManifoldPoint): void;
recycle(): void;
}
/**
* Contact ids to facilitate warm starting.
*
* ContactFeature: The features that intersect to form the contact point.
*/
export declare class ContactID {
/**
* Used to quickly compare contact ids.
*/
key: number;
/** ContactFeature index on shapeA */
indexA: number;
/** ContactFeature index on shapeB */
indexB: number;
/** ContactFeature type on shapeA */
typeA: ContactFeatureType;
/** ContactFeature type on shapeB */
typeB: ContactFeatureType;
setFeatures(indexA: number, typeA: ContactFeatureType, indexB: number, typeB: ContactFeatureType): void;
set(that: ContactID): void;
swapFeatures(): void;
recycle(): void;
}
/**
* This is used to compute the current state of a contact manifold.
*/
export declare class WorldManifold {
/** World vector pointing from A to B */
normal: Vec2Value;
/** World contact point (point of intersection) */
points: Vec2Value[];
/** A negative value indicates overlap, in meters */
separations: number[];
/** The number of manifold points */
pointCount: number;
recycle(): void;
}
/**
* Compute the point states given two manifolds. The states pertain to the
* transition from manifold1 to manifold2. So state1 is either persist or remove
* while state2 is either add or persist.
*/
export declare function getPointStates(state1: PointState[], state2: PointState[], manifold1: Manifold, manifold2: Manifold): void;
/**
* Clipping for contact manifolds. Sutherland-Hodgman clipping.
*/
export declare function clipSegmentToLine(vOut: ClipVertex[], vIn: ClipVertex[], normal: Vec2Value, offset: number, vertexIndexA: number): number;
/**
* A contact edge is used to connect bodies and contacts together in a contact
* graph where each body is a node and each contact is an edge. A contact edge
* belongs to a doubly linked list maintained in each attached body. Each
* contact has two contact nodes, one for each attached body.
*/
export declare class ContactEdge {
contact: Contact;
prev: ContactEdge | null;
next: ContactEdge | null;
other: Body$1 | null;
constructor(contact: Contact);
}
export type EvaluateFunction = (manifold: Manifold, xfA: TransformValue, fixtureA: Fixture, indexA: number, xfB: TransformValue, fixtureB: Fixture, indexB: number) => void;
/**
* Friction mixing law. The idea is to allow either fixture to drive the
* friction to zero. For example, anything slides on ice.
*/
export declare function mixFriction(friction1: number, friction2: number): number;
/**
* Restitution mixing law. The idea is allow for anything to bounce off an
* inelastic surface. For example, a superball bounces on anything.
*/
export declare function mixRestitution(restitution1: number, restitution2: number): number;
export declare class VelocityConstraintPoint {
rA: Vec2Value;
rB: Vec2Value;
normalImpulse: number;
tangentImpulse: number;
normalMass: number;
tangentMass: number;
velocityBias: number;
recycle(): void;
}
/**
* The class manages contact between two shapes. A contact exists for each
* overlapping AABB in the broad-phase (except if filtered). Therefore a contact
* object may exist that has no contact points.
*/
export declare class Contact {
initConstraint(step: TimeStep): void;
/**
* Get the contact manifold. Do not modify the manifold unless you understand
* the internals of the library.
*/
getManifold(): Manifold;
/**
* Get the world manifold.
*/
getWorldManifold(worldManifold: WorldManifold | null): WorldManifold | undefined;
/**
* Enable/disable this contact. This can be used inside the pre-solve contact
* listener. The contact is only disabled for the current time step (or sub-step
* in continuous collisions).
*/
setEnabled(flag: boolean): void;
/**
* Has this contact been disabled?
*/
isEnabled(): boolean;
/**
* Is this contact touching?
*/
isTouching(): boolean;
/**
* Get the next contact in the world's contact list.
*/
getNext(): Contact | null;
/**
* Get fixture A in this contact.
*/
getFixtureA(): Fixture;
/**
* Get fixture B in this contact.
*/
getFixtureB(): Fixture;
/**
* Get the child primitive index for fixture A.
*/
getChildIndexA(): number;
/**
* Get the child primitive index for fixture B.
*/
getChildIndexB(): number;
/**
* Flag this contact for filtering. Filtering will occur the next time step.
*/
flagForFiltering(): void;
/**
* Override the default friction mixture. You can call this in
* "pre-solve" callback. This value persists until set or reset.
*/
setFriction(friction: number): void;
/**
* Get the friction.
*/
getFriction(): number;
/**
* Reset the friction mixture to the default value.
*/
resetFriction(): void;
/**
* Override the default restitution mixture. You can call this in
* "pre-solve" callback. The value persists until you set or reset.
*/
setRestitution(restitution: number): void;
/**
* Get the restitution.
*/
getRestitution(): number;
/**
* Reset the restitution to the default value.
*/
resetRestitution(): void;
/**
* Set the desired tangent speed for a conveyor belt behavior. In meters per
* second.
*/
setTangentSpeed(speed: number): void;
/**
* Get the desired tangent speed. In meters per second.
*/
getTangentSpeed(): number;
/**
* Called by Update method, and implemented by subclasses.
*/
evaluate(manifold: Manifold, xfA: TransformValue, xfB: TransformValue): void;
/**
* Updates the contact manifold and touching status.
*
* Note: do not assume the fixture AABBs are overlapping or are valid.
*
* @param listener.beginContact
* @param listener.endContact
* @param listener.preSolve
*/
update(listener?: {
beginContact(contact: Contact): void;
endContact(contact: Contact): void;
preSolve(contact: Contact, oldManifold: Manifold): void;
}): void;
solvePositionConstraint(step: TimeStep): number;
solvePositionConstraintTOI(step: TimeStep, toiA: Body$1, toiB: Body$1): number;
private _solvePositionConstraint;
initVelocityConstraint(step: TimeStep): void;
warmStartConstraint(step: TimeStep): void;
storeConstraintImpulses(step: TimeStep): void;
solveVelocityConstraint(step: TimeStep): void;
}
/**
* A static body does not move under simulation and behaves as if it has infinite mass.
* Internally, zero is stored for the mass and the inverse mass.
* Static bodies can be moved manually by the user.
* A static body has zero velocity.
* Static bodies do not collide with other static or kinematic bodies.
*
* A kinematic body moves under simulation according to its velocity.
* Kinematic bodies do not respond to forces.
* They can be moved manually by the user, but normally a kinematic body is moved by setting its velocity.
* A kinematic body behaves as if it has infinite mass, however, zero is stored for the mass and the inverse mass.
* Kinematic bodies do not collide with other kinematic or static bodies.
*
* A dynamic body is fully simulated.
* They can be moved manually by the user, but normally they move according to forces.
* A dynamic body can collide with all body types.
* A dynamic body always has finite, non-zero mass.
* If you try to set the mass of a dynamic body to zero, it will automatically acquire a mass of one kilogram and it won't rotate.
*/
export type BodyType = "static" | "kinematic" | "dynamic";
export interface BodyDef {
/**
* Body types are static, kinematic, or dynamic. Note: if a dynamic
* body would have zero mass, the mass is set to one.
*/
type?: BodyType;
/**
* The world position of the body. Avoid creating bodies at the
* origin since this can lead to many overlapping shapes.
*/
position?: Vec2Value;
/**
* The world angle of the body in radians.
*/
angle?: number;
/**
* The linear velocity of the body's origin in world co-ordinates.
*/
linearVelocity?: Vec2Value;
angularVelocity?: number;
/**
* Linear damping is use to reduce the linear velocity. The
* damping parameter can be larger than 1.0 but the damping effect becomes
* sensitive to the time step when the damping parameter is large.
* Units are 1/time
*/
linearDamping?: number;
/**
* Angular damping is use to reduce the angular velocity.
* The damping parameter can be larger than 1.0 but the damping effect
* becomes sensitive to the time step when the damping parameter is large.
* Units are 1/time
*/
angularDamping?: number;
/**
* Should this body be prevented from rotating? Useful for characters.
*/
fixedRotation?: boolean;
/**
* Is this a fast moving body that should be prevented from
* tunneling through other moving bodies? Note that all bodies are
* prevented from tunneling through kinematic and static bodies. This
* setting is only considered on dynamic bodies. Warning: You should use
* this flag sparingly since it increases processing time.
*/
bullet?: boolean;
gravityScale?: number;
/**
* Set this flag to false if this body should never fall asleep. Note that this increases CPU usage.
*/
allowSleep?: boolean;
/**
* Is this body initially awake or sleeping?
*/
awake?: boolean;
/**
* Does this body start out active?
*/
active?: boolean;
userData?: any;
/** Styling for dev-tools. */
style?: Style;
}
/**
* MassData This holds the mass data computed for a shape.
*/
export interface MassData {
/** The mass of the shape, usually in kilograms. */
mass: number;
/** The position of the shape's centroid relative to the shape's origin. */
center: Vec2Value;
/** The rotational inertia of the shape about the local origin. */
I: number;
}
/**
* A rigid body composed of one or more fixtures.
*
* To create a new Body use {@link World.createBody}.
*/
declare class Body$1 {
/** @hidden */
static readonly STATIC: BodyType;
/** @hidden */
static readonly KINEMATIC: BodyType;
/** @hidden */
static readonly DYNAMIC: BodyType;
/** Styling for dev-tools. */
style: Style;
/** @hidden @experimental Similar to userData, but used by dev-tools or runtime environment. */
appData: Record<string, any>;
isWorldLocked(): boolean;
getWorld(): World;
getNext(): Body$1 | null;
setUserData(data: any): void;
getUserData(): unknown;
getFixtureList(): Fixture | null;
getJointList(): JointEdge | null;
/**
* Warning: this list changes during the time step and you may miss some
* collisions if you don't use ContactListener.
*/
getContactList(): ContactEdge | null;
isStatic(): boolean;
isDynamic(): boolean;
isKinematic(): boolean;
/**
* This will alter the mass and velocity.
*/
setStatic(): Body$1;
setDynamic(): Body$1;
setKinematic(): Body$1;
/**
* Get the type of the body.
*/
getType(): BodyType;
/**
* Set the type of the body to "static", "kinematic" or "dynamic".
* @param type The type of the body.
*
* Warning: This functio