Show:

File: src/core/Engine.js

                        /**
                        * The `Matter.Engine` module contains methods for creating and manipulating engines.
                        * An engine is a controller that manages updating the simulation of the world.
                        * See `Matter.Runner` for an optional game loop utility.
                        *
                        * See the included usage [examples](https://github.com/liabru/matter-js/tree/master/examples).
                        *
                        * @class Engine
                        */
                        
                        var Engine = {};
                        
                        module.exports = Engine;
                        
                        var World = require('../body/World');
                        var Sleeping = require('./Sleeping');
                        var Resolver = require('../collision/Resolver');
                        var Render = require('../render/Render');
                        var Pairs = require('../collision/Pairs');
                        var Metrics = require('./Metrics');
                        var Grid = require('../collision/Grid');
                        var Events = require('./Events');
                        var Composite = require('../body/Composite');
                        var Constraint = require('../constraint/Constraint');
                        var Common = require('./Common');
                        var Body = require('../body/Body');
                        
                        (function() {
                        
                            /**
                             * Creates a new engine. 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.
                             * See the properties section below for detailed information on what you can pass via the `options` object.
                             * @method create
                             * @param {object} [options]
                             * @return {engine} engine
                             */
                            Engine.create = function(element, options) {
                                // options may be passed as the first (and only) argument
                                options = Common.isElement(element) ? options : element;
                                element = Common.isElement(element) ? element : null;
                                options = options || {};
                        
                                if (element || options.render) {
                                    Common.warn('Engine.create: engine.render is deprecated (see docs)');
                                }
                        
                                var defaults = {
                                    positionIterations: 6,
                                    velocityIterations: 4,
                                    constraintIterations: 2,
                                    enableSleeping: false,
                                    events: [],
                                    plugin: {},
                                    timing: {
                                        timestamp: 0,
                                        timeScale: 1
                                    },
                                    broadphase: {
                                        controller: Grid
                                    }
                                };
                        
                                var engine = Common.extend(defaults, options);
                        
                                // @deprecated
                                if (element || engine.render) {
                                    var renderDefaults = {
                                        element: element,
                                        controller: Render
                                    };
                                    
                                    engine.render = Common.extend(renderDefaults, engine.render);
                                }
                        
                                // @deprecated
                                if (engine.render && engine.render.controller) {
                                    engine.render = engine.render.controller.create(engine.render);
                                }
                        
                                // @deprecated
                                if (engine.render) {
                                    engine.render.engine = engine;
                                }
                        
                                engine.world = options.world || World.create(engine.world);
                                engine.pairs = Pairs.create();
                                engine.broadphase = engine.broadphase.controller.create(engine.broadphase);
                                engine.metrics = engine.metrics || { extended: false };
                        
                                // @if DEBUG
                                engine.metrics = Metrics.create(engine.metrics);
                                // @endif
                        
                                return engine;
                            };
                        
                            /**
                             * Moves the simulation forward in time by `delta` ms.
                             * The `correction` argument is an optional `Number` that specifies the time correction factor to apply to the update.
                             * This can help improve the accuracy of the simulation in cases where `delta` is changing between updates.
                             * The value of `correction` is defined as `delta / lastDelta`, i.e. the percentage change of `delta` over the last step.
                             * Therefore the value is always `1` (no correction) when `delta` constant (or when no correction is desired, which is the default).
                             * See the paper on <a href="http://lonesock.net/article/verlet.html">Time Corrected Verlet</a> for more information.
                             *
                             * Triggers `beforeUpdate` and `afterUpdate` events.
                             * Triggers `collisionStart`, `collisionActive` and `collisionEnd` events.
                             * @method update
                             * @param {engine} engine
                             * @param {number} [delta=16.666]
                             * @param {number} [correction=1]
                             */
                            Engine.update = function(engine, delta, correction) {
                                delta = delta || 1000 / 60;
                                correction = correction || 1;
                        
                                var world = engine.world,
                                    timing = engine.timing,
                                    broadphase = engine.broadphase,
                                    broadphasePairs = [],
                                    i;
                        
                                // increment timestamp
                                timing.timestamp += delta * timing.timeScale;
                        
                                // create an event object
                                var event = {
                                    timestamp: timing.timestamp
                                };
                        
                                Events.trigger(engine, 'beforeUpdate', event);
                        
                                // get lists of all bodies and constraints, no matter what composites they are in
                                var allBodies = Composite.allBodies(world),
                                    allConstraints = Composite.allConstraints(world);
                        
                                // @if DEBUG
                                // reset metrics logging
                                Metrics.reset(engine.metrics);
                                // @endif
                        
                                // if sleeping enabled, call the sleeping controller
                                if (engine.enableSleeping)
                                    Sleeping.update(allBodies, timing.timeScale);
                        
                                // applies gravity to all bodies
                                Engine._bodiesApplyGravity(allBodies, world.gravity);
                        
                                // update all body position and rotation by integration
                                Engine._bodiesUpdate(allBodies, delta, timing.timeScale, correction, world.bounds);
                        
                                // update all constraints (first pass)
                                Constraint.preSolveAll(allBodies);
                                for (i = 0; i < engine.constraintIterations; i++) {
                                    Constraint.solveAll(allConstraints, timing.timeScale);
                                }
                                Constraint.postSolveAll(allBodies);
                        
                                // broadphase pass: find potential collision pairs
                                if (broadphase.controller) {
                                    // if world is dirty, we must flush the whole grid
                                    if (world.isModified)
                                        broadphase.controller.clear(broadphase);
                        
                                    // update the grid buckets based on current bodies
                                    broadphase.controller.update(broadphase, allBodies, engine, world.isModified);
                                    broadphasePairs = broadphase.pairsList;
                                } else {
                                    // if no broadphase set, we just pass all bodies
                                    broadphasePairs = allBodies;
                                }
                        
                                // clear all composite modified flags
                                if (world.isModified) {
                                    Composite.setModified(world, false, false, true);
                                }
                        
                                // narrowphase pass: find actual collisions, then create or update collision pairs
                                var collisions = broadphase.detector(broadphasePairs, engine);
                        
                                // update collision pairs
                                var pairs = engine.pairs,
                                    timestamp = timing.timestamp;
                                Pairs.update(pairs, collisions, timestamp);
                                Pairs.removeOld(pairs, timestamp);
                        
                                // wake up bodies involved in collisions
                                if (engine.enableSleeping)
                                    Sleeping.afterCollisions(pairs.list, timing.timeScale);
                        
                                // trigger collision events
                                if (pairs.collisionStart.length > 0)
                                    Events.trigger(engine, 'collisionStart', { pairs: pairs.collisionStart });
                        
                                // iteratively resolve position between collisions
                                Resolver.preSolvePosition(pairs.list);
                                for (i = 0; i < engine.positionIterations; i++) {
                                    Resolver.solvePosition(pairs.list, timing.timeScale);
                                }
                                Resolver.postSolvePosition(allBodies);
                        
                                // update all constraints (second pass)
                                Constraint.preSolveAll(allBodies);
                                for (i = 0; i < engine.constraintIterations; i++) {
                                    Constraint.solveAll(allConstraints, timing.timeScale);
                                }
                                Constraint.postSolveAll(allBodies);
                        
                                // iteratively resolve velocity between collisions
                                Resolver.preSolveVelocity(pairs.list);
                                for (i = 0; i < engine.velocityIterations; i++) {
                                    Resolver.solveVelocity(pairs.list, timing.timeScale);
                                }
                        
                                // trigger collision events
                                if (pairs.collisionActive.length > 0)
                                    Events.trigger(engine, 'collisionActive', { pairs: pairs.collisionActive });
                        
                                if (pairs.collisionEnd.length > 0)
                                    Events.trigger(engine, 'collisionEnd', { pairs: pairs.collisionEnd });
                        
                                // @if DEBUG
                                // update metrics log
                                Metrics.update(engine.metrics, engine);
                                // @endif
                        
                                // clear force buffers
                                Engine._bodiesClearForces(allBodies);
                        
                                Events.trigger(engine, 'afterUpdate', event);
                        
                                return engine;
                            };
                            
                            /**
                             * Merges two engines by keeping the configuration of `engineA` but replacing the world with the one from `engineB`.
                             * @method merge
                             * @param {engine} engineA
                             * @param {engine} engineB
                             */
                            Engine.merge = function(engineA, engineB) {
                                Common.extend(engineA, engineB);
                                
                                if (engineB.world) {
                                    engineA.world = engineB.world;
                        
                                    Engine.clear(engineA);
                        
                                    var bodies = Composite.allBodies(engineA.world);
                        
                                    for (var i = 0; i < bodies.length; i++) {
                                        var body = bodies[i];
                                        Sleeping.set(body, false);
                                        body.id = Common.nextId();
                                    }
                                }
                            };
                        
                            /**
                             * Clears the engine including the world, pairs and broadphase.
                             * @method clear
                             * @param {engine} engine
                             */
                            Engine.clear = function(engine) {
                                var world = engine.world;
                                
                                Pairs.clear(engine.pairs);
                        
                                var broadphase = engine.broadphase;
                                if (broadphase.controller) {
                                    var bodies = Composite.allBodies(world);
                                    broadphase.controller.clear(broadphase);
                                    broadphase.controller.update(broadphase, bodies, engine, true);
                                }
                            };
                        
                            /**
                             * Zeroes the `body.force` and `body.torque` force buffers.
                             * @method _bodiesClearForces
                             * @private
                             * @param {body[]} bodies
                             */
                            Engine._bodiesClearForces = function(bodies) {
                                for (var i = 0; i < bodies.length; i++) {
                                    var body = bodies[i];
                        
                                    // reset force buffers
                                    body.force.x = 0;
                                    body.force.y = 0;
                                    body.torque = 0;
                                }
                            };
                        
                            /**
                             * Applys a mass dependant force to all given bodies.
                             * @method _bodiesApplyGravity
                             * @private
                             * @param {body[]} bodies
                             * @param {vector} gravity
                             */
                            Engine._bodiesApplyGravity = function(bodies, gravity) {
                                var gravityScale = typeof gravity.scale !== 'undefined' ? gravity.scale : 0.001;
                        
                                if ((gravity.x === 0 && gravity.y === 0) || gravityScale === 0) {
                                    return;
                                }
                                
                                for (var i = 0; i < bodies.length; i++) {
                                    var body = bodies[i];
                        
                                    if (body.isStatic || body.isSleeping)
                                        continue;
                        
                                    // apply gravity
                                    body.force.y += body.mass * gravity.y * gravityScale;
                                    body.force.x += body.mass * gravity.x * gravityScale;
                                }
                            };
                        
                            /**
                             * Applys `Body.update` to all given `bodies`.
                             * @method _bodiesUpdate
                             * @private
                             * @param {body[]} bodies
                             * @param {number} deltaTime 
                             * The amount of time elapsed between updates
                             * @param {number} timeScale
                             * @param {number} correction 
                             * The Verlet correction factor (deltaTime / lastDeltaTime)
                             * @param {bounds} worldBounds
                             */
                            Engine._bodiesUpdate = function(bodies, deltaTime, timeScale, correction, worldBounds) {
                                for (var i = 0; i < bodies.length; i++) {
                                    var body = bodies[i];
                        
                                    if (body.isStatic || body.isSleeping)
                                        continue;
                        
                                    Body.update(body, deltaTime, timeScale, correction);
                                }
                            };
                        
                            /**
                             * An alias for `Runner.run`, see `Matter.Runner` for more information.
                             * @method run
                             * @param {engine} engine
                             */
                        
                            /**
                            * Fired just before an update
                            *
                            * @event beforeUpdate
                            * @param {} event An event object
                            * @param {number} event.timestamp The engine.timing.timestamp of the event
                            * @param {} event.source The source object of the event
                            * @param {} event.name The name of the event
                            */
                        
                            /**
                            * Fired after engine update and all collision events
                            *
                            * @event afterUpdate
                            * @param {} event An event object
                            * @param {number} event.timestamp The engine.timing.timestamp of the event
                            * @param {} event.source The source object of the event
                            * @param {} event.name The name of the event
                            */
                        
                            /**
                            * Fired after engine update, provides a list of all pairs that have started to collide in the current tick (if any)
                            *
                            * @event collisionStart
                            * @param {} event An event object
                            * @param {} event.pairs List of affected pairs
                            * @param {number} event.timestamp The engine.timing.timestamp of the event
                            * @param {} event.source The source object of the event
                            * @param {} event.name The name of the event
                            */
                        
                            /**
                            * Fired after engine update, provides a list of all pairs that are colliding in the current tick (if any)
                            *
                            * @event collisionActive
                            * @param {} event An event object
                            * @param {} event.pairs List of affected pairs
                            * @param {number} event.timestamp The engine.timing.timestamp of the event
                            * @param {} event.source The source object of the event
                            * @param {} event.name The name of the event
                            */
                        
                            /**
                            * Fired after engine update, provides a list of all pairs that have ended collision in the current tick (if any)
                            *
                            * @event collisionEnd
                            * @param {} event An event object
                            * @param {} event.pairs List of affected pairs
                            * @param {number} event.timestamp The engine.timing.timestamp of the event
                            * @param {} event.source The source object of the event
                            * @param {} event.name The name of the event
                            */
                        
                            /*
                            *
                            *  Properties Documentation
                            *
                            */
                        
                            /**
                             * An integer `Number` that specifies the number of position iterations to perform each update.
                             * The higher the value, the higher quality the simulation will be at the expense of performance.
                             *
                             * @property positionIterations
                             * @type number
                             * @default 6
                             */
                        
                            /**
                             * An integer `Number` that specifies the number of velocity iterations to perform each update.
                             * The higher the value, the higher quality the simulation will be at the expense of performance.
                             *
                             * @property velocityIterations
                             * @type number
                             * @default 4
                             */
                        
                            /**
                             * An integer `Number` that specifies the number of constraint iterations to perform each update.
                             * The higher the value, the higher quality the simulation will be at the expense of performance.
                             * The default value of `2` is usually very adequate.
                             *
                             * @property constraintIterations
                             * @type number
                             * @default 2
                             */
                        
                            /**
                             * A flag that specifies whether the engine should allow sleeping via the `Matter.Sleeping` module.
                             * Sleeping can improve stability and performance, but often at the expense of accuracy.
                             *
                             * @property enableSleeping
                             * @type boolean
                             * @default false
                             */
                        
                            /**
                             * An `Object` containing properties regarding the timing systems of the engine. 
                             *
                             * @property timing
                             * @type object
                             */
                        
                            /**
                             * A `Number` that specifies the global scaling factor of time for all bodies.
                             * A value of `0` freezes the simulation.
                             * A value of `0.1` gives a slow-motion effect.
                             * A value of `1.2` gives a speed-up effect.
                             *
                             * @property timing.timeScale
                             * @type number
                             * @default 1
                             */
                        
                            /**
                             * A `Number` that specifies the current simulation-time in milliseconds starting from `0`. 
                             * It is incremented on every `Engine.update` by the given `delta` argument. 
                             *
                             * @property timing.timestamp
                             * @type number
                             * @default 0
                             */
                        
                            /**
                             * An instance of a `Render` controller. The default value is a `Matter.Render` instance created by `Engine.create`.
                             * One may also develop a custom renderer module based on `Matter.Render` and pass an instance of it to `Engine.create` via `options.render`.
                             *
                             * A minimal custom renderer object must define at least three functions: `create`, `clear` and `world` (see `Matter.Render`).
                             * It is also possible to instead pass the _module_ reference via `options.render.controller` and `Engine.create` will instantiate one for you.
                             *
                             * @property render
                             * @type render
                             * @deprecated see Demo.js for an example of creating a renderer
                             * @default a Matter.Render instance
                             */
                        
                            /**
                             * An instance of a broadphase controller. The default value is a `Matter.Grid` instance created by `Engine.create`.
                             *
                             * @property broadphase
                             * @type grid
                             * @default a Matter.Grid instance
                             */
                        
                            /**
                             * A `World` composite object that will contain all simulated bodies and constraints.
                             *
                             * @property world
                             * @type world
                             * @default a Matter.World instance
                             */
                        
                            /**
                             * An object reserved for storing plugin-specific properties.
                             *
                             * @property plugin
                             * @type {}
                             */
                        
                        })();
                        
                            
0.14.2