/**
* The `Matter.Body` module contains methods for creating and manipulating rigid bodies.
* For creating bodies with common configurations such as rectangles, circles and other polygons see 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 Common = require('../core/Common');
var Bounds = require('../geometry/Bounds');
var Axes = require('../geometry/Axes');
(function() {
Body._timeCorrection = true;
Body._inertiaScale = 4;
Body._nextCollidingGroupId = 1;
Body._nextNonCollidingGroupId = -1;
Body._nextCategory = 0x0001;
Body._baseDelta = 1000 / 60;
/**
* 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,
strokeStyle: null,
fillStyle: null,
lineWidth: null,
sprite: {
xScale: 1,
yScale: 1,
xOffset: 0,
yOffset: 0
}
},
events: null,
bounds: null,
chamfer: null,
circleRadius: 0,
positionPrev: null,
anglePrev: 0,
parent: null,
axes: null,
area: 0,
mass: 0,
inertia: 0,
deltaTime: 1000 / 60,
_original: null
};
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 ? '#14151f' : Common.choose(['#f19648', '#f5d259', '#f55a3c', '#063e7b', '#ececd1'])),
defaultStrokeStyle = body.isStatic ? '#555' : '#ccc',
defaultLineWidth = body.isStatic && body.render.fillStyle === null ? 1 : 0;
body.render.fillStyle = body.render.fillStyle || defaultFillStyle;
body.render.strokeStyle = body.render.strokeStyle || defaultStrokeStyle;
body.render.lineWidth = body.render.lineWidth || defaultLineWidth;
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) {
if (!Object.prototype.hasOwnProperty.call(settings, property))
continue;
value = settings[property];
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 'speed':
Body.setSpeed(body, value);
break;
case 'angularSpeed':
Body.setAngularSpeed(body, value);
break;
case 'parts':
Body.setParts(body, value);
break;
case 'centre':
Body.setCentre(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];
if (isStatic) {
if (!part.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;
part._original = null;
}
part.isStatic = isStatic;
}
};
/**
* Sets the mass of the body. Inverse mass, density and inertia are automatically updated to reflect the change.
* @method setMass
* @param {body} body
* @param {number} mass
*/
Body.setMass = function(body, mass) {
var moment = body.inertia / (body.mass / 6);
body.inertia = moment * (mass / 6);
body.inverseInertia = 1 / body.inertia;
body.mass = mass;
body.inverseMass = 1 / body.mass;
body.density = body.mass / body.area;
};
/**
* Sets the density of the body. Mass and inertia are 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 of the body. This is the second moment of area in two dimensions.
* 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 vertices must be decomposed into convex parts.
*
* @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`.
*
* See `body.parts` for details and requirements on how parts are used.
*
* See Bodies.fromVertices for a related utility.
*
* This function updates `body` mass, inertia and centroid based on the parts geometry.
* Sets each `part.parent` to be this `body`.
*
* The convex hull is computed and set on this `body` (unless `autoHull` is `false`).
* Automatically ensures that the first part in `body.parts` is 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 = Body._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);
};
/**
* Set the centre of mass of the body.
* The `centre` is a vector in world-space unless `relative` is set, in which case it is a translation.
* The centre of mass is the point the body rotates about and can be used to simulate non-uniform density.
* This is equal to moving `body.position` but not the `body.vertices`.
* Invalid if the `centre` falls outside the body's convex hull.
* @method setCentre
* @param {body} body
* @param {vector} centre
* @param {bool} relative
*/
Body.setCentre = function(body, centre, relative) {
if (!relative) {
body.positionPrev.x = centre.x - (body.position.x - body.positionPrev.x);
body.positionPrev.y = centre.y - (body.position.y - body.positionPrev.y);
body.position.x = centre.x;
body.position.y = centre.y;
} else {
body.positionPrev.x += centre.x;
body.positionPrev.y += centre.y;
body.position.x += centre.x;
body.position.y += centre.y;
}
};
/**
* Sets the position of the body. By default velocity is unchanged.
* If `updateVelocity` is `true` then velocity is inferred from the change in position.
* @method setPosition
* @param {body} body
* @param {vector} position
* @param {boolean} [updateVelocity=false]
*/
Body.setPosition = function(body, position, updateVelocity) {
var delta = Vector.sub(position, body.position);
if (updateVelocity) {
body.positionPrev.x = body.position.x;
body.positionPrev.y = body.position.y;
body.velocity.x = delta.x;
body.velocity.y = delta.y;
body.speed = Vector.magnitude(delta);
} else {
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. By default angular velocity is unchanged.
* If `updateVelocity` is `true` then angular velocity is inferred from the change in angle.
* @method setAngle
* @param {body} body
* @param {number} angle
* @param {boolean} [updateVelocity=false]
*/
Body.setAngle = function(body, angle, updateVelocity) {
var delta = angle - body.angle;
if (updateVelocity) {
body.anglePrev = body.angle;
body.angularVelocity = delta;
body.angularSpeed = Math.abs(delta);
} else {
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 current linear velocity of the body.
* Affects body speed.
* @method setVelocity
* @param {body} body
* @param {vector} velocity
*/
Body.setVelocity = function(body, velocity) {
var timeScale = body.deltaTime / Body._baseDelta;
body.positionPrev.x = body.position.x - velocity.x * timeScale;
body.positionPrev.y = body.position.y - velocity.y * timeScale;
body.velocity.x = (body.position.x - body.positionPrev.x) / timeScale;
body.velocity.y = (body.position.y - body.positionPrev.y) / timeScale;
body.speed = Vector.magnitude(body.velocity);
};
/**
* Gets the current linear velocity of the body.
* @method getVelocity
* @param {body} body
* @return {vector} velocity
*/
Body.getVelocity = function(body) {
var timeScale = Body._baseDelta / body.deltaTime;
return {
x: (body.position.x - body.positionPrev.x) * timeScale,
y: (body.position.y - body.positionPrev.y) * timeScale
};
};
/**
* Gets the current linear speed of the body.
* Equivalent to the magnitude of its velocity.
* @method getSpeed
* @param {body} body
* @return {number} speed
*/
Body.getSpeed = function(body) {
return Vector.magnitude(Body.getVelocity(body));
};
/**
* Sets the current linear speed of the body.
* Direction is maintained. Affects body velocity.
* @method setSpeed
* @param {body} body
* @param {number} speed
*/
Body.setSpeed = function(body, speed) {
Body.setVelocity(body, Vector.mult(Vector.normalise(Body.getVelocity(body)), speed));
};
/**
* Sets the current rotational velocity of the body.
* Affects body angular speed.
* @method setAngularVelocity
* @param {body} body
* @param {number} velocity
*/
Body.setAngularVelocity = function(body, velocity) {
var timeScale = body.deltaTime / Body._baseDelta;
body.anglePrev = body.angle - velocity * timeScale;
body.angularVelocity = (body.angle - body.anglePrev) / timeScale;
body.angularSpeed = Math.abs(body.angularVelocity);
};
/**
* Gets the current rotational velocity of the body.
* @method getAngularVelocity
* @param {body} body
* @return {number} angular velocity
*/
Body.getAngularVelocity = function(body) {
return (body.angle - body.anglePrev) * Body._baseDelta / body.deltaTime;
};
/**
* Gets the current rotational speed of the body.
* Equivalent to the magnitude of its angular velocity.
* @method getAngularSpeed
* @param {body} body
* @return {number} angular speed
*/
Body.getAngularSpeed = function(body) {
return Math.abs(Body.getAngularVelocity(body));
};
/**
* Sets the current rotational speed of the body.
* Direction is maintained. Affects body angular velocity.
* @method setAngularSpeed
* @param {body} body
* @param {number} speed
*/
Body.setAngularSpeed = function(body, speed) {
Body.setAngularVelocity(body, Common.sign(Body.getAngularVelocity(body)) * speed);
};
/**
* Moves a body by a given vector relative to its current position. By default velocity is unchanged.
* If `updateVelocity` is `true` then velocity is inferred from the change in position.
* @method translate
* @param {body} body
* @param {vector} translation
* @param {boolean} [updateVelocity=false]
*/
Body.translate = function(body, translation, updateVelocity) {
Body.setPosition(body, Vector.add(body.position, translation), updateVelocity);
};
/**
* Rotates a body by a given angle relative to its current angle. By default angular velocity is unchanged.
* If `updateVelocity` is `true` then angular velocity is inferred from the change in angle.
* @method rotate
* @param {body} body
* @param {number} rotation
* @param {vector} [point]
* @param {boolean} [updateVelocity=false]
*/
Body.rotate = function(body, rotation, point, updateVelocity) {
if (!point) {
Body.setAngle(body, body.angle + rotation, updateVelocity);
} else {
var cos = Math.cos(rotation),
sin = Math.sin(rotation),
dx = body.position.x - point.x,
dy = body.position.y - point.y;
Body.setPosition(body, {
x: point.x + (dx * cos - dy * sin),
y: point.y + (dx * sin + dy * cos)
}, updateVelocity);
Body.setAngle(body, body.angle + rotation, updateVelocity);
}
};
/**
* 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) {
var totalArea = 0,
totalInertia = 0;
point = point || body.position;
for (var i = 0; i < body.parts.length; i++) {
var part = body.parts[i];
// scale vertices
Vertices.scale(part.vertices, scaleX, scaleY, point);
// update properties
part.axes = Axes.fromVertices(part.vertices);
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, Body._inertiaScale * Vertices.inertia(part.vertices, part.mass));
Vertices.translate(part.vertices, { x: part.position.x, y: part.position.y });
if (i > 0) {
totalArea += part.area;
totalInertia += part.inertia;
}
// scale position
part.position.x = point.x + (part.position.x - point.x) * scaleX;
part.position.y = point.y + (part.position.y - point.y) * scaleY;
// update bounds
Bounds.update(part.bounds, part.vertices, body.velocity);
}
// handle parent body
if (body.parts.length > 1) {
body.area = totalArea;
if (!body.isStatic) {
Body.setMass(body, body.density * totalArea);
Body.setInertia(body, totalInertia);
}
}
// handle circles
if (body.circleRadius) {
if (scaleX === scaleY) {
body.circleRadius *= scaleX;
} else {
// body is no longer a circle
body.circleRadius = null;
}
}
};
/**
* Performs an update by integrating the equations of motion on the `body`.
* This is applied every update by `Matter.Engine` automatically.
* @method update
* @param {body} body
* @param {number} [deltaTime=16.666]
*/
Body.update = function(body, deltaTime) {
deltaTime = (typeof deltaTime !== 'undefined' ? deltaTime : (1000 / 60)) * body.timeScale;
var deltaTimeSquared = deltaTime * deltaTime,
correction = Body._timeCorrection ? deltaTime / (body.deltaTime || deltaTime) : 1;
// from the previous step
var frictionAir = 1 - body.frictionAir * (deltaTime / Common._baseDelta),
velocityPrevX = (body.position.x - body.positionPrev.x) * correction,
velocityPrevY = (body.position.y - body.positionPrev.y) * correction;
// update velocity with Verlet integration
body.velocity.x = (velocityPrevX * frictionAir) + (body.force.x / body.mass) * deltaTimeSquared;
body.velocity.y = (velocityPrevY * frictionAir) + (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;
body.deltaTime = deltaTime;
// 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;
// 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);
}
};
/**
* Updates properties `body.velocity`, `body.speed`, `body.angularVelocity` and `body.angularSpeed` which are normalised in relation to `Body._baseDelta`.
* @method updateVelocities
* @param {body} body
*/
Body.updateVelocities = function(body) {
var timeScale = Body._baseDelta / body.deltaTime,
bodyVelocity = body.velocity;
bodyVelocity.x = (body.position.x - body.positionPrev.x) * timeScale;
bodyVelocity.y = (body.position.y - body.positionPrev.y) * timeScale;
body.speed = Math.sqrt((bodyVelocity.x * bodyVelocity.x) + (bodyVelocity.y * bodyVelocity.y));
body.angularVelocity = (body.angle - body.anglePrev) * timeScale;
body.angularSpeed = Math.abs(body.angularVelocity);
};
/**
* Applies the `force` to the `body` from the force origin `position` in world-space, over a single timestep, including applying any resulting angular torque.
*
* Forces are useful for effects like gravity, wind or rocket thrust, but can be difficult in practice when precise control is needed. In these cases see `Body.setVelocity` and `Body.setPosition` as an alternative.
*
* The force from this function is only applied once for the duration of a single timestep, in other words the duration depends directly on the current engine update `delta` and the rate of calls to this function.
*
* Therefore to account for time, you should apply the force constantly over as many engine updates as equivalent to the intended duration.
*
* If all or part of the force duration is some fraction of a timestep, first multiply the force by `duration / timestep`.
*
* The force origin `position` in world-space must also be specified. Passing `body.position` will result in zero angular effect as the force origin would be at the centre of mass.
*
* The `body` will take time to accelerate under a force, the resulting effect depends on duration of the force, the body mass and other forces on the body including friction combined.
* @method applyForce
* @param {body} body
* @param {vector} position The force origin in world-space. Pass `body.position` to avoid angular torque.
* @param {vector} force
*/
Body.applyForce = function(body, position, force) {
var offset = { x: position.x - body.position.x, y: position.y - body.position.y };
body.force.x += force.x;
body.force.y += force.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 {}
*/
Body._totalProperties = function(body) {
// from equations at:
// 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],
mass = part.mass !== Infinity ? part.mass : 1;
properties.mass += mass;
properties.area += part.area;
properties.inertia += part.inertia;
properties.centre = Vector.add(properties.centre, Vector.mult(part.position, mass));
}
properties.centre = Vector.div(properties.centre, properties.mass);
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
*/
/**
* _Read only_. Set by `Body.create`.
*
* A `String` denoting the type of object.
*
* @readOnly
* @property type
* @type string
* @default "body"
*/
/**
* An arbitrary `String` name to help the user identify and manage bodies.
*
* @property label
* @type string
* @default "Body"
*/
/**
* _Read only_. Use `Body.setParts` to set.
*
* See `Bodies.fromVertices` for a related utility.
*
* An array of bodies (the 'parts') that make up this body (the 'parent'). The first body in this array must always be a self-reference to this `body`.
*
* The parts are fixed together and therefore perform as a single unified rigid body.
*
* Parts in relation to each other are allowed to overlap, as well as form gaps or holes, so can be used to create complex concave bodies unlike when using a single part.
*
* Use properties and functions on the parent `body` rather than on parts.
*
* Outside of their geometry, most properties on parts are not considered or updated.
* As such 'per-part' material properties among others are not currently considered.
*
* Parts should be created specifically for their parent body.
* Parts should not be shared or reused between bodies, only one parent is supported.
* Parts should not have their own parts, they are not handled recursively.
* Parts should not be added to the world directly or any other composite.
* Parts own vertices must be convex and in clockwise order.
*
* A body with more than one part is sometimes referred to as a 'compound' body.
*
* Use `Body.setParts` when setting parts to ensure correct updates of all properties.
*
* @readOnly
* @property parts
* @type body[]
*/
/**
* An object reserved for storing plugin-specific properties.
*
* @property plugin
* @type {}
*/
/**
* _Read only_. Updated by `Body.setParts`.
*
* A reference to the body that this is a part of. See `body.parts`.
* This is a self reference if the body is not a part of another body.
*
* @readOnly
* @property parent
* @type body
*/
/**
* A `Number` specifying the angle of the body, in radians.
*
* @property angle
* @type number
* @default 0
*/
/**
* _Read only_. Use `Body.setVertices` or `Body.setParts` to set. See also `Bodies.fromVertices`.
*
* 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 }]`
*
* Vertices must always be convex, in clockwise order and must not contain any duplicate points.
*
* Concave vertices should be decomposed into convex `parts`, see `Bodies.fromVertices` and `Body.setParts`.
*
* When set the vertices are translated such that `body.position` is at the centre of mass.
* Many other body properties are automatically calculated from these vertices when set including `density`, `area` and `inertia`.
*
* The module `Matter.Vertices` contains useful methods for working with vertices.
*
* @readOnly
* @property vertices
* @type vector[]
*/
/**
* _Read only_. Use `Body.setPosition` to set.
*
* A `Vector` that specifies the current world-space position of the body.
*
* @readOnly
* @property position
* @type vector
* @default { x: 0, y: 0 }
*/
/**
* A `Vector` that accumulates the total force applied to the body for a single update.
* Force is zeroed after every `Engine.update`, so constant forces should be applied for every update they are needed. See also `Body.applyForce`.
*
* @property force
* @type vector
* @default { x: 0, y: 0 }
*/
/**
* A `Number` that accumulates the total torque (turning force) applied to the body for a single update. See also `Body.applyForce`.
* Torque is zeroed after every `Engine.update`, so constant torques should be applied for every update they are needed.
*
* Torques result in angular acceleration on every update, which depends on body inertia and the engine update delta.
*
* @property torque
* @type number
* @default 0
*/
/**
* _Read only_. Use `Body.setSpeed` to set.
*
* See `Body.getSpeed` for details.
*
* Equivalent to the magnitude of `body.velocity` (always positive).
*
* @readOnly
* @property speed
* @type number
* @default 0
*/
/**
* _Read only_. Use `Body.setVelocity` to set.
*
* See `Body.getVelocity` for details.
*
* Equivalent to the magnitude of `body.angularVelocity` (always positive).
*
* @readOnly
* @property velocity
* @type vector
* @default { x: 0, y: 0 }
*/
/**
* _Read only_. Use `Body.setAngularSpeed` to set.
*
* See `Body.getAngularSpeed` for details.
*
*
* @readOnly
* @property angularSpeed
* @type number
* @default 0
*/
/**
* _Read only_. Use `Body.setAngularVelocity` to set.
*
* See `Body.getAngularVelocity` for details.
*
*
* @readOnly
* @property angularVelocity
* @type number
* @default 0
*/
/**
* _Read only_. Use `Body.setStatic` to set.
*
* A flag that indicates whether a body is considered static. A static body can never change position or angle and is completely fixed.
*
* @readOnly
* @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
*/
/**
* _Read only_. Use `Sleeping.set` to set.
*
* 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.
*
* @readOnly
* @property isSleeping
* @type boolean
* @default false
*/
/**
* _Read only_. Calculated during engine update only when sleeping is enabled.
*
* A `Number` that loosely measures the amount of movement a body currently has.
*
* Derived from `body.speed^2 + body.angularSpeed^2`. See `Sleeping.update`.
*
* @readOnly
* @property motion
* @type number
* @default 0
*/
/**
* A `Number` that defines the length of time during 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
*/
/**
* _Read only_. Use `Body.setDensity` to set.
*
* A `Number` that defines the density of the body (mass per unit area).
*
* Mass will also be updated when set.
*
* @readOnly
* @property density
* @type number
* @default 0.001
*/
/**
* _Read only_. Use `Body.setMass` to set.
*
* A `Number` that defines the mass of the body.
*
* Density will also be updated when set.
*
* @readOnly
* @property mass
* @type number
*/
/**
* _Read only_. Use `Body.setMass` to set.
*
* A `Number` that defines the inverse mass of the body (`1 / mass`).
*
* @readOnly
* @property inverseMass
* @type number
*/
/**
* _Read only_. Automatically calculated when vertices, mass or density are set or set through `Body.setInertia`.
*
* A `Number` that defines the moment of inertia of the body. This is the second moment of area in two dimensions.
*
* Can be manually set to `Infinity` to prevent rotation of the body. See `Body.setInertia`.
*
* @readOnly
* @property inertia
* @type number
*/
/**
* _Read only_. Automatically calculated when vertices, mass or density are set or calculated by `Body.setInertia`.
*
* A `Number` that defines the inverse moment of inertia of the body (`1 / inertia`).
*
* @readOnly
* @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 thin boundary around the body where it is allowed to slightly sink into other bodies.
*
* This is required for proper collision response, including friction and restitution effects.
*
* The default should generally suffice in most cases. You may need to decrease this value for very small bodies that are nearing the default value in scale.
*
* @property slop
* @type number
* @default 0.05
*/
/**
* A `Number` that specifies per-body time scaling.
*
* @property timeScale
* @type number
* @default 1
*/
/**
* _Read only_. Updated during engine update.
*
* A `Number` that records the last delta time value used to update this body.
* Used to calculate speed and velocity.
*
* @readOnly
* @property deltaTime
* @type number
* @default 1000 / 60
*/
/**
* 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 0
*/
/**
* 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
*/
/**
* _Read only_. Calculated automatically when vertices are set.
*
* An array of unique axis vectors (edge normals) used for collision detection.
* These are automatically calculated when vertices are set.
* They are constantly updated by `Body.update` during the simulation.
*
* @readOnly
* @property axes
* @type vector[]
*/
/**
* _Read only_. Calculated automatically when vertices are set.
*
* A `Number` that measures the area of the body's convex hull.
*
* @readOnly
* @property area
* @type string
* @default
*/
/**
* A `Bounds` object that defines the AABB region for the body.
* It is automatically calculated when vertices are set and constantly updated by `Body.update` during simulation.
*
* @property bounds
* @type bounds
*/
/**
* Temporarily may hold parameters to be passed to `Vertices.chamfer` where supported by external functions.
*
* See `Vertices.chamfer` for possible parameters this object may hold.
*
* Currently only functions inside `Matter.Bodies` provide a utility using this property as a vertices pre-processing option.
*
* Alternatively consider using `Vertices.chamfer` directly on vertices before passing them to a body creation function.
*
* @property chamfer
* @type object|null|undefined
*/
})();