/** * @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