/** * The `Matter.Body` module contains methods for creating and manipulating body models. * A `Matter.Body` is a rigid body that can be simulated by a `Matter.Engine`. * Factories for commonly used body configurations (such as rectangles, circles and other polygons) can be found in the module `Matter.Bodies`. * * See the included usage [examples](https://github.com/liabru/matter-js/tree/master/examples). * @class Body */ var Body = {}; module.exports = Body; var Vertices = require('../geometry/Vertices'); var Vector = require('../geometry/Vector'); var Sleeping = require('../core/Sleeping'); var Render = require('../render/Render'); var Common = require('../core/Common'); var Bounds = require('../geometry/Bounds'); var Axes = require('../geometry/Axes'); (function() { Body._inertiaScale = 4; Body._nextCollidingGroupId = 1; Body._nextNonCollidingGroupId = -1; Body._nextCategory = 0x0001; /** * Creates a new rigid body model. The options parameter is an object that specifies any properties you wish to override the defaults. * All properties have default values, and many are pre-calculated automatically based on other properties. * Vertices must be specified in clockwise order. * See the properties section below for detailed information on what you can pass via the `options` object. * @method create * @param {} options * @return {body} body */ Body.create = function(options) { var defaults = { id: Common.nextId(), type: 'body', label: 'Body', parts: [], plugin: {}, angle: 0, vertices: Vertices.fromPath('L 0 0 L 40 0 L 40 40 L 0 40'), position: { x: 0, y: 0 }, force: { x: 0, y: 0 }, torque: 0, positionImpulse: { x: 0, y: 0 }, constraintImpulse: { x: 0, y: 0, angle: 0 }, totalContacts: 0, speed: 0, angularSpeed: 0, velocity: { x: 0, y: 0 }, angularVelocity: 0, isSensor: false, isStatic: false, isSleeping: false, motion: 0, sleepThreshold: 60, density: 0.001, restitution: 0, friction: 0.1, frictionStatic: 0.5, frictionAir: 0.01, collisionFilter: { category: 0x0001, mask: 0xFFFFFFFF, group: 0 }, slop: 0.05, timeScale: 1, render: { visible: true, opacity: 1, sprite: { xScale: 1, yScale: 1, xOffset: 0, yOffset: 0 }, lineWidth: 0 } }; var body = Common.extend(defaults, options); _initProperties(body, options); return body; }; /** * Returns the next unique group index for which bodies will collide. * If `isNonColliding` is `true`, returns the next unique group index for which bodies will _not_ collide. * See `body.collisionFilter` for more information. * @method nextGroup * @param {bool} [isNonColliding=false] * @return {Number} Unique group index */ Body.nextGroup = function(isNonColliding) { if (isNonColliding) return Body._nextNonCollidingGroupId--; return Body._nextCollidingGroupId++; }; /** * Returns the next unique category bitfield (starting after the initial default category `0x0001`). * There are 32 available. See `body.collisionFilter` for more information. * @method nextCategory * @return {Number} Unique category bitfield */ Body.nextCategory = function() { Body._nextCategory = Body._nextCategory << 1; return Body._nextCategory; }; /** * Initialises body properties. * @method _initProperties * @private * @param {body} body * @param {} [options] */ var _initProperties = function(body, options) { options = options || {}; // init required properties (order is important) Body.set(body, { bounds: body.bounds || Bounds.create(body.vertices), positionPrev: body.positionPrev || Vector.clone(body.position), anglePrev: body.anglePrev || body.angle, vertices: body.vertices, parts: body.parts || [body], isStatic: body.isStatic, isSleeping: body.isSleeping, parent: body.parent || body }); Vertices.rotate(body.vertices, body.angle, body.position); Axes.rotate(body.axes, body.angle); Bounds.update(body.bounds, body.vertices, body.velocity); // allow options to override the automatically calculated properties Body.set(body, { axes: options.axes || body.axes, area: options.area || body.area, mass: options.mass || body.mass, inertia: options.inertia || body.inertia }); // render properties var defaultFillStyle = (body.isStatic ? '#2e2b44' : Common.choose(['#006BA6', '#0496FF', '#FFBC42', '#D81159', '#8F2D56'])), defaultStrokeStyle = Common.shadeColor(defaultFillStyle, -20); body.render.fillStyle = body.render.fillStyle || defaultFillStyle; body.render.strokeStyle = body.render.strokeStyle || defaultStrokeStyle; body.render.sprite.xOffset += -(body.bounds.min.x - body.position.x) / (body.bounds.max.x - body.bounds.min.x); body.render.sprite.yOffset += -(body.bounds.min.y - body.position.y) / (body.bounds.max.y - body.bounds.min.y); }; /** * Given a property and a value (or map of), sets the property(s) on the body, using the appropriate setter functions if they exist. * Prefer to use the actual setter functions in performance critical situations. * @method set * @param {body} body * @param {} settings A property name (or map of properties and values) to set on the body. * @param {} value The value to set if `settings` is a single property name. */ Body.set = function(body, settings, value) { var property; if (typeof settings === 'string') { property = settings; settings = {}; settings[property] = value; } for (property in settings) { value = settings[property]; if (!settings.hasOwnProperty(property)) continue; switch (property) { case 'isStatic': Body.setStatic(body, value); break; case 'isSleeping': Sleeping.set(body, value); break; case 'mass': Body.setMass(body, value); break; case 'density': Body.setDensity(body, value); break; case 'inertia': Body.setInertia(body, value); break; case 'vertices': Body.setVertices(body, value); break; case 'position': Body.setPosition(body, value); break; case 'angle': Body.setAngle(body, value); break; case 'velocity': Body.setVelocity(body, value); break; case 'angularVelocity': Body.setAngularVelocity(body, value); break; case 'parts': Body.setParts(body, value); break; default: body[property] = value; } } }; /** * Sets the body as static, including isStatic flag and setting mass and inertia to Infinity. * @method setStatic * @param {body} body * @param {bool} isStatic */ Body.setStatic = function(body, isStatic) { for (var i = 0; i < body.parts.length; i++) { var part = body.parts[i]; part.isStatic = isStatic; if (isStatic) { part._original = { restitution: part.restitution, friction: part.friction, mass: part.mass, inertia: part.inertia, density: part.density, inverseMass: part.inverseMass, inverseInertia: part.inverseInertia }; part.restitution = 0; part.friction = 1; part.mass = part.inertia = part.density = Infinity; part.inverseMass = part.inverseInertia = 0; part.positionPrev.x = part.position.x; part.positionPrev.y = part.position.y; part.anglePrev = part.angle; part.angularVelocity = 0; part.speed = 0; part.angularSpeed = 0; part.motion = 0; } else if (part._original) { part.restitution = part._original.restitution; part.friction = part._original.friction; part.mass = part._original.mass; part.inertia = part._original.inertia; part.density = part._original.density; part.inverseMass = part._original.inverseMass; part.inverseInertia = part._original.inverseInertia; delete part._original; } } }; /** * Sets the mass of the body. Inverse mass and density are automatically updated to reflect the change. * @method setMass * @param {body} body * @param {number} mass */ Body.setMass = function(body, mass) { body.mass = mass; body.inverseMass = 1 / body.mass; body.density = body.mass / body.area; }; /** * Sets the density of the body. Mass is automatically updated to reflect the change. * @method setDensity * @param {body} body * @param {number} density */ Body.setDensity = function(body, density) { Body.setMass(body, density * body.area); body.density = density; }; /** * Sets the moment of inertia (i.e. second moment of area) of the body of the body. * Inverse inertia is automatically updated to reflect the change. Mass is not changed. * @method setInertia * @param {body} body * @param {number} inertia */ Body.setInertia = function(body, inertia) { body.inertia = inertia; body.inverseInertia = 1 / body.inertia; }; /** * Sets the body's vertices and updates body properties accordingly, including inertia, area and mass (with respect to `body.density`). * Vertices will be automatically transformed to be orientated around their centre of mass as the origin. * They are then automatically translated to world space based on `body.position`. * * The `vertices` argument should be passed as an array of `Matter.Vector` points (or a `Matter.Vertices` array). * Vertices must form a convex hull, concave hulls are not supported. * * @method setVertices * @param {body} body * @param {vector[]} vertices */ Body.setVertices = function(body, vertices) { // change vertices if (vertices[0].body === body) { body.vertices = vertices; } else { body.vertices = Vertices.create(vertices, body); } // update properties body.axes = Axes.fromVertices(body.vertices); body.area = Vertices.area(body.vertices); Body.setMass(body, body.density * body.area); // orient vertices around the centre of mass at origin (0, 0) var centre = Vertices.centre(body.vertices); Vertices.translate(body.vertices, centre, -1); // update inertia while vertices are at origin (0, 0) Body.setInertia(body, Body._inertiaScale * Vertices.inertia(body.vertices, body.mass)); // update geometry Vertices.translate(body.vertices, body.position); Bounds.update(body.bounds, body.vertices, body.velocity); }; /** * Sets the parts of the `body` and updates mass, inertia and centroid. * Each part will have its parent set to `body`. * By default the convex hull will be automatically computed and set on `body`, unless `autoHull` is set to `false.` * Note that this method will ensure that the first part in `body.parts` will always be the `body`. * @method setParts * @param {body} body * @param [body] parts * @param {bool} [autoHull=true] */ Body.setParts = function(body, parts, autoHull) { var i; // add all the parts, ensuring that the first part is always the parent body parts = parts.slice(0); body.parts.length = 0; body.parts.push(body); body.parent = body; for (i = 0; i < parts.length; i++) { var part = parts[i]; if (part !== body) { part.parent = body; body.parts.push(part); } } if (body.parts.length === 1) return; autoHull = typeof autoHull !== 'undefined' ? autoHull : true; // find the convex hull of all parts to set on the parent body if (autoHull) { var vertices = []; for (i = 0; i < parts.length; i++) { vertices = vertices.concat(parts[i].vertices); } Vertices.clockwiseSort(vertices); var hull = Vertices.hull(vertices), hullCentre = Vertices.centre(hull); Body.setVertices(body, hull); Vertices.translate(body.vertices, hullCentre); } // sum the properties of all compound parts of the parent body var total = _totalProperties(body); body.area = total.area; body.parent = body; body.position.x = total.centre.x; body.position.y = total.centre.y; body.positionPrev.x = total.centre.x; body.positionPrev.y = total.centre.y; Body.setMass(body, total.mass); Body.setInertia(body, total.inertia); Body.setPosition(body, total.centre); }; /** * Sets the position of the body instantly. Velocity, angle, force etc. are unchanged. * @method setPosition * @param {body} body * @param {vector} position */ Body.setPosition = function(body, position) { var delta = Vector.sub(position, body.position); body.positionPrev.x += delta.x; body.positionPrev.y += delta.y; for (var i = 0; i < body.parts.length; i++) { var part = body.parts[i]; part.position.x += delta.x; part.position.y += delta.y; Vertices.translate(part.vertices, delta); Bounds.update(part.bounds, part.vertices, body.velocity); } }; /** * Sets the angle of the body instantly. Angular velocity, position, force etc. are unchanged. * @method setAngle * @param {body} body * @param {number} angle */ Body.setAngle = function(body, angle) { var delta = angle - body.angle; body.anglePrev += delta; for (var i = 0; i < body.parts.length; i++) { var part = body.parts[i]; part.angle += delta; Vertices.rotate(part.vertices, delta, body.position); Axes.rotate(part.axes, delta); Bounds.update(part.bounds, part.vertices, body.velocity); if (i > 0) { Vector.rotateAbout(part.position, delta, body.position, part.position); } } }; /** * Sets the linear velocity of the body instantly. Position, angle, force etc. are unchanged. See also `Body.applyForce`. * @method setVelocity * @param {body} body * @param {vector} velocity */ Body.setVelocity = function(body, velocity) { body.positionPrev.x = body.position.x - velocity.x; body.positionPrev.y = body.position.y - velocity.y; body.velocity.x = velocity.x; body.velocity.y = velocity.y; body.speed = Vector.magnitude(body.velocity); }; /** * Sets the angular velocity of the body instantly. Position, angle, force etc. are unchanged. See also `Body.applyForce`. * @method setAngularVelocity * @param {body} body * @param {number} velocity */ Body.setAngularVelocity = function(body, velocity) { body.anglePrev = body.angle - velocity; body.angularVelocity = velocity; body.angularSpeed = Math.abs(body.angularVelocity); }; /** * Moves a body by a given vector relative to its current position, without imparting any velocity. * @method translate * @param {body} body * @param {vector} translation */ Body.translate = function(body, translation) { Body.setPosition(body, Vector.add(body.position, translation)); }; /** * Rotates a body by a given angle relative to its current angle, without imparting any angular velocity. * @method rotate * @param {body} body * @param {number} rotation */ Body.rotate = function(body, rotation) { Body.setAngle(body, body.angle + rotation); }; /** * Scales the body, including updating physical properties (mass, area, axes, inertia), from a world-space point (default is body centre). * @method scale * @param {body} body * @param {number} scaleX * @param {number} scaleY * @param {vector} [point] */ Body.scale = function(body, scaleX, scaleY, point) { for (var i = 0; i < body.parts.length; i++) { var part = body.parts[i]; // scale vertices Vertices.scale(part.vertices, scaleX, scaleY, body.position); // update properties part.axes = Axes.fromVertices(part.vertices); if (!body.isStatic) { part.area = Vertices.area(part.vertices); Body.setMass(part, body.density * part.area); // update inertia (requires vertices to be at origin) Vertices.translate(part.vertices, { x: -part.position.x, y: -part.position.y }); Body.setInertia(part, Vertices.inertia(part.vertices, part.mass)); Vertices.translate(part.vertices, { x: part.position.x, y: part.position.y }); } // update bounds Bounds.update(part.bounds, part.vertices, body.velocity); } // handle circles if (body.circleRadius) { if (scaleX === scaleY) { body.circleRadius *= scaleX; } else { // body is no longer a circle body.circleRadius = null; } } if (!body.isStatic) { var total = _totalProperties(body); body.area = total.area; Body.setMass(body, total.mass); Body.setInertia(body, total.inertia); } }; /** * Performs a simulation step for the given `body`, including updating position and angle using Verlet integration. * @method update * @param {body} body * @param {number} deltaTime * @param {number} timeScale * @param {number} correction */ Body.update = function(body, deltaTime, timeScale, correction) { var deltaTimeSquared = Math.pow(deltaTime * timeScale * body.timeScale, 2); // from the previous step var frictionAir = 1 - body.frictionAir * timeScale * body.timeScale, velocityPrevX = body.position.x - body.positionPrev.x, velocityPrevY = body.position.y - body.positionPrev.y; // update velocity with Verlet integration body.velocity.x = (velocityPrevX * frictionAir * correction) + (body.force.x / body.mass) * deltaTimeSquared; body.velocity.y = (velocityPrevY * frictionAir * correction) + (body.force.y / body.mass) * deltaTimeSquared; body.positionPrev.x = body.position.x; body.positionPrev.y = body.position.y; body.position.x += body.velocity.x; body.position.y += body.velocity.y; // update angular velocity with Verlet integration body.angularVelocity = ((body.angle - body.anglePrev) * frictionAir * correction) + (body.torque / body.inertia) * deltaTimeSquared; body.anglePrev = body.angle; body.angle += body.angularVelocity; // track speed and acceleration body.speed = Vector.magnitude(body.velocity); body.angularSpeed = Math.abs(body.angularVelocity); // transform the body geometry for (var i = 0; i < body.parts.length; i++) { var part = body.parts[i]; Vertices.translate(part.vertices, body.velocity); if (i > 0) { part.position.x += body.velocity.x; part.position.y += body.velocity.y; } if (body.angularVelocity !== 0) { Vertices.rotate(part.vertices, body.angularVelocity, body.position); Axes.rotate(part.axes, body.angularVelocity); if (i > 0) { Vector.rotateAbout(part.position, body.angularVelocity, body.position, part.position); } } Bounds.update(part.bounds, part.vertices, body.velocity); } }; /** * Applies a force to a body from a given world-space position, including resulting torque. * @method applyForce * @param {body} body * @param {vector} position * @param {vector} force */ Body.applyForce = function(body, position, force) { body.force.x += force.x; body.force.y += force.y; var offset = { x: position.x - body.position.x, y: position.y - body.position.y }; body.torque += offset.x * force.y - offset.y * force.x; }; /** * Returns the sums of the properties of all compound parts of the parent body. * @method _totalProperties * @private * @param {body} body * @return {} */ var _totalProperties = function(body) { // https://ecourses.ou.edu/cgi-bin/ebook.cgi?doc=&topic=st&chap_sec=07.2&page=theory // http://output.to/sideway/default.asp?qno=121100087 var properties = { mass: 0, area: 0, inertia: 0, centre: { x: 0, y: 0 } }; // sum the properties of all compound parts of the parent body for (var i = body.parts.length === 1 ? 0 : 1; i < body.parts.length; i++) { var part = body.parts[i]; properties.mass += part.mass; properties.area += part.area; properties.inertia += part.inertia; properties.centre = Vector.add(properties.centre, Vector.mult(part.position, part.mass !== Infinity ? part.mass : 1)); } properties.centre = Vector.div(properties.centre, properties.mass !== Infinity ? properties.mass : body.parts.length); return properties; }; /* * * Events Documentation * */ /** * Fired when a body starts sleeping (where `this` is the body). * * @event sleepStart * @this {body} The body that has started sleeping * @param {} event An event object * @param {} event.source The source object of the event * @param {} event.name The name of the event */ /** * Fired when a body ends sleeping (where `this` is the body). * * @event sleepEnd * @this {body} The body that has ended sleeping * @param {} event An event object * @param {} event.source The source object of the event * @param {} event.name The name of the event */ /* * * Properties Documentation * */ /** * An integer `Number` uniquely identifying number generated in `Body.create` by `Common.nextId`. * * @property id * @type number */ /** * A `String` denoting the type of object. * * @property type * @type string * @default "body" * @readOnly */ /** * An arbitrary `String` name to help the user identify and manage bodies. * * @property label * @type string * @default "Body" */ /** * An array of bodies that make up this body. * The first body in the array must always be a self reference to the current body instance. * All bodies in the `parts` array together form a single rigid compound body. * Parts are allowed to overlap, have gaps or holes or even form concave bodies. * Parts themselves should never be added to a `World`, only the parent body should be. * Use `Body.setParts` when setting parts to ensure correct updates of all properties. * * @property parts * @type body[] */ /** * An object reserved for storing plugin-specific properties. * * @property plugin * @type {} */ /** * A self reference if the body is _not_ a part of another body. * Otherwise this is a reference to the body that this is a part of. * See `body.parts`. * * @property parent * @type body */ /** * A `Number` specifying the angle of the body, in radians. * * @property angle * @type number * @default 0 */ /** * An array of `Vector` objects that specify the convex hull of the rigid body. * These should be provided about the origin `(0, 0)`. E.g. * * [{ x: 0, y: 0 }, { x: 25, y: 50 }, { x: 50, y: 0 }] * * When passed via `Body.create`, the vertices are translated relative to `body.position` (i.e. world-space, and constantly updated by `Body.update` during simulation). * The `Vector` objects are also augmented with additional properties required for efficient collision detection. * * Other properties such as `inertia` and `bounds` are automatically calculated from the passed vertices (unless provided via `options`). * Concave hulls are not currently supported. The module `Matter.Vertices` contains useful methods for working with vertices. * * @property vertices * @type vector[] */ /** * A `Vector` that specifies the current world-space position of the body. * * @property position * @type vector * @default { x: 0, y: 0 } */ /** * A `Vector` that specifies the force to apply in the current step. It is zeroed after every `Body.update`. See also `Body.applyForce`. * * @property force * @type vector * @default { x: 0, y: 0 } */ /** * A `Number` that specifies the torque (turning force) to apply in the current step. It is zeroed after every `Body.update`. * * @property torque * @type number * @default 0 */ /** * A `Number` that _measures_ the current speed of the body after the last `Body.update`. It is read-only and always positive (it's the magnitude of `body.velocity`). * * @readOnly * @property speed * @type number * @default 0 */ /** * A `Number` that _measures_ the current angular speed of the body after the last `Body.update`. It is read-only and always positive (it's the magnitude of `body.angularVelocity`). * * @readOnly * @property angularSpeed * @type number * @default 0 */ /** * A `Vector` that _measures_ the current velocity of the body after the last `Body.update`. It is read-only. * If you need to modify a body's velocity directly, you should either apply a force or simply change the body's `position` (as the engine uses position-Verlet integration). * * @readOnly * @property velocity * @type vector * @default { x: 0, y: 0 } */ /** * A `Number` that _measures_ the current angular velocity of the body after the last `Body.update`. It is read-only. * If you need to modify a body's angular velocity directly, you should apply a torque or simply change the body's `angle` (as the engine uses position-Verlet integration). * * @readOnly * @property angularVelocity * @type number * @default 0 */ /** * A flag that indicates whether a body is considered static. A static body can never change position or angle and is completely fixed. * If you need to set a body as static after its creation, you should use `Body.setStatic` as this requires more than just setting this flag. * * @property isStatic * @type boolean * @default false */ /** * A flag that indicates whether a body is a sensor. Sensor triggers collision events, but doesn't react with colliding body physically. * * @property isSensor * @type boolean * @default false */ /** * A flag that indicates whether the body is considered sleeping. A sleeping body acts similar to a static body, except it is only temporary and can be awoken. * If you need to set a body as sleeping, you should use `Sleeping.set` as this requires more than just setting this flag. * * @property isSleeping * @type boolean * @default false */ /** * A `Number` that _measures_ the amount of movement a body currently has (a combination of `speed` and `angularSpeed`). It is read-only and always positive. * It is used and updated by the `Matter.Sleeping` module during simulation to decide if a body has come to rest. * * @readOnly * @property motion * @type number * @default 0 */ /** * A `Number` that defines the number of updates in which this body must have near-zero velocity before it is set as sleeping by the `Matter.Sleeping` module (if sleeping is enabled by the engine). * * @property sleepThreshold * @type number * @default 60 */ /** * A `Number` that defines the density of the body, that is its mass per unit area. * If you pass the density via `Body.create` the `mass` property is automatically calculated for you based on the size (area) of the object. * This is generally preferable to simply setting mass and allows for more intuitive definition of materials (e.g. rock has a higher density than wood). * * @property density * @type number * @default 0.001 */ /** * A `Number` that defines the mass of the body, although it may be more appropriate to specify the `density` property instead. * If you modify this value, you must also modify the `body.inverseMass` property (`1 / mass`). * * @property mass * @type number */ /** * A `Number` that defines the inverse mass of the body (`1 / mass`). * If you modify this value, you must also modify the `body.mass` property. * * @property inverseMass * @type number */ /** * A `Number` that defines the moment of inertia (i.e. second moment of area) of the body. * It is automatically calculated from the given convex hull (`vertices` array) and density in `Body.create`. * If you modify this value, you must also modify the `body.inverseInertia` property (`1 / inertia`). * * @property inertia * @type number */ /** * A `Number` that defines the inverse moment of inertia of the body (`1 / inertia`). * If you modify this value, you must also modify the `body.inertia` property. * * @property inverseInertia * @type number */ /** * A `Number` that defines the restitution (elasticity) of the body. The value is always positive and is in the range `(0, 1)`. * A value of `0` means collisions may be perfectly inelastic and no bouncing may occur. * A value of `0.8` means the body may bounce back with approximately 80% of its kinetic energy. * Note that collision response is based on _pairs_ of bodies, and that `restitution` values are _combined_ with the following formula: * * Math.max(bodyA.restitution, bodyB.restitution) * * @property restitution * @type number * @default 0 */ /** * A `Number` that defines the friction of the body. The value is always positive and is in the range `(0, 1)`. * A value of `0` means that the body may slide indefinitely. * A value of `1` means the body may come to a stop almost instantly after a force is applied. * * The effects of the value may be non-linear. * High values may be unstable depending on the body. * The engine uses a Coulomb friction model including static and kinetic friction. * Note that collision response is based on _pairs_ of bodies, and that `friction` values are _combined_ with the following formula: * * Math.min(bodyA.friction, bodyB.friction) * * @property friction * @type number * @default 0.1 */ /** * A `Number` that defines the static friction of the body (in the Coulomb friction model). * A value of `0` means the body will never 'stick' when it is nearly stationary and only dynamic `friction` is used. * The higher the value (e.g. `10`), the more force it will take to initially get the body moving when nearly stationary. * This value is multiplied with the `friction` property to make it easier to change `friction` and maintain an appropriate amount of static friction. * * @property frictionStatic * @type number * @default 0.5 */ /** * A `Number` that defines the air friction of the body (air resistance). * A value of `0` means the body will never slow as it moves through space. * The higher the value, the faster a body slows when moving through space. * The effects of the value are non-linear. * * @property frictionAir * @type number * @default 0.01 */ /** * An `Object` that specifies the collision filtering properties of this body. * * Collisions between two bodies will obey the following rules: * - If the two bodies have the same non-zero value of `collisionFilter.group`, * they will always collide if the value is positive, and they will never collide * if the value is negative. * - If the two bodies have different values of `collisionFilter.group` or if one * (or both) of the bodies has a value of 0, then the category/mask rules apply as follows: * * Each body belongs to a collision category, given by `collisionFilter.category`. This * value is used as a bit field and the category should have only one bit set, meaning that * the value of this property is a power of two in the range [1, 2^31]. Thus, there are 32 * different collision categories available. * * Each body also defines a collision bitmask, given by `collisionFilter.mask` which specifies * the categories it collides with (the value is the bitwise AND value of all these categories). * * Using the category/mask rules, two bodies `A` and `B` collide if each includes the other's * category in its mask, i.e. `(categoryA & maskB) !== 0` and `(categoryB & maskA) !== 0` * are both true. * * @property collisionFilter * @type object */ /** * An Integer `Number`, that specifies the collision group this body belongs to. * See `body.collisionFilter` for more information. * * @property collisionFilter.group * @type object * @default 0 */ /** * A bit field that specifies the collision category this body belongs to. * The category value should have only one bit set, for example `0x0001`. * This means there are up to 32 unique collision categories available. * See `body.collisionFilter` for more information. * * @property collisionFilter.category * @type object * @default 1 */ /** * A bit mask that specifies the collision categories this body may collide with. * See `body.collisionFilter` for more information. * * @property collisionFilter.mask * @type object * @default -1 */ /** * A `Number` that specifies a tolerance on how far a body is allowed to 'sink' or rotate into other bodies. * Avoid changing this value unless you understand the purpose of `slop` in physics engines. * The default should generally suffice, although very large bodies may require larger values for stable stacking. * * @property slop * @type number * @default 0.05 */ /** * A `Number` that allows per-body time scaling, e.g. a force-field where bodies inside are in slow-motion, while others are at full speed. * * @property timeScale * @type number * @default 1 */ /** * An `Object` that defines the rendering properties to be consumed by the module `Matter.Render`. * * @property render * @type object */ /** * A flag that indicates if the body should be rendered. * * @property render.visible * @type boolean * @default true */ /** * Sets the opacity to use when rendering. * * @property render.opacity * @type number * @default 1 */ /** * An `Object` that defines the sprite properties to use when rendering, if any. * * @property render.sprite * @type object */ /** * An `String` that defines the path to the image to use as the sprite texture, if any. * * @property render.sprite.texture * @type string */ /** * A `Number` that defines the scaling in the x-axis for the sprite, if any. * * @property render.sprite.xScale * @type number * @default 1 */ /** * A `Number` that defines the scaling in the y-axis for the sprite, if any. * * @property render.sprite.yScale * @type number * @default 1 */ /** * A `Number` that defines the offset in the x-axis for the sprite (normalised by texture width). * * @property render.sprite.xOffset * @type number * @default 0 */ /** * A `Number` that defines the offset in the y-axis for the sprite (normalised by texture height). * * @property render.sprite.yOffset * @type number * @default 0 */ /** * A `Number` that defines the line width to use when rendering the body outline (if a sprite is not defined). * A value of `0` means no outline will be rendered. * * @property render.lineWidth * @type number * @default 1.5 */ /** * A `String` that defines the fill style to use when rendering the body (if a sprite is not defined). * It is the same as when using a canvas, so it accepts CSS style property values. * * @property render.fillStyle * @type string * @default a random colour */ /** * A `String` that defines the stroke style to use when rendering the body outline (if a sprite is not defined). * It is the same as when using a canvas, so it accepts CSS style property values. * * @property render.strokeStyle * @type string * @default a random colour */ /** * An array of unique axis vectors (edge normals) used for collision detection. * These are automatically calculated from the given convex hull (`vertices` array) in `Body.create`. * They are constantly updated by `Body.update` during the simulation. * * @property axes * @type vector[] */ /** * A `Number` that _measures_ the area of the body's convex hull, calculated at creation by `Body.create`. * * @property area * @type string * @default */ /** * A `Bounds` object that defines the AABB region for the body. * It is automatically calculated from the given convex hull (`vertices` array) in `Body.create` and constantly updated by `Body.update` during simulation. * * @property bounds * @type bounds */ })();