/**
* @import Entity from "../../renderable/entity/entity.js";
* @import Container from "../../renderable/container.js";
* @import Renderable from "../../renderable/renderable.js";
* @import Sprite from "../../renderable/sprite.js";
* @import NineSliceSprite from "../../renderable/nineslicesprite.js";
* @import {Vector2d} from "../../math/vector2d.js";
* @import ResponseObject from "../response.js";
**/
/**
* a Generic Physic Body Object with some physic properties and behavior functionality, to add as a member of a Renderable.
* @category Physics
* @see Renderable.body
*/
export default class Body {
/**
* @param {Renderable|Container|Entity|Sprite|NineSliceSprite} ancestor - the parent object this body is attached to
* @param {Rect|Rect[]|Polygon|Polygon[]|Line|Line[]|Ellipse|Ellipse[]|Point|Point[]|Bounds|Bounds[]|object} [shapes] - a initial shape, list of shapes, or JSON object defining the body
* @param {Function} [onBodyUpdate] - callback for when the body is updated (e.g. add/remove shapes)
*/
constructor(ancestor: Renderable | Container | Entity | Sprite | NineSliceSprite, shapes?: Rect | Rect[] | Polygon | Polygon[] | Line | Line[] | Ellipse | Ellipse[] | Point | Point[] | Bounds | Bounds[] | object, onBodyUpdate?: Function);
/**
* a reference to the parent object that contains this body,
* or undefined if it has not been added to one.
* @public
* @type {Renderable|Container|Entity|Sprite|NineSliceSprite}
* @default undefined
*/
public ancestor: Renderable | Container | Entity | Sprite | NineSliceSprite;
/**
* The AABB bounds box representing this body
* @public
* @type {Bounds}
*/
public bounds: Bounds;
/**
* The collision shapes of the body. Always an array — every
* mutation path goes through `push` / `includes`. The
* non-array `Point` that used to be in this union was a
* mis-doc and broke downstream `shapes.length` reads in
* TypeScript.
* @ignore
* @type {(Polygon|Line|Ellipse|Point)[]}
*/
shapes: (Polygon | Line | Ellipse | Point)[];
/**
* The body collision mask, that defines what should collide with what.
* (by default will collide with all entities)
* @ignore
* @type {number}
* @default collision.types.ALL_OBJECT
* @see collision.types
*/
collisionMask: number;
/**
* define the collision type of the body for collision filtering
* @public
* @type {number}
* @default collision.types.ENEMY_OBJECT
* @see collision.types
* @example
* // set the body collision type
* body.collisionType = me.collision.types.PLAYER_OBJECT;
*/
public collisionType: number;
/**
* The current velocity of the body.
* See to apply a force if you need to modify a body velocity
* @see Body.force
* @public
* @type {Vector2d}
* @default <0,0>
*/
public vel: Vector2d;
/**
* body force to apply to this the body in the current step.
* (any positive or negative force will be cancelled after every world/body update cycle)
* @public
* @type {Vector2d}
* @default <0,0>
* @see Body.setMaxVelocity
* @example
* // define a default maximum acceleration, initial force and friction
* this.body.force.set(1, 0);
* this.body.friction.set(0.4, 0);
* this.body.setMaxVelocity(3, 15);
*
* // apply a positive or negative force when pressing left of right key
* update(dt) {
* if (me.input.isKeyPressed("left")) {
* this.body.force.x = -this.body.maxVel.x;
* } else if (me.input.isKeyPressed("right")) {
* this.body.force.x = this.body.maxVel.x;
* }
* }
*/
public force: Vector2d;
/**
* body friction
* @public
* @type {Vector2d}
* @default <0,0>
*/
public friction: Vector2d;
/**
* the body bounciness level when colliding with other solid bodies :
* a value of 0 will not bounce, a value of 1 will fully rebound.
* @public
* @type {number}
* @default 0
*/
public bounce: number;
/**
* the body mass
* @public
* @type {number}
* @default 1
*/
public mass: number;
/**
* Current rotation angle (radians). Visual-only under the built-in
* SAT solver — the collision shapes themselves are NOT rotated by
* angular integration; only `renderable.currentTransform` is.
* Defaults to `0` and is integrated each step from
* {@link Body#angularVelocity}. Set directly via
* {@link Body#setAngle} or as a side effect of integration.
* @public
* @type {number}
* @default 0
* @example
* // teleport the sprite to face down-right (45°):
* sprite.body.angle = Math.PI / 4;
*/
public angle: number;
/**
* Angular velocity in radians per frame. Default `0` — bodies that
* never touch the angular API pay no integration cost. See
* {@link Body#setAngularVelocity} and {@link Body#applyTorque}.
* @public
* @type {number}
* @default 0
* @example
* // continuously spin a pickup at ~3°/frame (~180°/sec at 60fps):
* pickup.body.angularVelocity = 0.05;
*/
public angularVelocity: number;
/**
* Per-step exponential decay applied to {@link Body#angularVelocity}
* — analog of `frictionAir` for rotation. `0` = no damping
* (bodies spin forever); `1` = full damping per step (rotation
* stops instantly). Typical values are small (`0.01` – `0.05`)
* so spin decays naturally over a few seconds. Negative values
* are ignored (treated as `0`); values `> 1` flip the sign each
* step (overdamped — usually a foot-gun).
* @public
* @type {number}
* @default 0
* @example
* // dynamite barrel spins on impact then slows to a stop:
* barrel.body.angularDrag = 0.02;
* barrel.body.applyTorque(120);
*/
public angularDrag: number;
/**
* Moment-of-inertia analog used when converting force-at-offset
* and torque into angular velocity: `Δω = τ / pseudoInertia`.
* Defaults to a geometry-derived approximation
* `(width² + height²) / 12` matching the moment of inertia of a
* unit-mass rectangle. Override directly to make a body harder or
* easier to spin. Auto-recomputed after every {@link Body#addShape}
* call — manual overrides must come AFTER the body is fully built.
* @public
* @type {number}
* @default `(width² + height²) / 12`
* @example
* // a heavy boss is hard to knock around:
* boss.body.addShape(new me.Rect(0, 0, 64, 64));
* boss.body.pseudoInertia *= 10;
*/
public pseudoInertia: number;
/**
* max velocity (to limit body velocity)
* @public
* @type {Vector2d}
* @default <490,490>
*/
public maxVel: Vector2d;
/**
* Either this body is a static body or not.
* A static body is completely fixed and can never change position or angle.
* @readonly
* @public
* @type {boolean}
* @default false
*/
public readonly isStatic: boolean;
/**
* Whether this body is a sensor. A sensor detects collisions and
* fires the `onCollision*` events on the renderable, but does not
* physically respond to the contact (the SAT solver skips the
* positional push-out). Useful for triggers, ground-snap assists,
* etc. — same role as Matter's `isSensor`.
* @public
* @type {boolean}
* @default false
*/
public isSensor: boolean;
/**
* The degree to which this body is affected by the world gravity
* @public
* @see {@link World.gravity}
* @type {number}
* @default 1.0
*/
public gravityScale: number;
/**
* If true this body won't be affected by the world gravity.
* @public
* @see {@link World.gravity}
* @type {boolean}
* @default false
* @deprecated since 19.5.0 — use `gravityScale = 0` (or
* `bodyDef.gravityScale = 0` at construction, or
* `body.setGravityScale(0)` at runtime) instead. `gravityScale`
* is part of the portable {@link PhysicsBody} surface and works
* on every adapter; `ignoreGravity` is a builtin-only field that
* the matter adapter silently ignores. The two-field check
* (`!ignoreGravity && gravityScale !== 0`) used by builtin is
* redundant — set `gravityScale = 0` and both branches agree.
*/
public ignoreGravity: boolean;
/**
* falling state of the body
* true if the object is falling
* false if the object is standing on something
* @readonly
* @public
* @type {boolean}
* @default false
*/
public readonly falling: boolean;
/**
* jumping state of the body
* equal true if the body is jumping
* @readonly
* @public
* @type {boolean}
* @default false
*/
public readonly jumping: boolean;
onBodyUpdate: Function | undefined;
/**
* set the body as a static body
* static body do not move automatically and do not check against collision with others
* @param {boolean} [isStatic=true]
*/
setStatic(isStatic?: boolean): void;
/**
* set this body's linear velocity. Portable across physics adapters —
* under the builtin adapter this mutates `body.vel`; under Matter it
* delegates to `Matter.Body.setVelocity`.
* @param {number} x - velocity along the X axis
* @param {number} y - velocity along the Y axis
*/
setVelocity(x: number, y: number): void;
/**
* read this body's linear velocity into an optional output vector.
* @param {Vector2d} [out] - vector to write into; a new Vector2d is
* allocated when omitted
* @returns {Vector2d}
*/
getVelocity(out?: Vector2d): Vector2d;
/**
* accumulate a force on this body for the current step. Repeated calls
* within a single update add together; the engine clears the
* accumulator at the end of each integration step. Force magnitude
* conventions differ between adapters — consult the active adapter's
* docs for tuning ranges (builtin: px/frame²; Matter: Newtonian
* `force/mass·dt²`, typically ~100× smaller than builtin).
* @param {number} x - force along the X axis
* @param {number} y - force along the Y axis
* @param {number} [pointX] - world X of the application point; when
* present (along with `pointY`) and different from the body centroid,
* the resulting lever arm generates a torque
* `τ = (r.x · F.y) − (r.y · F.x)` that bumps {@link Body#angularVelocity}
* by `τ / pseudoInertia`. Omit both `pointX` and `pointY` for the
* linear-only behaviour that's compatible with code written before
* the angular API was added.
* @param {number} [pointY] - world Y of the application point
* @example
* // pure linear thrust (2-arg form, unchanged behaviour):
* ship.body.applyForce(0, -0.05);
*
* // off-centre push on a crate: the contact point at the top of the
* // crate is above its centroid, so the same horizontal force now
* // both translates AND tips the crate forward.
* const topX = crate.pos.x + crate.width / 2;
* const topY = crate.pos.y;
* crate.body.applyForce(1.5, 0, topX, topY);
*
* // wind pushing on the top of a flag-pole: pole tilts, base stays put
* // (only meaningful here if the base is anchored / static).
* pole.body.applyForce(0.3, 0, pole.pos.x + pole.width / 2, pole.pos.y);
*/
applyForce(x: number, y: number, pointX?: number, pointY?: number): void;
/**
* Apply an instantaneous angular impulse: `Δω = τ / pseudoInertia`.
* The angular analog of {@link Body#applyImpulse} — bypasses the
* lever-arm computation in {@link Body#applyForce} for the
* "just spin this up directly" case (a power-up's intrinsic spin,
* an explicit thruster, a knockback spin effect on hit).
* @param {number} torque - angular impulse magnitude. Positive values
* produce clockwise rotation on screen (matching the Y-down canvas
* convention); negative values rotate counter-clockwise.
* @example
* // give a pickup a one-shot spin-up when collected:
* pickup.body.applyTorque(80);
*
* // explosion knockback that both pushes and spins:
* crate.body.applyImpulse(impulseX, impulseY);
* crate.body.applyTorque((Math.random() - 0.5) * 100);
*/
applyTorque(torque: number): void;
/**
* Set angular velocity directly. Bypasses inertia — the value is the
* actual rad/frame that integration will apply next step. Use this
* for "set and hold" rotation (a coin that always spins at the same
* rate); use {@link Body#applyTorque} for impulse-style spin-up.
* @param {number} omega - target angular velocity (rad / frame)
* @example
* // make a fan blade spin at a fixed rate:
* fan.body.setAngularVelocity(0.1); // ~6°/frame
*/
setAngularVelocity(omega: number): void;
/**
* Read current angular velocity (rad / frame).
* @returns {number}
* @example
* // freeze rotation if the body is spinning too fast:
* if (Math.abs(body.getAngularVelocity()) > 2) {
* body.setAngularVelocity(0);
* }
*/
getAngularVelocity(): number;
/**
* Set absolute rotation angle (radians). Updates the body's `angle`
* field and re-syncs the renderable's `currentTransform` immediately
* so the visual rotation reflects the new value without waiting for
* the next integration step.
* @param {number} rad - target angle in radians
* @example
* // turret aims at the player every frame:
* const dx = player.centerX - turret.centerX;
* const dy = player.centerY - turret.centerY;
* turret.body.setAngle(Math.atan2(dy, dx));
*/
setAngle(rad: number): void;
/**
* Read absolute rotation angle (radians).
* @returns {number}
*/
getAngle(): number;
/**
* Sync `this.angle` to the renderable's `currentTransform`. Pivot is
* the body's bounds center (matches the matter adapter's rotation
* pivot — see `MatterAdapter.syncFromPhysics`). Internal helper used
* by both the per-step integrator and {@link Body#setAngle}.
* @ignore
*/
_syncAngleTransform(): void;
/**
* apply an instantaneous impulse to this body — a single-step velocity
* change scaled by inverse mass (`dv = J / m`). Useful for one-shot
* events like a cue strike, projectile launch, or knockback, where
* mass should influence the resulting velocity change. Repeated calls
* within a single update accumulate. Static bodies (mass 0) ignore
* the call. Identical signature on the Matter adapter, where the
* adapter integrates the impulse the same way (matter has no native
* `applyImpulse`).
* @param {number} x - impulse along the X axis
* @param {number} y - impulse along the Y axis
*/
applyImpulse(x: number, y: number): void;
/**
* set this body's mass. Useful for variable-mass entities (projectiles
* loaded with ammo, weight pickups, characters carrying objects).
* Mass affects `applyImpulse` (via `dv = J / m`) and the proportional
* push-out response in dynamic-dynamic collisions. A mass of 0 makes
* the body inert to forces and impulses (without going static).
* @param {number} m - new mass, non-negative
*/
setMass(m: number): void;
/**
* set this body's restitution / bounce factor. `0` = no bounce (energy
* absorbed on contact); `1` = perfect elastic rebound; values in
* between dampen the rebound. Applied by `Body.respondToCollision` —
* see `BuiltinAdapter` docs for the cancellation math.
*
* Matches the `bodyDef.restitution` field name used at registration
* time; the body-side property has historically been called `bounce`,
* which is the canonical legacy name and is preserved.
* @param {number} r - restitution factor, typically in [0, 1]
*/
setBounce(r: number): void;
/**
* set this body's per-body gravity multiplier. `1` = world gravity
* (default), `0` = ignore world gravity (e.g. flying enemy, underwater
* float), `2` = 2× gravity (heavy-feel objects). Multiplied with the
* world's `gravity.y` each frame inside `applyGravity`.
* @param {number} scale - gravity scale factor
*/
setGravityScale(scale: number): void;
/**
* toggle this body between solid and sensor. Sensor bodies still emit
* collision events (`onCollisionStart`, `onCollisionActive`,
* `onCollisionEnd`) but the solver does not physically resolve the
* contact — same semantics as Matter's `isSensor`. Useful for one-way
* platforms, trigger zones, and ground-snap assists.
* @param {boolean} [isSensor=true]
*/
setSensor(isSensor?: boolean): void;
/**
* add a collision shape to this body
* (note: me.Rect objects will be converted to me.Polygon before being added)
* @param {Rect|Polygon|Line|Ellipse|Point|Point[]|Bounds|object} shape - a shape or JSON object
* @returns {number} the shape array length
* @example
* // add a rectangle shape
* this.body.addShape(new me.Rect(0, 0, image.width, image.height));
* // add a shape from a JSON object
* this.body.addShape(me.loader.getJSON("shapesdef").banana);
*/
addShape(shape: Rect | Polygon | Line | Ellipse | Point | Point[] | Bounds | object): number;
/**
* Recompute the default `pseudoInertia` from the current bounds.
* Uses the moment-of-inertia formula for a unit-mass rectangle —
* `(width² + height²) / 12` — which gives a value that scales
* sensibly with body size: a small body resists rotation less, a
* large body more. Clamped to a minimum of 1 to keep divisions
* well-defined even on degenerate 0-size bodies.
* @ignore
*/
_recomputePseudoInertia(): void;
/**
* set the body vertices to the given one
* @param {Vector2d[]} vertices - an array of me.Vector2d points defining a convex hull
* @param {number} [index=0] - the shape object for which to set the vertices
* @param {boolean} [clear=true] - either to reset the body definition before adding the new vertices
*/
setVertices(vertices: Vector2d[], index?: number, clear?: boolean): void;
/**
* add the given vertices to the body shape
* @param {Vector2d[]} vertices - an array of me.Vector2d points defining a convex hull
* @param {number} [index=0] - the shape object for which to set the vertices
*/
addVertices(vertices: Vector2d[], index?: number): void;
/**
* add collision mesh based on a JSON object
* (this will also apply any physic properties defined in the given JSON file)
* @param {object} json - a JSON object as exported from a Physics Editor tool
* @param {string} [id] - an optional shape identifier within the given the json object
* @see https://www.codeandweb.com/physicseditor
* @returns {number} how many shapes were added to the body
* @example
* // define the body based on the banana shape
* this.body.fromJSON(me.loader.getJSON("shapesdef").banana);
* // or ...
* this.body.fromJSON(me.loader.getJSON("shapesdef"), "banana");
*/
fromJSON(json: object, id?: string): number;
/**
* return the collision shape at the given index
* @param {number} [index=0] - the shape object at the specified index
* @returns {Polygon|Line|Ellipse} shape a shape object if defined
*/
getShape(index?: number): Polygon | Line | Ellipse;
/**
* returns the AABB bounding box for this body
* @returns {Bounds} bounding box Rectangle object
*/
getBounds(): Bounds;
/**
* remove the specified shape from the body shape list
* @param {Polygon|Line|Ellipse} shape - a shape object
* @returns {number} the shape array length
*/
removeShape(shape: Polygon | Line | Ellipse): number;
/**
* remove the shape at the given index from the body shape list
* @param {number} index - the shape object at the specified index
* @returns {number} the shape array length
*/
removeShapeAt(index: number): number;
/**
* By default all physic bodies are able to collide with all other bodies,
* but it's also possible to specify 'collision filters' to provide a finer
* control over which body can collide with each other.
* @see collision.types
* @param {number} [bitmask = collision.types.ALL_OBJECT] - the collision mask
* @example
* // filter collision detection with collision shapes, enemies and collectables
* body.setCollisionMask(me.collision.types.WORLD_SHAPE | me.collision.types.ENEMY_OBJECT | me.collision.types.COLLECTABLE_OBJECT);
* ...
* // disable collision detection with all other objects
* body.setCollisionMask(me.collision.types.NO_OBJECT);
*/
setCollisionMask(bitmask?: number): void;
/**
* define the collision type of the body for collision filtering
* @see collision.types
* @param {number} type - the collision type
* @example
* // set the body collision type
* body.collisionType = me.collision.types.PLAYER_OBJECT;
*/
setCollisionType(type: number): void;
/**
* the built-in function to solve the collision response
* @param {ResponseObject} response - the collision response object
* @see {@link ResponseObject}
*/
respondToCollision(response: ResponseObject): void;
/**
* The forEach() method executes a provided function once per body shape element.
* the callback function is invoked with three arguments:
* - The current element being processed in the array
* - The index of element in the array.
* - The array forEach() was called upon.
* @param {Function} callback - function to execute on each element
* @param {object} [thisArg] - value to use as this(i.e reference Object) when executing callback.
* @example
* // iterate through all shapes of the physic body
* mySprite.body.forEach((shape) => {
* shape.doSomething();
* });
* mySprite.body.forEach((shape, index) => { ... });
* mySprite.body.forEach((shape, index, array) => { ... });
* mySprite.body.forEach((shape, index, array) => { ... }, thisArg);
*/
forEach(callback: Function, thisArg?: object): void;
/**
* Returns true if the any of the shape composing the body contains the given point.
* @param {number|Vector2d} x - x coordinate or a vector point to check
* @param {number} [y] - y coordinate
* @returns {boolean} true if contains
* @example
* if (mySprite.body.contains(10, 10)) {
* // do something
* }
* // or
* if (mySprite.body.contains(myVector2d)) {
* // do something
* }
*/
contains(...args: any[]): boolean;
/**
* Rotate this body (counter-clockwise) by the specified angle (in radians).
* Unless specified the body will be rotated around its center point
* @param {number} angle - The angle to rotate (in radians)
* @param {Vector2d} [v=Body.getBounds().center] - an optional point to rotate around
* @returns {Body} Reference to this object for method chaining
*/
rotate(angle: number, v?: Vector2d): Body;
/**
* cap the body velocity (body.maxVel property) to the specified value
* @param {number} x - max velocity on x axis
* @param {number} y - max velocity on y axis
*/
setMaxVelocity(x: number, y: number): void;
/**
* set the body default friction
* @param {number} x - horizontal friction
* @param {number} y - vertical friction
*/
setFriction(x?: number, y?: number): void;
/**
* Updates the parent's position as well as computes the new body's velocity based
* on the values of force/friction. Velocity changes are proportional to the
* me.timer.tick value (which can be used to scale velocities). The approach to moving the
* parent renderable is to compute new values of the Body.vel property then add them to
* the parent.pos value thus changing the position by the amount of Body.vel each time the
* update call is made.
* Updates to Body.vel are bounded by maxVel (which defaults to viewport size if not set)
* At this time a call to Body.Update does not call the onBodyUpdate callback that is listed in the constructor arguments.
* @protected
* @param {number} dt - time since the last update in milliseconds.
* @returns {boolean} true if resulting velocity is different than 0
*/
protected update(): boolean;
/**
* Destroy function
* @ignore
*/
destroy(): void;
}
import type Renderable from "../../renderable/renderable.js";
import type Container from "../../renderable/container.js";
import type Entity from "../../renderable/entity/entity.js";
import type Sprite from "../../renderable/sprite.js";
import type NineSliceSprite from "../../renderable/nineslicesprite.js";
import { Bounds } from "../bounds.ts";
import { Polygon } from "../../geometries/polygon.ts";
import { Line } from "../../geometries/line.ts";
import { Ellipse } from "../../geometries/ellipse.ts";
import { Point } from "../../geometries/point.ts";
import { Vector2d } from "../../math/vector2d.ts";
import { Rect } from "../../geometries/rectangle.ts";
import type ResponseObject from "../response.js";
//# sourceMappingURL=body.d.ts.map