From 2b5819c0682ca3de62fb248f8144bf08ea4dc599 Mon Sep 17 00:00:00 2001 From: liabru Date: Sat, 22 Jun 2024 18:59:48 +0100 Subject: [PATCH] remove alpha build --- build/matter.alpha.js | 11372 ------------------------------------ build/matter.alpha.min.js | 7 - 2 files changed, 11379 deletions(-) delete mode 100644 build/matter.alpha.js delete mode 100644 build/matter.alpha.min.js diff --git a/build/matter.alpha.js b/build/matter.alpha.js deleted file mode 100644 index 5869e93..0000000 --- a/build/matter.alpha.js +++ /dev/null @@ -1,11372 +0,0 @@ -/*! - * matter-js 0.19.0-alpha+205aaa5 by @liabru - * Experimental pre-release build. - * http://brm.io/matter-js/ - * License MIT - * - * The MIT License (MIT) - * - * Copyright (c) Liam Brummitt and contributors. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -(function webpackUniversalModuleDefinition(root, factory) { - if(typeof exports === 'object' && typeof module === 'object') - module.exports = factory(); - else if(typeof define === 'function' && define.amd) - define("Matter", [], factory); - else if(typeof exports === 'object') - exports["Matter"] = factory(); - else - root["Matter"] = factory(); -})(this, function() { -return /******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) { -/******/ return installedModules[moduleId].exports; -/******/ } -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ -/******/ // Flag the module as loaded -/******/ module.l = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/******/ -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; -/******/ -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; -/******/ -/******/ // define getter function for harmony exports -/******/ __webpack_require__.d = function(exports, name, getter) { -/******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); -/******/ } -/******/ }; -/******/ -/******/ // define __esModule on exports -/******/ __webpack_require__.r = function(exports) { -/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { -/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); -/******/ } -/******/ Object.defineProperty(exports, '__esModule', { value: true }); -/******/ }; -/******/ -/******/ // create a fake namespace object -/******/ // mode & 1: value is a module id, require it -/******/ // mode & 2: merge all properties of value into the ns -/******/ // mode & 4: return value when already ns object -/******/ // mode & 8|1: behave like require -/******/ __webpack_require__.t = function(value, mode) { -/******/ if(mode & 1) value = __webpack_require__(value); -/******/ if(mode & 8) return value; -/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; -/******/ var ns = Object.create(null); -/******/ __webpack_require__.r(ns); -/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); -/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); -/******/ return ns; -/******/ }; -/******/ -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __webpack_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ -/******/ // Object.prototype.hasOwnProperty.call -/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; -/******/ -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; -/******/ -/******/ -/******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 20); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ (function(module, exports) { - -/** -* The `Matter.Common` module contains utility functions that are common to all modules. -* -* @class Common -*/ - -var Common = {}; - -module.exports = Common; - -(function() { - - Common._baseDelta = 1000 / 60; - Common._nextId = 0; - Common._seed = 0; - Common._nowStartTime = +(new Date()); - Common._warnedOnce = {}; - Common._decomp = null; - - /** - * Extends the object in the first argument using the object in the second argument. - * @method extend - * @param {} obj - * @param {boolean} deep - * @return {} obj extended - */ - Common.extend = function(obj, deep) { - var argsStart, - args, - deepClone; - - if (typeof deep === 'boolean') { - argsStart = 2; - deepClone = deep; - } else { - argsStart = 1; - deepClone = true; - } - - for (var i = argsStart; i < arguments.length; i++) { - var source = arguments[i]; - - if (source) { - for (var prop in source) { - if (deepClone && source[prop] && source[prop].constructor === Object) { - if (!obj[prop] || obj[prop].constructor === Object) { - obj[prop] = obj[prop] || {}; - Common.extend(obj[prop], deepClone, source[prop]); - } else { - obj[prop] = source[prop]; - } - } else { - obj[prop] = source[prop]; - } - } - } - } - - return obj; - }; - - /** - * Creates a new clone of the object, if deep is true references will also be cloned. - * @method clone - * @param {} obj - * @param {bool} deep - * @return {} obj cloned - */ - Common.clone = function(obj, deep) { - return Common.extend({}, deep, obj); - }; - - /** - * Returns the list of keys for the given object. - * @method keys - * @param {} obj - * @return {string[]} keys - */ - Common.keys = function(obj) { - if (Object.keys) - return Object.keys(obj); - - // avoid hasOwnProperty for performance - var keys = []; - for (var key in obj) - keys.push(key); - return keys; - }; - - /** - * Returns the list of values for the given object. - * @method values - * @param {} obj - * @return {array} Array of the objects property values - */ - Common.values = function(obj) { - var values = []; - - if (Object.keys) { - var keys = Object.keys(obj); - for (var i = 0; i < keys.length; i++) { - values.push(obj[keys[i]]); - } - return values; - } - - // avoid hasOwnProperty for performance - for (var key in obj) - values.push(obj[key]); - return values; - }; - - /** - * Gets a value from `base` relative to the `path` string. - * @method get - * @param {} obj The base object - * @param {string} path The path relative to `base`, e.g. 'Foo.Bar.baz' - * @param {number} [begin] Path slice begin - * @param {number} [end] Path slice end - * @return {} The object at the given path - */ - Common.get = function(obj, path, begin, end) { - path = path.split('.').slice(begin, end); - - for (var i = 0; i < path.length; i += 1) { - obj = obj[path[i]]; - } - - return obj; - }; - - /** - * Sets a value on `base` relative to the given `path` string. - * @method set - * @param {} obj The base object - * @param {string} path The path relative to `base`, e.g. 'Foo.Bar.baz' - * @param {} val The value to set - * @param {number} [begin] Path slice begin - * @param {number} [end] Path slice end - * @return {} Pass through `val` for chaining - */ - Common.set = function(obj, path, val, begin, end) { - var parts = path.split('.').slice(begin, end); - Common.get(obj, path, 0, -1)[parts[parts.length - 1]] = val; - return val; - }; - - /** - * Shuffles the given array in-place. - * The function uses a seeded random generator. - * @method shuffle - * @param {array} array - * @return {array} array shuffled randomly - */ - Common.shuffle = function(array) { - for (var i = array.length - 1; i > 0; i--) { - var j = Math.floor(Common.random() * (i + 1)); - var temp = array[i]; - array[i] = array[j]; - array[j] = temp; - } - return array; - }; - - /** - * Randomly chooses a value from a list with equal probability. - * The function uses a seeded random generator. - * @method choose - * @param {array} choices - * @return {object} A random choice object from the array - */ - Common.choose = function(choices) { - return choices[Math.floor(Common.random() * choices.length)]; - }; - - /** - * Returns true if the object is a HTMLElement, otherwise false. - * @method isElement - * @param {object} obj - * @return {boolean} True if the object is a HTMLElement, otherwise false - */ - Common.isElement = function(obj) { - if (typeof HTMLElement !== 'undefined') { - return obj instanceof HTMLElement; - } - - return !!(obj && obj.nodeType && obj.nodeName); - }; - - /** - * Returns true if the object is an array. - * @method isArray - * @param {object} obj - * @return {boolean} True if the object is an array, otherwise false - */ - Common.isArray = function(obj) { - return Object.prototype.toString.call(obj) === '[object Array]'; - }; - - /** - * Returns true if the object is a function. - * @method isFunction - * @param {object} obj - * @return {boolean} True if the object is a function, otherwise false - */ - Common.isFunction = function(obj) { - return typeof obj === "function"; - }; - - /** - * Returns true if the object is a plain object. - * @method isPlainObject - * @param {object} obj - * @return {boolean} True if the object is a plain object, otherwise false - */ - Common.isPlainObject = function(obj) { - return typeof obj === 'object' && obj.constructor === Object; - }; - - /** - * Returns true if the object is a string. - * @method isString - * @param {object} obj - * @return {boolean} True if the object is a string, otherwise false - */ - Common.isString = function(obj) { - return toString.call(obj) === '[object String]'; - }; - - /** - * Returns the given value clamped between a minimum and maximum value. - * @method clamp - * @param {number} value - * @param {number} min - * @param {number} max - * @return {number} The value clamped between min and max inclusive - */ - Common.clamp = function(value, min, max) { - if (value < min) - return min; - if (value > max) - return max; - return value; - }; - - /** - * Returns the sign of the given value. - * @method sign - * @param {number} value - * @return {number} -1 if negative, +1 if 0 or positive - */ - Common.sign = function(value) { - return value < 0 ? -1 : 1; - }; - - /** - * Returns the current timestamp since the time origin (e.g. from page load). - * The result is in milliseconds and will use high-resolution timing if available. - * @method now - * @return {number} the current timestamp in milliseconds - */ - Common.now = function() { - if (typeof window !== 'undefined' && window.performance) { - if (window.performance.now) { - return window.performance.now(); - } else if (window.performance.webkitNow) { - return window.performance.webkitNow(); - } - } - - if (Date.now) { - return Date.now(); - } - - return (new Date()) - Common._nowStartTime; - }; - - /** - * Returns a random value between a minimum and a maximum value inclusive. - * The function uses a seeded random generator. - * @method random - * @param {number} min - * @param {number} max - * @return {number} A random number between min and max inclusive - */ - Common.random = function(min, max) { - min = (typeof min !== "undefined") ? min : 0; - max = (typeof max !== "undefined") ? max : 1; - return min + _seededRandom() * (max - min); - }; - - var _seededRandom = function() { - // https://en.wikipedia.org/wiki/Linear_congruential_generator - Common._seed = (Common._seed * 9301 + 49297) % 233280; - return Common._seed / 233280; - }; - - /** - * Converts a CSS hex colour string into an integer. - * @method colorToNumber - * @param {string} colorString - * @return {number} An integer representing the CSS hex string - */ - Common.colorToNumber = function(colorString) { - colorString = colorString.replace('#',''); - - if (colorString.length == 3) { - colorString = colorString.charAt(0) + colorString.charAt(0) - + colorString.charAt(1) + colorString.charAt(1) - + colorString.charAt(2) + colorString.charAt(2); - } - - return parseInt(colorString, 16); - }; - - /** - * The console logging level to use, where each level includes all levels above and excludes the levels below. - * The default level is 'debug' which shows all console messages. - * - * Possible level values are: - * - 0 = None - * - 1 = Debug - * - 2 = Info - * - 3 = Warn - * - 4 = Error - * @static - * @property logLevel - * @type {Number} - * @default 1 - */ - Common.logLevel = 1; - - /** - * Shows a `console.log` message only if the current `Common.logLevel` allows it. - * The message will be prefixed with 'matter-js' to make it easily identifiable. - * @method log - * @param ...objs {} The objects to log. - */ - Common.log = function() { - if (console && Common.logLevel > 0 && Common.logLevel <= 3) { - console.log.apply(console, ['matter-js:'].concat(Array.prototype.slice.call(arguments))); - } - }; - - /** - * Shows a `console.info` message only if the current `Common.logLevel` allows it. - * The message will be prefixed with 'matter-js' to make it easily identifiable. - * @method info - * @param ...objs {} The objects to log. - */ - Common.info = function() { - if (console && Common.logLevel > 0 && Common.logLevel <= 2) { - console.info.apply(console, ['matter-js:'].concat(Array.prototype.slice.call(arguments))); - } - }; - - /** - * Shows a `console.warn` message only if the current `Common.logLevel` allows it. - * The message will be prefixed with 'matter-js' to make it easily identifiable. - * @method warn - * @param ...objs {} The objects to log. - */ - Common.warn = function() { - if (console && Common.logLevel > 0 && Common.logLevel <= 3) { - console.warn.apply(console, ['matter-js:'].concat(Array.prototype.slice.call(arguments))); - } - }; - - /** - * Uses `Common.warn` to log the given message one time only. - * @method warnOnce - * @param ...objs {} The objects to log. - */ - Common.warnOnce = function() { - var message = Array.prototype.slice.call(arguments).join(' '); - - if (!Common._warnedOnce[message]) { - Common.warn(message); - Common._warnedOnce[message] = true; - } - }; - - /** - * Shows a deprecated console warning when the function on the given object is called. - * The target function will be replaced with a new function that first shows the warning - * and then calls the original function. - * @method deprecated - * @param {object} obj The object or module - * @param {string} name The property name of the function on obj - * @param {string} warning The one-time message to show if the function is called - */ - Common.deprecated = function(obj, prop, warning) { - obj[prop] = Common.chain(function() { - Common.warnOnce('🔅 deprecated 🔅', warning); - }, obj[prop]); - }; - - /** - * Returns the next unique sequential ID. - * @method nextId - * @return {Number} Unique sequential ID - */ - Common.nextId = function() { - return Common._nextId++; - }; - - /** - * A cross browser compatible indexOf implementation. - * @method indexOf - * @param {array} haystack - * @param {object} needle - * @return {number} The position of needle in haystack, otherwise -1. - */ - Common.indexOf = function(haystack, needle) { - if (haystack.indexOf) - return haystack.indexOf(needle); - - for (var i = 0; i < haystack.length; i++) { - if (haystack[i] === needle) - return i; - } - - return -1; - }; - - /** - * A cross browser compatible array map implementation. - * @method map - * @param {array} list - * @param {function} func - * @return {array} Values from list transformed by func. - */ - Common.map = function(list, func) { - if (list.map) { - return list.map(func); - } - - var mapped = []; - - for (var i = 0; i < list.length; i += 1) { - mapped.push(func(list[i])); - } - - return mapped; - }; - - /** - * Takes a directed graph and returns the partially ordered set of vertices in topological order. - * Circular dependencies are allowed. - * @method topologicalSort - * @param {object} graph - * @return {array} Partially ordered set of vertices in topological order. - */ - Common.topologicalSort = function(graph) { - // https://github.com/mgechev/javascript-algorithms - // Copyright (c) Minko Gechev (MIT license) - // Modifications: tidy formatting and naming - var result = [], - visited = [], - temp = []; - - for (var node in graph) { - if (!visited[node] && !temp[node]) { - Common._topologicalSort(node, visited, temp, graph, result); - } - } - - return result; - }; - - Common._topologicalSort = function(node, visited, temp, graph, result) { - var neighbors = graph[node] || []; - temp[node] = true; - - for (var i = 0; i < neighbors.length; i += 1) { - var neighbor = neighbors[i]; - - if (temp[neighbor]) { - // skip circular dependencies - continue; - } - - if (!visited[neighbor]) { - Common._topologicalSort(neighbor, visited, temp, graph, result); - } - } - - temp[node] = false; - visited[node] = true; - - result.push(node); - }; - - /** - * Takes _n_ functions as arguments and returns a new function that calls them in order. - * The arguments applied when calling the new function will also be applied to every function passed. - * The value of `this` refers to the last value returned in the chain that was not `undefined`. - * Therefore if a passed function does not return a value, the previously returned value is maintained. - * After all passed functions have been called the new function returns the last returned value (if any). - * If any of the passed functions are a chain, then the chain will be flattened. - * @method chain - * @param ...funcs {function} The functions to chain. - * @return {function} A new function that calls the passed functions in order. - */ - Common.chain = function() { - var funcs = []; - - for (var i = 0; i < arguments.length; i += 1) { - var func = arguments[i]; - - if (func._chained) { - // flatten already chained functions - funcs.push.apply(funcs, func._chained); - } else { - funcs.push(func); - } - } - - var chain = function() { - // https://github.com/GoogleChrome/devtools-docs/issues/53#issuecomment-51941358 - var lastResult, - args = new Array(arguments.length); - - for (var i = 0, l = arguments.length; i < l; i++) { - args[i] = arguments[i]; - } - - for (i = 0; i < funcs.length; i += 1) { - var result = funcs[i].apply(lastResult, args); - - if (typeof result !== 'undefined') { - lastResult = result; - } - } - - return lastResult; - }; - - chain._chained = funcs; - - return chain; - }; - - /** - * Chains a function to excute before the original function on the given `path` relative to `base`. - * See also docs for `Common.chain`. - * @method chainPathBefore - * @param {} base The base object - * @param {string} path The path relative to `base` - * @param {function} func The function to chain before the original - * @return {function} The chained function that replaced the original - */ - Common.chainPathBefore = function(base, path, func) { - return Common.set(base, path, Common.chain( - func, - Common.get(base, path) - )); - }; - - /** - * Chains a function to excute after the original function on the given `path` relative to `base`. - * See also docs for `Common.chain`. - * @method chainPathAfter - * @param {} base The base object - * @param {string} path The path relative to `base` - * @param {function} func The function to chain after the original - * @return {function} The chained function that replaced the original - */ - Common.chainPathAfter = function(base, path, func) { - return Common.set(base, path, Common.chain( - Common.get(base, path), - func - )); - }; - - /** - * Provide the [poly-decomp](https://github.com/schteppe/poly-decomp.js) library module to enable - * concave vertex decomposition support when using `Bodies.fromVertices` e.g. `Common.setDecomp(require('poly-decomp'))`. - * @method setDecomp - * @param {} decomp The [poly-decomp](https://github.com/schteppe/poly-decomp.js) library module. - */ - Common.setDecomp = function(decomp) { - Common._decomp = decomp; - }; - - /** - * Returns the [poly-decomp](https://github.com/schteppe/poly-decomp.js) library module provided through `Common.setDecomp`, - * otherwise returns the global `decomp` if set. - * @method getDecomp - * @return {} The [poly-decomp](https://github.com/schteppe/poly-decomp.js) library module if provided. - */ - Common.getDecomp = function() { - // get user provided decomp if set - var decomp = Common._decomp; - - try { - // otherwise from window global - if (!decomp && typeof window !== 'undefined') { - decomp = window.decomp; - } - - // otherwise from node global - if (!decomp && typeof global !== 'undefined') { - decomp = global.decomp; - } - } catch (e) { - // decomp not available - decomp = null; - } - - return decomp; - }; -})(); - - -/***/ }), -/* 1 */ -/***/ (function(module, exports) { - -/** -* The `Matter.Bounds` module contains methods for creating and manipulating axis-aligned bounding boxes (AABB). -* -* @class Bounds -*/ - -var Bounds = {}; - -module.exports = Bounds; - -(function() { - - /** - * Creates a new axis-aligned bounding box (AABB) for the given vertices. - * @method create - * @param {vertices} vertices - * @return {bounds} A new bounds object - */ - Bounds.create = function(vertices) { - var bounds = { - min: { x: 0, y: 0 }, - max: { x: 0, y: 0 } - }; - - if (vertices) - Bounds.update(bounds, vertices); - - return bounds; - }; - - /** - * Updates bounds using the given vertices and extends the bounds given a velocity. - * @method update - * @param {bounds} bounds - * @param {vertices} vertices - * @param {vector} velocity - */ - Bounds.update = function(bounds, vertices, velocity) { - bounds.min.x = Infinity; - bounds.max.x = -Infinity; - bounds.min.y = Infinity; - bounds.max.y = -Infinity; - - for (var i = 0; i < vertices.length; i++) { - var vertex = vertices[i]; - if (vertex.x > bounds.max.x) bounds.max.x = vertex.x; - if (vertex.x < bounds.min.x) bounds.min.x = vertex.x; - if (vertex.y > bounds.max.y) bounds.max.y = vertex.y; - if (vertex.y < bounds.min.y) bounds.min.y = vertex.y; - } - - if (velocity) { - if (velocity.x > 0) { - bounds.max.x += velocity.x; - } else { - bounds.min.x += velocity.x; - } - - if (velocity.y > 0) { - bounds.max.y += velocity.y; - } else { - bounds.min.y += velocity.y; - } - } - }; - - /** - * Returns true if the bounds contains the given point. - * @method contains - * @param {bounds} bounds - * @param {vector} point - * @return {boolean} True if the bounds contain the point, otherwise false - */ - Bounds.contains = function(bounds, point) { - return point.x >= bounds.min.x && point.x <= bounds.max.x - && point.y >= bounds.min.y && point.y <= bounds.max.y; - }; - - /** - * Returns true if the two bounds intersect. - * @method overlaps - * @param {bounds} boundsA - * @param {bounds} boundsB - * @return {boolean} True if the bounds overlap, otherwise false - */ - Bounds.overlaps = function(boundsA, boundsB) { - return (boundsA.min.x <= boundsB.max.x && boundsA.max.x >= boundsB.min.x - && boundsA.max.y >= boundsB.min.y && boundsA.min.y <= boundsB.max.y); - }; - - /** - * Translates the bounds by the given vector. - * @method translate - * @param {bounds} bounds - * @param {vector} vector - */ - Bounds.translate = function(bounds, vector) { - bounds.min.x += vector.x; - bounds.max.x += vector.x; - bounds.min.y += vector.y; - bounds.max.y += vector.y; - }; - - /** - * Shifts the bounds to the given position. - * @method shift - * @param {bounds} bounds - * @param {vector} position - */ - Bounds.shift = function(bounds, position) { - var deltaX = bounds.max.x - bounds.min.x, - deltaY = bounds.max.y - bounds.min.y; - - bounds.min.x = position.x; - bounds.max.x = position.x + deltaX; - bounds.min.y = position.y; - bounds.max.y = position.y + deltaY; - }; - -})(); - - -/***/ }), -/* 2 */ -/***/ (function(module, exports) { - -/** -* The `Matter.Vector` module contains methods for creating and manipulating vectors. -* Vectors are the basis of all the geometry related operations in the engine. -* A `Matter.Vector` object is of the form `{ x: 0, y: 0 }`. -* -* See the included usage [examples](https://github.com/liabru/matter-js/tree/master/examples). -* -* @class Vector -*/ - -// TODO: consider params for reusing vector objects - -var Vector = {}; - -module.exports = Vector; - -(function() { - - /** - * Creates a new vector. - * @method create - * @param {number} x - * @param {number} y - * @return {vector} A new vector - */ - Vector.create = function(x, y) { - return { x: x || 0, y: y || 0 }; - }; - - /** - * Returns a new vector with `x` and `y` copied from the given `vector`. - * @method clone - * @param {vector} vector - * @return {vector} A new cloned vector - */ - Vector.clone = function(vector) { - return { x: vector.x, y: vector.y }; - }; - - /** - * Returns the magnitude (length) of a vector. - * @method magnitude - * @param {vector} vector - * @return {number} The magnitude of the vector - */ - Vector.magnitude = function(vector) { - return Math.sqrt((vector.x * vector.x) + (vector.y * vector.y)); - }; - - /** - * Returns the magnitude (length) of a vector (therefore saving a `sqrt` operation). - * @method magnitudeSquared - * @param {vector} vector - * @return {number} The squared magnitude of the vector - */ - Vector.magnitudeSquared = function(vector) { - return (vector.x * vector.x) + (vector.y * vector.y); - }; - - /** - * Rotates the vector about (0, 0) by specified angle. - * @method rotate - * @param {vector} vector - * @param {number} angle - * @param {vector} [output] - * @return {vector} The vector rotated about (0, 0) - */ - Vector.rotate = function(vector, angle, output) { - var cos = Math.cos(angle), sin = Math.sin(angle); - if (!output) output = {}; - var x = vector.x * cos - vector.y * sin; - output.y = vector.x * sin + vector.y * cos; - output.x = x; - return output; - }; - - /** - * Rotates the vector about a specified point by specified angle. - * @method rotateAbout - * @param {vector} vector - * @param {number} angle - * @param {vector} point - * @param {vector} [output] - * @return {vector} A new vector rotated about the point - */ - Vector.rotateAbout = function(vector, angle, point, output) { - var cos = Math.cos(angle), sin = Math.sin(angle); - if (!output) output = {}; - var x = point.x + ((vector.x - point.x) * cos - (vector.y - point.y) * sin); - output.y = point.y + ((vector.x - point.x) * sin + (vector.y - point.y) * cos); - output.x = x; - return output; - }; - - /** - * Normalises a vector (such that its magnitude is `1`). - * @method normalise - * @param {vector} vector - * @return {vector} A new vector normalised - */ - Vector.normalise = function(vector) { - var magnitude = Vector.magnitude(vector); - if (magnitude === 0) - return { x: 0, y: 0 }; - return { x: vector.x / magnitude, y: vector.y / magnitude }; - }; - - /** - * Returns the dot-product of two vectors. - * @method dot - * @param {vector} vectorA - * @param {vector} vectorB - * @return {number} The dot product of the two vectors - */ - Vector.dot = function(vectorA, vectorB) { - return (vectorA.x * vectorB.x) + (vectorA.y * vectorB.y); - }; - - /** - * Returns the cross-product of two vectors. - * @method cross - * @param {vector} vectorA - * @param {vector} vectorB - * @return {number} The cross product of the two vectors - */ - Vector.cross = function(vectorA, vectorB) { - return (vectorA.x * vectorB.y) - (vectorA.y * vectorB.x); - }; - - /** - * Returns the cross-product of three vectors. - * @method cross3 - * @param {vector} vectorA - * @param {vector} vectorB - * @param {vector} vectorC - * @return {number} The cross product of the three vectors - */ - Vector.cross3 = function(vectorA, vectorB, vectorC) { - return (vectorB.x - vectorA.x) * (vectorC.y - vectorA.y) - (vectorB.y - vectorA.y) * (vectorC.x - vectorA.x); - }; - - /** - * Adds the two vectors. - * @method add - * @param {vector} vectorA - * @param {vector} vectorB - * @param {vector} [output] - * @return {vector} A new vector of vectorA and vectorB added - */ - Vector.add = function(vectorA, vectorB, output) { - if (!output) output = {}; - output.x = vectorA.x + vectorB.x; - output.y = vectorA.y + vectorB.y; - return output; - }; - - /** - * Subtracts the two vectors. - * @method sub - * @param {vector} vectorA - * @param {vector} vectorB - * @param {vector} [output] - * @return {vector} A new vector of vectorA and vectorB subtracted - */ - Vector.sub = function(vectorA, vectorB, output) { - if (!output) output = {}; - output.x = vectorA.x - vectorB.x; - output.y = vectorA.y - vectorB.y; - return output; - }; - - /** - * Multiplies a vector and a scalar. - * @method mult - * @param {vector} vector - * @param {number} scalar - * @return {vector} A new vector multiplied by scalar - */ - Vector.mult = function(vector, scalar) { - return { x: vector.x * scalar, y: vector.y * scalar }; - }; - - /** - * Divides a vector and a scalar. - * @method div - * @param {vector} vector - * @param {number} scalar - * @return {vector} A new vector divided by scalar - */ - Vector.div = function(vector, scalar) { - return { x: vector.x / scalar, y: vector.y / scalar }; - }; - - /** - * Returns the perpendicular vector. Set `negate` to true for the perpendicular in the opposite direction. - * @method perp - * @param {vector} vector - * @param {bool} [negate=false] - * @return {vector} The perpendicular vector - */ - Vector.perp = function(vector, negate) { - negate = negate === true ? -1 : 1; - return { x: negate * -vector.y, y: negate * vector.x }; - }; - - /** - * Negates both components of a vector such that it points in the opposite direction. - * @method neg - * @param {vector} vector - * @return {vector} The negated vector - */ - Vector.neg = function(vector) { - return { x: -vector.x, y: -vector.y }; - }; - - /** - * Returns the angle between the vector `vectorB - vectorA` and the x-axis in radians. - * @method angle - * @param {vector} vectorA - * @param {vector} vectorB - * @return {number} The angle in radians - */ - Vector.angle = function(vectorA, vectorB) { - return Math.atan2(vectorB.y - vectorA.y, vectorB.x - vectorA.x); - }; - - /** - * Temporary vector pool (not thread-safe). - * @property _temp - * @type {vector[]} - * @private - */ - Vector._temp = [ - Vector.create(), Vector.create(), - Vector.create(), Vector.create(), - Vector.create(), Vector.create() - ]; - -})(); - -/***/ }), -/* 3 */ -/***/ (function(module, exports, __webpack_require__) { - -/** -* The `Matter.Vertices` module contains methods for creating and manipulating sets of vertices. -* A set of vertices is an array of `Matter.Vector` with additional indexing properties inserted by `Vertices.create`. -* A `Matter.Body` maintains a set of vertices to represent the shape of the object (its convex hull). -* -* See the included usage [examples](https://github.com/liabru/matter-js/tree/master/examples). -* -* @class Vertices -*/ - -var Vertices = {}; - -module.exports = Vertices; - -var Vector = __webpack_require__(2); -var Common = __webpack_require__(0); - -(function() { - - /** - * Creates a new set of `Matter.Body` compatible vertices. - * The `points` argument accepts an array of `Matter.Vector` points orientated around the origin `(0, 0)`, for example: - * - * [{ x: 0, y: 0 }, { x: 25, y: 50 }, { x: 50, y: 0 }] - * - * The `Vertices.create` method returns a new array of vertices, which are similar to Matter.Vector objects, - * but with some additional references required for efficient collision detection routines. - * - * Vertices must be specified in clockwise order. - * - * Note that the `body` argument is not optional, a `Matter.Body` reference must be provided. - * - * @method create - * @param {vector[]} points - * @param {body} body - */ - Vertices.create = function(points, body) { - var vertices = []; - - for (var i = 0; i < points.length; i++) { - var point = points[i], - vertex = { - x: point.x, - y: point.y, - index: i, - body: body, - isInternal: false - }; - - vertices.push(vertex); - } - - return vertices; - }; - - /** - * Parses a string containing ordered x y pairs separated by spaces (and optionally commas), - * into a `Matter.Vertices` object for the given `Matter.Body`. - * For parsing SVG paths, see `Svg.pathToVertices`. - * @method fromPath - * @param {string} path - * @param {body} body - * @return {vertices} vertices - */ - Vertices.fromPath = function(path, body) { - var pathPattern = /L?\s*([-\d.e]+)[\s,]*([-\d.e]+)*/ig, - points = []; - - path.replace(pathPattern, function(match, x, y) { - points.push({ x: parseFloat(x), y: parseFloat(y) }); - }); - - return Vertices.create(points, body); - }; - - /** - * Returns the centre (centroid) of the set of vertices. - * @method centre - * @param {vertices} vertices - * @return {vector} The centre point - */ - Vertices.centre = function(vertices) { - var area = Vertices.area(vertices, true), - centre = { x: 0, y: 0 }, - cross, - temp, - j; - - for (var i = 0; i < vertices.length; i++) { - j = (i + 1) % vertices.length; - cross = Vector.cross(vertices[i], vertices[j]); - temp = Vector.mult(Vector.add(vertices[i], vertices[j]), cross); - centre = Vector.add(centre, temp); - } - - return Vector.div(centre, 6 * area); - }; - - /** - * Returns the average (mean) of the set of vertices. - * @method mean - * @param {vertices} vertices - * @return {vector} The average point - */ - Vertices.mean = function(vertices) { - var average = { x: 0, y: 0 }; - - for (var i = 0; i < vertices.length; i++) { - average.x += vertices[i].x; - average.y += vertices[i].y; - } - - return Vector.div(average, vertices.length); - }; - - /** - * Returns the area of the set of vertices. - * @method area - * @param {vertices} vertices - * @param {bool} signed - * @return {number} The area - */ - Vertices.area = function(vertices, signed) { - var area = 0, - j = vertices.length - 1; - - for (var i = 0; i < vertices.length; i++) { - area += (vertices[j].x - vertices[i].x) * (vertices[j].y + vertices[i].y); - j = i; - } - - if (signed) - return area / 2; - - return Math.abs(area) / 2; - }; - - /** - * Returns the moment of inertia (second moment of area) of the set of vertices given the total mass. - * @method inertia - * @param {vertices} vertices - * @param {number} mass - * @return {number} The polygon's moment of inertia - */ - Vertices.inertia = function(vertices, mass) { - var numerator = 0, - denominator = 0, - v = vertices, - cross, - j; - - // find the polygon's moment of inertia, using second moment of area - // from equations at http://www.physicsforums.com/showthread.php?t=25293 - for (var n = 0; n < v.length; n++) { - j = (n + 1) % v.length; - cross = Math.abs(Vector.cross(v[j], v[n])); - numerator += cross * (Vector.dot(v[j], v[j]) + Vector.dot(v[j], v[n]) + Vector.dot(v[n], v[n])); - denominator += cross; - } - - return (mass / 6) * (numerator / denominator); - }; - - /** - * Translates the set of vertices in-place. - * @method translate - * @param {vertices} vertices - * @param {vector} vector - * @param {number} scalar - */ - Vertices.translate = function(vertices, vector, scalar) { - scalar = typeof scalar !== 'undefined' ? scalar : 1; - - var verticesLength = vertices.length, - translateX = vector.x * scalar, - translateY = vector.y * scalar, - i; - - for (i = 0; i < verticesLength; i++) { - vertices[i].x += translateX; - vertices[i].y += translateY; - } - - return vertices; - }; - - /** - * Rotates the set of vertices in-place. - * @method rotate - * @param {vertices} vertices - * @param {number} angle - * @param {vector} point - */ - Vertices.rotate = function(vertices, angle, point) { - if (angle === 0) - return; - - var cos = Math.cos(angle), - sin = Math.sin(angle), - pointX = point.x, - pointY = point.y, - verticesLength = vertices.length, - vertex, - dx, - dy, - i; - - for (i = 0; i < verticesLength; i++) { - vertex = vertices[i]; - dx = vertex.x - pointX; - dy = vertex.y - pointY; - vertex.x = pointX + (dx * cos - dy * sin); - vertex.y = pointY + (dx * sin + dy * cos); - } - - return vertices; - }; - - /** - * Returns `true` if the `point` is inside the set of `vertices`. - * @method contains - * @param {vertices} vertices - * @param {vector} point - * @return {boolean} True if the vertices contains point, otherwise false - */ - Vertices.contains = function(vertices, point) { - var pointX = point.x, - pointY = point.y, - verticesLength = vertices.length, - vertex = vertices[verticesLength - 1], - nextVertex; - - for (var i = 0; i < verticesLength; i++) { - nextVertex = vertices[i]; - - if ((pointX - vertex.x) * (nextVertex.y - vertex.y) - + (pointY - vertex.y) * (vertex.x - nextVertex.x) > 0) { - return false; - } - - vertex = nextVertex; - } - - return true; - }; - - /** - * Scales the vertices from a point (default is centre) in-place. - * @method scale - * @param {vertices} vertices - * @param {number} scaleX - * @param {number} scaleY - * @param {vector} point - */ - Vertices.scale = function(vertices, scaleX, scaleY, point) { - if (scaleX === 1 && scaleY === 1) - return vertices; - - point = point || Vertices.centre(vertices); - - var vertex, - delta; - - for (var i = 0; i < vertices.length; i++) { - vertex = vertices[i]; - delta = Vector.sub(vertex, point); - vertices[i].x = point.x + delta.x * scaleX; - vertices[i].y = point.y + delta.y * scaleY; - } - - return vertices; - }; - - /** - * Chamfers a set of vertices by giving them rounded corners, returns a new set of vertices. - * The radius parameter is a single number or an array to specify the radius for each vertex. - * @method chamfer - * @param {vertices} vertices - * @param {number[]} radius - * @param {number} quality - * @param {number} qualityMin - * @param {number} qualityMax - */ - Vertices.chamfer = function(vertices, radius, quality, qualityMin, qualityMax) { - if (typeof radius === 'number') { - radius = [radius]; - } else { - radius = radius || [8]; - } - - // quality defaults to -1, which is auto - quality = (typeof quality !== 'undefined') ? quality : -1; - qualityMin = qualityMin || 2; - qualityMax = qualityMax || 14; - - var newVertices = []; - - for (var i = 0; i < vertices.length; i++) { - var prevVertex = vertices[i - 1 >= 0 ? i - 1 : vertices.length - 1], - vertex = vertices[i], - nextVertex = vertices[(i + 1) % vertices.length], - currentRadius = radius[i < radius.length ? i : radius.length - 1]; - - if (currentRadius === 0) { - newVertices.push(vertex); - continue; - } - - var prevNormal = Vector.normalise({ - x: vertex.y - prevVertex.y, - y: prevVertex.x - vertex.x - }); - - var nextNormal = Vector.normalise({ - x: nextVertex.y - vertex.y, - y: vertex.x - nextVertex.x - }); - - var diagonalRadius = Math.sqrt(2 * Math.pow(currentRadius, 2)), - radiusVector = Vector.mult(Common.clone(prevNormal), currentRadius), - midNormal = Vector.normalise(Vector.mult(Vector.add(prevNormal, nextNormal), 0.5)), - scaledVertex = Vector.sub(vertex, Vector.mult(midNormal, diagonalRadius)); - - var precision = quality; - - if (quality === -1) { - // automatically decide precision - precision = Math.pow(currentRadius, 0.32) * 1.75; - } - - precision = Common.clamp(precision, qualityMin, qualityMax); - - // use an even value for precision, more likely to reduce axes by using symmetry - if (precision % 2 === 1) - precision += 1; - - var alpha = Math.acos(Vector.dot(prevNormal, nextNormal)), - theta = alpha / precision; - - for (var j = 0; j < precision; j++) { - newVertices.push(Vector.add(Vector.rotate(radiusVector, theta * j), scaledVertex)); - } - } - - return newVertices; - }; - - /** - * Sorts the input vertices into clockwise order in place. - * @method clockwiseSort - * @param {vertices} vertices - * @return {vertices} vertices - */ - Vertices.clockwiseSort = function(vertices) { - var centre = Vertices.mean(vertices); - - vertices.sort(function(vertexA, vertexB) { - return Vector.angle(centre, vertexA) - Vector.angle(centre, vertexB); - }); - - return vertices; - }; - - /** - * Returns true if the vertices form a convex shape (vertices must be in clockwise order). - * @method isConvex - * @param {vertices} vertices - * @return {bool} `true` if the `vertices` are convex, `false` if not (or `null` if not computable). - */ - Vertices.isConvex = function(vertices) { - // http://paulbourke.net/geometry/polygonmesh/ - // Copyright (c) Paul Bourke (use permitted) - - var flag = 0, - n = vertices.length, - i, - j, - k, - z; - - if (n < 3) - return null; - - for (i = 0; i < n; i++) { - j = (i + 1) % n; - k = (i + 2) % n; - z = (vertices[j].x - vertices[i].x) * (vertices[k].y - vertices[j].y); - z -= (vertices[j].y - vertices[i].y) * (vertices[k].x - vertices[j].x); - - if (z < 0) { - flag |= 1; - } else if (z > 0) { - flag |= 2; - } - - if (flag === 3) { - return false; - } - } - - if (flag !== 0){ - return true; - } else { - return null; - } - }; - - /** - * Returns the convex hull of the input vertices as a new array of points. - * @method hull - * @param {vertices} vertices - * @return [vertex] vertices - */ - Vertices.hull = function(vertices) { - // http://geomalgorithms.com/a10-_hull-1.html - - var upper = [], - lower = [], - vertex, - i; - - // sort vertices on x-axis (y-axis for ties) - vertices = vertices.slice(0); - vertices.sort(function(vertexA, vertexB) { - var dx = vertexA.x - vertexB.x; - return dx !== 0 ? dx : vertexA.y - vertexB.y; - }); - - // build lower hull - for (i = 0; i < vertices.length; i += 1) { - vertex = vertices[i]; - - while (lower.length >= 2 - && Vector.cross3(lower[lower.length - 2], lower[lower.length - 1], vertex) <= 0) { - lower.pop(); - } - - lower.push(vertex); - } - - // build upper hull - for (i = vertices.length - 1; i >= 0; i -= 1) { - vertex = vertices[i]; - - while (upper.length >= 2 - && Vector.cross3(upper[upper.length - 2], upper[upper.length - 1], vertex) <= 0) { - upper.pop(); - } - - upper.push(vertex); - } - - // concatenation of the lower and upper hulls gives the convex hull - // omit last points because they are repeated at the beginning of the other list - upper.pop(); - lower.pop(); - - return upper.concat(lower); - }; - -})(); - - -/***/ }), -/* 4 */ -/***/ (function(module, exports, __webpack_require__) { - -/** -* 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 = __webpack_require__(3); -var Vector = __webpack_require__(2); -var Sleeping = __webpack_require__(7); -var Common = __webpack_require__(0); -var Bounds = __webpack_require__(1); -var Axes = __webpack_require__(11); - -(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 - */ - -})(); - - -/***/ }), -/* 5 */ -/***/ (function(module, exports, __webpack_require__) { - -/** -* The `Matter.Events` module contains methods to fire and listen to events on other objects. -* -* See the included usage [examples](https://github.com/liabru/matter-js/tree/master/examples). -* -* @class Events -*/ - -var Events = {}; - -module.exports = Events; - -var Common = __webpack_require__(0); - -(function() { - - /** - * Subscribes a callback function to the given object's `eventName`. - * @method on - * @param {} object - * @param {string} eventNames - * @param {function} callback - */ - Events.on = function(object, eventNames, callback) { - var names = eventNames.split(' '), - name; - - for (var i = 0; i < names.length; i++) { - name = names[i]; - object.events = object.events || {}; - object.events[name] = object.events[name] || []; - object.events[name].push(callback); - } - - return callback; - }; - - /** - * Removes the given event callback. If no callback, clears all callbacks in `eventNames`. If no `eventNames`, clears all events. - * @method off - * @param {} object - * @param {string} eventNames - * @param {function} callback - */ - Events.off = function(object, eventNames, callback) { - if (!eventNames) { - object.events = {}; - return; - } - - // handle Events.off(object, callback) - if (typeof eventNames === 'function') { - callback = eventNames; - eventNames = Common.keys(object.events).join(' '); - } - - var names = eventNames.split(' '); - - for (var i = 0; i < names.length; i++) { - var callbacks = object.events[names[i]], - newCallbacks = []; - - if (callback && callbacks) { - for (var j = 0; j < callbacks.length; j++) { - if (callbacks[j] !== callback) - newCallbacks.push(callbacks[j]); - } - } - - object.events[names[i]] = newCallbacks; - } - }; - - /** - * Fires all the callbacks subscribed to the given object's `eventName`, in the order they subscribed, if any. - * @method trigger - * @param {} object - * @param {string} eventNames - * @param {} event - */ - Events.trigger = function(object, eventNames, event) { - var names, - name, - callbacks, - eventClone; - - var events = object.events; - - if (events && Common.keys(events).length > 0) { - if (!event) - event = {}; - - names = eventNames.split(' '); - - for (var i = 0; i < names.length; i++) { - name = names[i]; - callbacks = events[name]; - - if (callbacks) { - eventClone = Common.clone(event, false); - eventClone.name = name; - eventClone.source = object; - - for (var j = 0; j < callbacks.length; j++) { - callbacks[j].apply(object, [eventClone]); - } - } - } - } - }; - -})(); - - -/***/ }), -/* 6 */ -/***/ (function(module, exports, __webpack_require__) { - -/** -* A composite is a collection of `Matter.Body`, `Matter.Constraint` and other `Matter.Composite` objects. -* -* They are a container that can represent complex objects made of multiple parts, even if they are not physically connected. -* A composite could contain anything from a single body all the way up to a whole world. -* -* When making any changes to composites, use the included functions rather than changing their properties directly. -* -* See the included usage [examples](https://github.com/liabru/matter-js/tree/master/examples). -* -* @class Composite -*/ - -var Composite = {}; - -module.exports = Composite; - -var Events = __webpack_require__(5); -var Common = __webpack_require__(0); -var Bounds = __webpack_require__(1); -var Body = __webpack_require__(4); - -(function() { - - /** - * Creates a new composite. The options parameter is an object that specifies any properties you wish to override the defaults. - * See the properites section below for detailed information on what you can pass via the `options` object. - * @method create - * @param {} [options] - * @return {composite} A new composite - */ - Composite.create = function(options) { - return Common.extend({ - id: Common.nextId(), - type: 'composite', - parent: null, - isModified: false, - bodies: [], - constraints: [], - composites: [], - label: 'Composite', - plugin: {}, - cache: { - allBodies: null, - allConstraints: null, - allComposites: null - } - }, options); - }; - - /** - * Sets the composite's `isModified` flag. - * If `updateParents` is true, all parents will be set (default: false). - * If `updateChildren` is true, all children will be set (default: false). - * @private - * @method setModified - * @param {composite} composite - * @param {boolean} isModified - * @param {boolean} [updateParents=false] - * @param {boolean} [updateChildren=false] - */ - Composite.setModified = function(composite, isModified, updateParents, updateChildren) { - composite.isModified = isModified; - - if (isModified && composite.cache) { - composite.cache.allBodies = null; - composite.cache.allConstraints = null; - composite.cache.allComposites = null; - } - - if (updateParents && composite.parent) { - Composite.setModified(composite.parent, isModified, updateParents, updateChildren); - } - - if (updateChildren) { - for (var i = 0; i < composite.composites.length; i++) { - var childComposite = composite.composites[i]; - Composite.setModified(childComposite, isModified, updateParents, updateChildren); - } - } - }; - - /** - * Generic single or multi-add function. Adds a single or an array of body(s), constraint(s) or composite(s) to the given composite. - * Triggers `beforeAdd` and `afterAdd` events on the `composite`. - * @method add - * @param {composite} composite - * @param {object|array} object A single or an array of body(s), constraint(s) or composite(s) - * @return {composite} The original composite with the objects added - */ - Composite.add = function(composite, object) { - var objects = [].concat(object); - - Events.trigger(composite, 'beforeAdd', { object: object }); - - for (var i = 0; i < objects.length; i++) { - var obj = objects[i]; - - switch (obj.type) { - - case 'body': - // skip adding compound parts - if (obj.parent !== obj) { - Common.warn('Composite.add: skipped adding a compound body part (you must add its parent instead)'); - break; - } - - Composite.addBody(composite, obj); - break; - case 'constraint': - Composite.addConstraint(composite, obj); - break; - case 'composite': - Composite.addComposite(composite, obj); - break; - case 'mouseConstraint': - Composite.addConstraint(composite, obj.constraint); - break; - - } - } - - Events.trigger(composite, 'afterAdd', { object: object }); - - return composite; - }; - - /** - * Generic remove function. Removes one or many body(s), constraint(s) or a composite(s) to the given composite. - * Optionally searching its children recursively. - * Triggers `beforeRemove` and `afterRemove` events on the `composite`. - * @method remove - * @param {composite} composite - * @param {object|array} object - * @param {boolean} [deep=false] - * @return {composite} The original composite with the objects removed - */ - Composite.remove = function(composite, object, deep) { - var objects = [].concat(object); - - Events.trigger(composite, 'beforeRemove', { object: object }); - - for (var i = 0; i < objects.length; i++) { - var obj = objects[i]; - - switch (obj.type) { - - case 'body': - Composite.removeBody(composite, obj, deep); - break; - case 'constraint': - Composite.removeConstraint(composite, obj, deep); - break; - case 'composite': - Composite.removeComposite(composite, obj, deep); - break; - case 'mouseConstraint': - Composite.removeConstraint(composite, obj.constraint); - break; - - } - } - - Events.trigger(composite, 'afterRemove', { object: object }); - - return composite; - }; - - /** - * Adds a composite to the given composite. - * @private - * @method addComposite - * @param {composite} compositeA - * @param {composite} compositeB - * @return {composite} The original compositeA with the objects from compositeB added - */ - Composite.addComposite = function(compositeA, compositeB) { - compositeA.composites.push(compositeB); - compositeB.parent = compositeA; - Composite.setModified(compositeA, true, true, false); - return compositeA; - }; - - /** - * Removes a composite from the given composite, and optionally searching its children recursively. - * @private - * @method removeComposite - * @param {composite} compositeA - * @param {composite} compositeB - * @param {boolean} [deep=false] - * @return {composite} The original compositeA with the composite removed - */ - Composite.removeComposite = function(compositeA, compositeB, deep) { - var position = Common.indexOf(compositeA.composites, compositeB); - if (position !== -1) { - Composite.removeCompositeAt(compositeA, position); - } - - if (deep) { - for (var i = 0; i < compositeA.composites.length; i++){ - Composite.removeComposite(compositeA.composites[i], compositeB, true); - } - } - - return compositeA; - }; - - /** - * Removes a composite from the given composite. - * @private - * @method removeCompositeAt - * @param {composite} composite - * @param {number} position - * @return {composite} The original composite with the composite removed - */ - Composite.removeCompositeAt = function(composite, position) { - composite.composites.splice(position, 1); - Composite.setModified(composite, true, true, false); - return composite; - }; - - /** - * Adds a body to the given composite. - * @private - * @method addBody - * @param {composite} composite - * @param {body} body - * @return {composite} The original composite with the body added - */ - Composite.addBody = function(composite, body) { - composite.bodies.push(body); - Composite.setModified(composite, true, true, false); - return composite; - }; - - /** - * Removes a body from the given composite, and optionally searching its children recursively. - * @private - * @method removeBody - * @param {composite} composite - * @param {body} body - * @param {boolean} [deep=false] - * @return {composite} The original composite with the body removed - */ - Composite.removeBody = function(composite, body, deep) { - var position = Common.indexOf(composite.bodies, body); - if (position !== -1) { - Composite.removeBodyAt(composite, position); - } - - if (deep) { - for (var i = 0; i < composite.composites.length; i++){ - Composite.removeBody(composite.composites[i], body, true); - } - } - - return composite; - }; - - /** - * Removes a body from the given composite. - * @private - * @method removeBodyAt - * @param {composite} composite - * @param {number} position - * @return {composite} The original composite with the body removed - */ - Composite.removeBodyAt = function(composite, position) { - composite.bodies.splice(position, 1); - Composite.setModified(composite, true, true, false); - return composite; - }; - - /** - * Adds a constraint to the given composite. - * @private - * @method addConstraint - * @param {composite} composite - * @param {constraint} constraint - * @return {composite} The original composite with the constraint added - */ - Composite.addConstraint = function(composite, constraint) { - composite.constraints.push(constraint); - Composite.setModified(composite, true, true, false); - return composite; - }; - - /** - * Removes a constraint from the given composite, and optionally searching its children recursively. - * @private - * @method removeConstraint - * @param {composite} composite - * @param {constraint} constraint - * @param {boolean} [deep=false] - * @return {composite} The original composite with the constraint removed - */ - Composite.removeConstraint = function(composite, constraint, deep) { - var position = Common.indexOf(composite.constraints, constraint); - if (position !== -1) { - Composite.removeConstraintAt(composite, position); - } - - if (deep) { - for (var i = 0; i < composite.composites.length; i++){ - Composite.removeConstraint(composite.composites[i], constraint, true); - } - } - - return composite; - }; - - /** - * Removes a body from the given composite. - * @private - * @method removeConstraintAt - * @param {composite} composite - * @param {number} position - * @return {composite} The original composite with the constraint removed - */ - Composite.removeConstraintAt = function(composite, position) { - composite.constraints.splice(position, 1); - Composite.setModified(composite, true, true, false); - return composite; - }; - - /** - * Removes all bodies, constraints and composites from the given composite. - * Optionally clearing its children recursively. - * @method clear - * @param {composite} composite - * @param {boolean} keepStatic - * @param {boolean} [deep=false] - */ - Composite.clear = function(composite, keepStatic, deep) { - if (deep) { - for (var i = 0; i < composite.composites.length; i++){ - Composite.clear(composite.composites[i], keepStatic, true); - } - } - - if (keepStatic) { - composite.bodies = composite.bodies.filter(function(body) { return body.isStatic; }); - } else { - composite.bodies.length = 0; - } - - composite.constraints.length = 0; - composite.composites.length = 0; - - Composite.setModified(composite, true, true, false); - - return composite; - }; - - /** - * Returns all bodies in the given composite, including all bodies in its children, recursively. - * @method allBodies - * @param {composite} composite - * @return {body[]} All the bodies - */ - Composite.allBodies = function(composite) { - if (composite.cache && composite.cache.allBodies) { - return composite.cache.allBodies; - } - - var bodies = [].concat(composite.bodies); - - for (var i = 0; i < composite.composites.length; i++) - bodies = bodies.concat(Composite.allBodies(composite.composites[i])); - - if (composite.cache) { - composite.cache.allBodies = bodies; - } - - return bodies; - }; - - /** - * Returns all constraints in the given composite, including all constraints in its children, recursively. - * @method allConstraints - * @param {composite} composite - * @return {constraint[]} All the constraints - */ - Composite.allConstraints = function(composite) { - if (composite.cache && composite.cache.allConstraints) { - return composite.cache.allConstraints; - } - - var constraints = [].concat(composite.constraints); - - for (var i = 0; i < composite.composites.length; i++) - constraints = constraints.concat(Composite.allConstraints(composite.composites[i])); - - if (composite.cache) { - composite.cache.allConstraints = constraints; - } - - return constraints; - }; - - /** - * Returns all composites in the given composite, including all composites in its children, recursively. - * @method allComposites - * @param {composite} composite - * @return {composite[]} All the composites - */ - Composite.allComposites = function(composite) { - if (composite.cache && composite.cache.allComposites) { - return composite.cache.allComposites; - } - - var composites = [].concat(composite.composites); - - for (var i = 0; i < composite.composites.length; i++) - composites = composites.concat(Composite.allComposites(composite.composites[i])); - - if (composite.cache) { - composite.cache.allComposites = composites; - } - - return composites; - }; - - /** - * Searches the composite recursively for an object matching the type and id supplied, null if not found. - * @method get - * @param {composite} composite - * @param {number} id - * @param {string} type - * @return {object} The requested object, if found - */ - Composite.get = function(composite, id, type) { - var objects, - object; - - switch (type) { - case 'body': - objects = Composite.allBodies(composite); - break; - case 'constraint': - objects = Composite.allConstraints(composite); - break; - case 'composite': - objects = Composite.allComposites(composite).concat(composite); - break; - } - - if (!objects) - return null; - - object = objects.filter(function(object) { - return object.id.toString() === id.toString(); - }); - - return object.length === 0 ? null : object[0]; - }; - - /** - * Moves the given object(s) from compositeA to compositeB (equal to a remove followed by an add). - * @method move - * @param {compositeA} compositeA - * @param {object[]} objects - * @param {compositeB} compositeB - * @return {composite} Returns compositeA - */ - Composite.move = function(compositeA, objects, compositeB) { - Composite.remove(compositeA, objects); - Composite.add(compositeB, objects); - return compositeA; - }; - - /** - * Assigns new ids for all objects in the composite, recursively. - * @method rebase - * @param {composite} composite - * @return {composite} Returns composite - */ - Composite.rebase = function(composite) { - var objects = Composite.allBodies(composite) - .concat(Composite.allConstraints(composite)) - .concat(Composite.allComposites(composite)); - - for (var i = 0; i < objects.length; i++) { - objects[i].id = Common.nextId(); - } - - return composite; - }; - - /** - * Translates all children in the composite by a given vector relative to their current positions, - * without imparting any velocity. - * @method translate - * @param {composite} composite - * @param {vector} translation - * @param {bool} [recursive=true] - */ - Composite.translate = function(composite, translation, recursive) { - var bodies = recursive ? Composite.allBodies(composite) : composite.bodies; - - for (var i = 0; i < bodies.length; i++) { - Body.translate(bodies[i], translation); - } - - return composite; - }; - - /** - * Rotates all children in the composite by a given angle about the given point, without imparting any angular velocity. - * @method rotate - * @param {composite} composite - * @param {number} rotation - * @param {vector} point - * @param {bool} [recursive=true] - */ - Composite.rotate = function(composite, rotation, point, recursive) { - var cos = Math.cos(rotation), - sin = Math.sin(rotation), - bodies = recursive ? Composite.allBodies(composite) : composite.bodies; - - for (var i = 0; i < bodies.length; i++) { - var body = bodies[i], - 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) - }); - - Body.rotate(body, rotation); - } - - return composite; - }; - - /** - * Scales all children in the composite, including updating physical properties (mass, area, axes, inertia), from a world-space point. - * @method scale - * @param {composite} composite - * @param {number} scaleX - * @param {number} scaleY - * @param {vector} point - * @param {bool} [recursive=true] - */ - Composite.scale = function(composite, scaleX, scaleY, point, recursive) { - var bodies = recursive ? Composite.allBodies(composite) : composite.bodies; - - for (var i = 0; i < bodies.length; i++) { - var body = bodies[i], - dx = body.position.x - point.x, - dy = body.position.y - point.y; - - Body.setPosition(body, { - x: point.x + dx * scaleX, - y: point.y + dy * scaleY - }); - - Body.scale(body, scaleX, scaleY); - } - - return composite; - }; - - /** - * Returns the union of the bounds of all of the composite's bodies. - * @method bounds - * @param {composite} composite The composite. - * @returns {bounds} The composite bounds. - */ - Composite.bounds = function(composite) { - var bodies = Composite.allBodies(composite), - vertices = []; - - for (var i = 0; i < bodies.length; i += 1) { - var body = bodies[i]; - vertices.push(body.bounds.min, body.bounds.max); - } - - return Bounds.create(vertices); - }; - - /* - * - * Events Documentation - * - */ - - /** - * Fired when a call to `Composite.add` is made, before objects have been added. - * - * @event beforeAdd - * @param {} event An event object - * @param {} event.object The object(s) to be added (may be a single body, constraint, composite or a mixed array of these) - * @param {} event.source The source object of the event - * @param {} event.name The name of the event - */ - - /** - * Fired when a call to `Composite.add` is made, after objects have been added. - * - * @event afterAdd - * @param {} event An event object - * @param {} event.object The object(s) that have been added (may be a single body, constraint, composite or a mixed array of these) - * @param {} event.source The source object of the event - * @param {} event.name The name of the event - */ - - /** - * Fired when a call to `Composite.remove` is made, before objects have been removed. - * - * @event beforeRemove - * @param {} event An event object - * @param {} event.object The object(s) to be removed (may be a single body, constraint, composite or a mixed array of these) - * @param {} event.source The source object of the event - * @param {} event.name The name of the event - */ - - /** - * Fired when a call to `Composite.remove` is made, after objects have been removed. - * - * @event afterRemove - * @param {} event An event object - * @param {} event.object The object(s) that have been removed (may be a single body, constraint, composite or a mixed array of these) - * @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 `Composite.create` by `Common.nextId`. - * - * @property id - * @type number - */ - - /** - * A `String` denoting the type of object. - * - * @property type - * @type string - * @default "composite" - * @readOnly - */ - - /** - * An arbitrary `String` name to help the user identify and manage composites. - * - * @property label - * @type string - * @default "Composite" - */ - - /** - * A flag that specifies whether the composite has been modified during the current step. - * This is automatically managed when bodies, constraints or composites are added or removed. - * - * @property isModified - * @type boolean - * @default false - */ - - /** - * The `Composite` that is the parent of this composite. It is automatically managed by the `Matter.Composite` methods. - * - * @property parent - * @type composite - * @default null - */ - - /** - * An array of `Body` that are _direct_ children of this composite. - * To add or remove bodies you should use `Composite.add` and `Composite.remove` methods rather than directly modifying this property. - * If you wish to recursively find all descendants, you should use the `Composite.allBodies` method. - * - * @property bodies - * @type body[] - * @default [] - */ - - /** - * An array of `Constraint` that are _direct_ children of this composite. - * To add or remove constraints you should use `Composite.add` and `Composite.remove` methods rather than directly modifying this property. - * If you wish to recursively find all descendants, you should use the `Composite.allConstraints` method. - * - * @property constraints - * @type constraint[] - * @default [] - */ - - /** - * An array of `Composite` that are _direct_ children of this composite. - * To add or remove composites you should use `Composite.add` and `Composite.remove` methods rather than directly modifying this property. - * If you wish to recursively find all descendants, you should use the `Composite.allComposites` method. - * - * @property composites - * @type composite[] - * @default [] - */ - - /** - * An object reserved for storing plugin-specific properties. - * - * @property plugin - * @type {} - */ - - /** - * An object used for storing cached results for performance reasons. - * This is used internally only and is automatically managed. - * - * @private - * @property cache - * @type {} - */ - -})(); - - -/***/ }), -/* 7 */ -/***/ (function(module, exports, __webpack_require__) { - -/** -* The `Matter.Sleeping` module contains methods to manage the sleeping state of bodies. -* -* @class Sleeping -*/ - -var Sleeping = {}; - -module.exports = Sleeping; - -var Body = __webpack_require__(4); -var Events = __webpack_require__(5); -var Common = __webpack_require__(0); - -(function() { - - Sleeping._motionWakeThreshold = 0.18; - Sleeping._motionSleepThreshold = 0.08; - Sleeping._minBias = 0.9; - - /** - * Puts bodies to sleep or wakes them up depending on their motion. - * @method update - * @param {body[]} bodies - * @param {number} delta - */ - Sleeping.update = function(bodies, delta) { - var timeScale = delta / Common._baseDelta, - motionSleepThreshold = Sleeping._motionSleepThreshold; - - // update bodies sleeping status - for (var i = 0; i < bodies.length; i++) { - var body = bodies[i], - speed = Body.getSpeed(body), - angularSpeed = Body.getAngularSpeed(body), - motion = speed * speed + angularSpeed * angularSpeed; - - // wake up bodies if they have a force applied - if (body.force.x !== 0 || body.force.y !== 0) { - Sleeping.set(body, false); - continue; - } - - var minMotion = Math.min(body.motion, motion), - maxMotion = Math.max(body.motion, motion); - - // biased average motion estimation between frames - body.motion = Sleeping._minBias * minMotion + (1 - Sleeping._minBias) * maxMotion; - - if (body.sleepThreshold > 0 && body.motion < motionSleepThreshold) { - body.sleepCounter += 1; - - if (body.sleepCounter >= body.sleepThreshold / timeScale) { - Sleeping.set(body, true); - } - } else if (body.sleepCounter > 0) { - body.sleepCounter -= 1; - } - } - }; - - /** - * Given a set of colliding pairs, wakes the sleeping bodies involved. - * @method afterCollisions - * @param {pair[]} pairs - */ - Sleeping.afterCollisions = function(pairs) { - var motionSleepThreshold = Sleeping._motionSleepThreshold; - - // wake up bodies involved in collisions - for (var i = 0; i < pairs.length; i++) { - var pair = pairs[i]; - - // don't wake inactive pairs - if (!pair.isActive) - continue; - - var collision = pair.collision, - bodyA = collision.bodyA.parent, - bodyB = collision.bodyB.parent; - - // don't wake if at least one body is static - if ((bodyA.isSleeping && bodyB.isSleeping) || bodyA.isStatic || bodyB.isStatic) - continue; - - if (bodyA.isSleeping || bodyB.isSleeping) { - var sleepingBody = (bodyA.isSleeping && !bodyA.isStatic) ? bodyA : bodyB, - movingBody = sleepingBody === bodyA ? bodyB : bodyA; - - if (!sleepingBody.isStatic && movingBody.motion > motionSleepThreshold) { - Sleeping.set(sleepingBody, false); - } - } - } - }; - - /** - * Set a body as sleeping or awake. - * @method set - * @param {body} body - * @param {boolean} isSleeping - */ - Sleeping.set = function(body, isSleeping) { - var wasSleeping = body.isSleeping; - - if (isSleeping) { - body.isSleeping = true; - body.sleepCounter = body.sleepThreshold; - - body.positionImpulse.x = 0; - body.positionImpulse.y = 0; - - body.positionPrev.x = body.position.x; - body.positionPrev.y = body.position.y; - - body.anglePrev = body.angle; - body.speed = 0; - body.angularSpeed = 0; - body.motion = 0; - - if (!wasSleeping) { - Events.trigger(body, 'sleepStart'); - } - } else { - body.isSleeping = false; - body.sleepCounter = 0; - - if (wasSleeping) { - Events.trigger(body, 'sleepEnd'); - } - } - }; - -})(); - - -/***/ }), -/* 8 */ -/***/ (function(module, exports, __webpack_require__) { - -/** -* The `Matter.Collision` module contains methods for detecting collisions between a given pair of bodies. -* -* For efficient detection between a list of bodies, see `Matter.Detector` and `Matter.Query`. -* -* See `Matter.Engine` for collision events. -* -* @class Collision -*/ - -var Collision = {}; - -module.exports = Collision; - -var Vertices = __webpack_require__(3); -var Pair = __webpack_require__(9); - -(function() { - var _supports = []; - - var _overlapAB = { - overlap: 0, - axis: null - }; - - var _overlapBA = { - overlap: 0, - axis: null - }; - - /** - * Creates a new collision record. - * @method create - * @param {body} bodyA The first body part represented by the collision record - * @param {body} bodyB The second body part represented by the collision record - * @return {collision} A new collision record - */ - Collision.create = function(bodyA, bodyB) { - return { - pair: null, - collided: false, - bodyA: bodyA, - bodyB: bodyB, - parentA: bodyA.parent, - parentB: bodyB.parent, - depth: 0, - normal: { x: 0, y: 0 }, - tangent: { x: 0, y: 0 }, - penetration: { x: 0, y: 0 }, - supports: [] - }; - }; - - /** - * Detect collision between two bodies. - * @method collides - * @param {body} bodyA - * @param {body} bodyB - * @param {pairs} [pairs] Optionally reuse collision records from existing pairs. - * @return {collision|null} A collision record if detected, otherwise null - */ - Collision.collides = function(bodyA, bodyB, pairs) { - Collision._overlapAxes(_overlapAB, bodyA.vertices, bodyB.vertices, bodyA.axes); - - if (_overlapAB.overlap <= 0) { - return null; - } - - Collision._overlapAxes(_overlapBA, bodyB.vertices, bodyA.vertices, bodyB.axes); - - if (_overlapBA.overlap <= 0) { - return null; - } - - // reuse collision records for gc efficiency - var pair = pairs && pairs.table[Pair.id(bodyA, bodyB)], - collision; - - if (!pair) { - collision = Collision.create(bodyA, bodyB); - collision.collided = true; - collision.bodyA = bodyA.id < bodyB.id ? bodyA : bodyB; - collision.bodyB = bodyA.id < bodyB.id ? bodyB : bodyA; - collision.parentA = collision.bodyA.parent; - collision.parentB = collision.bodyB.parent; - } else { - collision = pair.collision; - } - - bodyA = collision.bodyA; - bodyB = collision.bodyB; - - var minOverlap; - - if (_overlapAB.overlap < _overlapBA.overlap) { - minOverlap = _overlapAB; - } else { - minOverlap = _overlapBA; - } - - var normal = collision.normal, - supports = collision.supports, - minAxis = minOverlap.axis, - minAxisX = minAxis.x, - minAxisY = minAxis.y; - - // ensure normal is facing away from bodyA - if (minAxisX * (bodyB.position.x - bodyA.position.x) + minAxisY * (bodyB.position.y - bodyA.position.y) < 0) { - normal.x = minAxisX; - normal.y = minAxisY; - } else { - normal.x = -minAxisX; - normal.y = -minAxisY; - } - - collision.tangent.x = -normal.y; - collision.tangent.y = normal.x; - - collision.depth = minOverlap.overlap; - - collision.penetration.x = normal.x * collision.depth; - collision.penetration.y = normal.y * collision.depth; - - // find support points, there is always either exactly one or two - var supportsB = Collision._findSupports(bodyA, bodyB, normal, 1), - supportCount = 0; - - // find the supports from bodyB that are inside bodyA - if (Vertices.contains(bodyA.vertices, supportsB[0])) { - supports[supportCount++] = supportsB[0]; - } - - if (Vertices.contains(bodyA.vertices, supportsB[1])) { - supports[supportCount++] = supportsB[1]; - } - - // find the supports from bodyA that are inside bodyB - if (supportCount < 2) { - var supportsA = Collision._findSupports(bodyB, bodyA, normal, -1); - - if (Vertices.contains(bodyB.vertices, supportsA[0])) { - supports[supportCount++] = supportsA[0]; - } - - if (supportCount < 2 && Vertices.contains(bodyB.vertices, supportsA[1])) { - supports[supportCount++] = supportsA[1]; - } - } - - // account for the edge case of overlapping but no vertex containment - if (supportCount === 0) { - supports[supportCount++] = supportsB[0]; - } - - // update supports array size - supports.length = supportCount; - - return collision; - }; - - /** - * Find the overlap between two sets of vertices. - * @method _overlapAxes - * @private - * @param {object} result - * @param {vertices} verticesA - * @param {vertices} verticesB - * @param {axes} axes - */ - Collision._overlapAxes = function(result, verticesA, verticesB, axes) { - var verticesALength = verticesA.length, - verticesBLength = verticesB.length, - verticesAX = verticesA[0].x, - verticesAY = verticesA[0].y, - verticesBX = verticesB[0].x, - verticesBY = verticesB[0].y, - axesLength = axes.length, - overlapMin = Number.MAX_VALUE, - overlapAxisNumber = 0, - overlap, - overlapAB, - overlapBA, - dot, - i, - j; - - for (i = 0; i < axesLength; i++) { - var axis = axes[i], - axisX = axis.x, - axisY = axis.y, - minA = verticesAX * axisX + verticesAY * axisY, - minB = verticesBX * axisX + verticesBY * axisY, - maxA = minA, - maxB = minB; - - for (j = 1; j < verticesALength; j += 1) { - dot = verticesA[j].x * axisX + verticesA[j].y * axisY; - - if (dot > maxA) { - maxA = dot; - } else if (dot < minA) { - minA = dot; - } - } - - for (j = 1; j < verticesBLength; j += 1) { - dot = verticesB[j].x * axisX + verticesB[j].y * axisY; - - if (dot > maxB) { - maxB = dot; - } else if (dot < minB) { - minB = dot; - } - } - - overlapAB = maxA - minB; - overlapBA = maxB - minA; - overlap = overlapAB < overlapBA ? overlapAB : overlapBA; - - if (overlap < overlapMin) { - overlapMin = overlap; - overlapAxisNumber = i; - - if (overlap <= 0) { - // can not be intersecting - break; - } - } - } - - result.axis = axes[overlapAxisNumber]; - result.overlap = overlapMin; - }; - - /** - * Projects vertices on an axis and returns an interval. - * @method _projectToAxis - * @private - * @param {} projection - * @param {} vertices - * @param {} axis - */ - Collision._projectToAxis = function(projection, vertices, axis) { - var min = vertices[0].x * axis.x + vertices[0].y * axis.y, - max = min; - - for (var i = 1; i < vertices.length; i += 1) { - var dot = vertices[i].x * axis.x + vertices[i].y * axis.y; - - if (dot > max) { - max = dot; - } else if (dot < min) { - min = dot; - } - } - - projection.min = min; - projection.max = max; - }; - - /** - * Finds supporting vertices given two bodies along a given direction using hill-climbing. - * @method _findSupports - * @private - * @param {body} bodyA - * @param {body} bodyB - * @param {vector} normal - * @param {number} direction - * @return [vector] - */ - Collision._findSupports = function(bodyA, bodyB, normal, direction) { - var vertices = bodyB.vertices, - verticesLength = vertices.length, - bodyAPositionX = bodyA.position.x, - bodyAPositionY = bodyA.position.y, - normalX = normal.x * direction, - normalY = normal.y * direction, - nearestDistance = Number.MAX_VALUE, - vertexA, - vertexB, - vertexC, - distance, - j; - - // find deepest vertex relative to the axis - for (j = 0; j < verticesLength; j += 1) { - vertexB = vertices[j]; - distance = normalX * (bodyAPositionX - vertexB.x) + normalY * (bodyAPositionY - vertexB.y); - - // convex hill-climbing - if (distance < nearestDistance) { - nearestDistance = distance; - vertexA = vertexB; - } - } - - // measure next vertex - vertexC = vertices[(verticesLength + vertexA.index - 1) % verticesLength]; - nearestDistance = normalX * (bodyAPositionX - vertexC.x) + normalY * (bodyAPositionY - vertexC.y); - - // compare with previous vertex - vertexB = vertices[(vertexA.index + 1) % verticesLength]; - if (normalX * (bodyAPositionX - vertexB.x) + normalY * (bodyAPositionY - vertexB.y) < nearestDistance) { - _supports[0] = vertexA; - _supports[1] = vertexB; - - return _supports; - } - - _supports[0] = vertexA; - _supports[1] = vertexC; - - return _supports; - }; - - /* - * - * Properties Documentation - * - */ - - /** - * A reference to the pair using this collision record, if there is one. - * - * @property pair - * @type {pair|null} - * @default null - */ - - /** - * A flag that indicates if the bodies were colliding when the collision was last updated. - * - * @property collided - * @type boolean - * @default false - */ - - /** - * The first body part represented by the collision (see also `collision.parentA`). - * - * @property bodyA - * @type body - */ - - /** - * The second body part represented by the collision (see also `collision.parentB`). - * - * @property bodyB - * @type body - */ - - /** - * The first body represented by the collision (i.e. `collision.bodyA.parent`). - * - * @property parentA - * @type body - */ - - /** - * The second body represented by the collision (i.e. `collision.bodyB.parent`). - * - * @property parentB - * @type body - */ - - /** - * A `Number` that represents the minimum separating distance between the bodies along the collision normal. - * - * @readOnly - * @property depth - * @type number - * @default 0 - */ - - /** - * A normalised `Vector` that represents the direction between the bodies that provides the minimum separating distance. - * - * @property normal - * @type vector - * @default { x: 0, y: 0 } - */ - - /** - * A normalised `Vector` that is the tangent direction to the collision normal. - * - * @property tangent - * @type vector - * @default { x: 0, y: 0 } - */ - - /** - * A `Vector` that represents the direction and depth of the collision. - * - * @property penetration - * @type vector - * @default { x: 0, y: 0 } - */ - - /** - * An array of body vertices that represent the support points in the collision. - * These are the deepest vertices (along the collision normal) of each body that are contained by the other body's vertices. - * - * @property supports - * @type vector[] - * @default [] - */ - -})(); - - -/***/ }), -/* 9 */ -/***/ (function(module, exports, __webpack_require__) { - -/** -* The `Matter.Pair` module contains methods for creating and manipulating collision pairs. -* -* @class Pair -*/ - -var Pair = {}; - -module.exports = Pair; - -var Contact = __webpack_require__(16); - -(function() { - - /** - * Creates a pair. - * @method create - * @param {collision} collision - * @param {number} timestamp - * @return {pair} A new pair - */ - Pair.create = function(collision, timestamp) { - var bodyA = collision.bodyA, - bodyB = collision.bodyB; - - var pair = { - id: Pair.id(bodyA, bodyB), - bodyA: bodyA, - bodyB: bodyB, - collision: collision, - contacts: [], - activeContacts: [], - separation: 0, - isActive: true, - confirmedActive: true, - isSensor: bodyA.isSensor || bodyB.isSensor, - timeCreated: timestamp, - timeUpdated: timestamp, - inverseMass: 0, - friction: 0, - frictionStatic: 0, - restitution: 0, - slop: 0 - }; - - Pair.update(pair, collision, timestamp); - - return pair; - }; - - /** - * Updates a pair given a collision. - * @method update - * @param {pair} pair - * @param {collision} collision - * @param {number} timestamp - */ - Pair.update = function(pair, collision, timestamp) { - var contacts = pair.contacts, - supports = collision.supports, - activeContacts = pair.activeContacts, - parentA = collision.parentA, - parentB = collision.parentB, - parentAVerticesLength = parentA.vertices.length; - - pair.isActive = true; - pair.timeUpdated = timestamp; - pair.collision = collision; - pair.separation = collision.depth; - pair.inverseMass = parentA.inverseMass + parentB.inverseMass; - pair.friction = parentA.friction < parentB.friction ? parentA.friction : parentB.friction; - pair.frictionStatic = parentA.frictionStatic > parentB.frictionStatic ? parentA.frictionStatic : parentB.frictionStatic; - pair.restitution = parentA.restitution > parentB.restitution ? parentA.restitution : parentB.restitution; - pair.slop = parentA.slop > parentB.slop ? parentA.slop : parentB.slop; - - collision.pair = pair; - activeContacts.length = 0; - - for (var i = 0; i < supports.length; i++) { - var support = supports[i], - contactId = support.body === parentA ? support.index : parentAVerticesLength + support.index, - contact = contacts[contactId]; - - if (contact) { - activeContacts.push(contact); - } else { - activeContacts.push(contacts[contactId] = Contact.create(support)); - } - } - }; - - /** - * Set a pair as active or inactive. - * @method setActive - * @param {pair} pair - * @param {bool} isActive - * @param {number} timestamp - */ - Pair.setActive = function(pair, isActive, timestamp) { - if (isActive) { - pair.isActive = true; - pair.timeUpdated = timestamp; - } else { - pair.isActive = false; - pair.activeContacts.length = 0; - } - }; - - /** - * Get the id for the given pair. - * @method id - * @param {body} bodyA - * @param {body} bodyB - * @return {string} Unique pairId - */ - Pair.id = function(bodyA, bodyB) { - if (bodyA.id < bodyB.id) { - return 'A' + bodyA.id + 'B' + bodyB.id; - } else { - return 'A' + bodyB.id + 'B' + bodyA.id; - } - }; - -})(); - - -/***/ }), -/* 10 */ -/***/ (function(module, exports, __webpack_require__) { - -/** -* The `Matter.Constraint` module contains methods for creating and manipulating constraints. -* Constraints are used for specifying that a fixed distance must be maintained between two bodies (or a body and a fixed world-space position). -* The stiffness of constraints can be modified to create springs or elastic. -* -* See the included usage [examples](https://github.com/liabru/matter-js/tree/master/examples). -* -* @class Constraint -*/ - -var Constraint = {}; - -module.exports = Constraint; - -var Vertices = __webpack_require__(3); -var Vector = __webpack_require__(2); -var Sleeping = __webpack_require__(7); -var Bounds = __webpack_require__(1); -var Axes = __webpack_require__(11); -var Common = __webpack_require__(0); - -(function() { - - Constraint._warming = 0.4; - Constraint._torqueDampen = 1; - Constraint._minLength = 0.000001; - - /** - * Creates a new constraint. - * All properties have default values, and many are pre-calculated automatically based on other properties. - * To simulate a revolute constraint (or pin joint) set `length: 0` and a high `stiffness` value (e.g. `0.7` or above). - * If the constraint is unstable, try lowering the `stiffness` value and / or increasing `engine.constraintIterations`. - * For compound bodies, constraints must be applied to the parent body (not one of its parts). - * See the properties section below for detailed information on what you can pass via the `options` object. - * @method create - * @param {} options - * @return {constraint} constraint - */ - Constraint.create = function(options) { - var constraint = options; - - // if bodies defined but no points, use body centre - if (constraint.bodyA && !constraint.pointA) - constraint.pointA = { x: 0, y: 0 }; - if (constraint.bodyB && !constraint.pointB) - constraint.pointB = { x: 0, y: 0 }; - - // calculate static length using initial world space points - var initialPointA = constraint.bodyA ? Vector.add(constraint.bodyA.position, constraint.pointA) : constraint.pointA, - initialPointB = constraint.bodyB ? Vector.add(constraint.bodyB.position, constraint.pointB) : constraint.pointB, - length = Vector.magnitude(Vector.sub(initialPointA, initialPointB)); - - constraint.length = typeof constraint.length !== 'undefined' ? constraint.length : length; - - // option defaults - constraint.id = constraint.id || Common.nextId(); - constraint.label = constraint.label || 'Constraint'; - constraint.type = 'constraint'; - constraint.stiffness = constraint.stiffness || (constraint.length > 0 ? 1 : 0.7); - constraint.damping = constraint.damping || 0; - constraint.angularStiffness = constraint.angularStiffness || 0; - constraint.angleA = constraint.bodyA ? constraint.bodyA.angle : constraint.angleA; - constraint.angleB = constraint.bodyB ? constraint.bodyB.angle : constraint.angleB; - constraint.plugin = {}; - - // render - var render = { - visible: true, - lineWidth: 2, - strokeStyle: '#ffffff', - type: 'line', - anchors: true - }; - - if (constraint.length === 0 && constraint.stiffness > 0.1) { - render.type = 'pin'; - render.anchors = false; - } else if (constraint.stiffness < 0.9) { - render.type = 'spring'; - } - - constraint.render = Common.extend(render, constraint.render); - - return constraint; - }; - - /** - * Prepares for solving by constraint warming. - * @private - * @method preSolveAll - * @param {body[]} bodies - */ - Constraint.preSolveAll = function(bodies) { - for (var i = 0; i < bodies.length; i += 1) { - var body = bodies[i], - impulse = body.constraintImpulse; - - if (body.isStatic || (impulse.x === 0 && impulse.y === 0 && impulse.angle === 0)) { - continue; - } - - body.position.x += impulse.x; - body.position.y += impulse.y; - body.angle += impulse.angle; - } - }; - - /** - * Solves all constraints in a list of collisions. - * @private - * @method solveAll - * @param {constraint[]} constraints - * @param {number} delta - */ - Constraint.solveAll = function(constraints, delta) { - var timeScale = Common.clamp(delta / Common._baseDelta, 0, 1); - - // Solve fixed constraints first. - for (var i = 0; i < constraints.length; i += 1) { - var constraint = constraints[i], - fixedA = !constraint.bodyA || (constraint.bodyA && constraint.bodyA.isStatic), - fixedB = !constraint.bodyB || (constraint.bodyB && constraint.bodyB.isStatic); - - if (fixedA || fixedB) { - Constraint.solve(constraints[i], timeScale); - } - } - - // Solve free constraints last. - for (i = 0; i < constraints.length; i += 1) { - constraint = constraints[i]; - fixedA = !constraint.bodyA || (constraint.bodyA && constraint.bodyA.isStatic); - fixedB = !constraint.bodyB || (constraint.bodyB && constraint.bodyB.isStatic); - - if (!fixedA && !fixedB) { - Constraint.solve(constraints[i], timeScale); - } - } - }; - - /** - * Solves a distance constraint with Gauss-Siedel method. - * @private - * @method solve - * @param {constraint} constraint - * @param {number} timeScale - */ - Constraint.solve = function(constraint, timeScale) { - var bodyA = constraint.bodyA, - bodyB = constraint.bodyB, - pointA = constraint.pointA, - pointB = constraint.pointB; - - if (!bodyA && !bodyB) - return; - - // update reference angle - if (bodyA && !bodyA.isStatic) { - Vector.rotate(pointA, bodyA.angle - constraint.angleA, pointA); - constraint.angleA = bodyA.angle; - } - - // update reference angle - if (bodyB && !bodyB.isStatic) { - Vector.rotate(pointB, bodyB.angle - constraint.angleB, pointB); - constraint.angleB = bodyB.angle; - } - - var pointAWorld = pointA, - pointBWorld = pointB; - - if (bodyA) pointAWorld = Vector.add(bodyA.position, pointA); - if (bodyB) pointBWorld = Vector.add(bodyB.position, pointB); - - if (!pointAWorld || !pointBWorld) - return; - - var delta = Vector.sub(pointAWorld, pointBWorld), - currentLength = Vector.magnitude(delta); - - // prevent singularity - if (currentLength < Constraint._minLength) { - currentLength = Constraint._minLength; - } - - // solve distance constraint with Gauss-Siedel method - var difference = (currentLength - constraint.length) / currentLength, - isRigid = constraint.stiffness >= 1 || constraint.length === 0, - stiffness = isRigid ? constraint.stiffness * timeScale - : constraint.stiffness * timeScale * timeScale, - damping = constraint.damping * timeScale, - force = Vector.mult(delta, difference * stiffness), - massTotal = (bodyA ? bodyA.inverseMass : 0) + (bodyB ? bodyB.inverseMass : 0), - inertiaTotal = (bodyA ? bodyA.inverseInertia : 0) + (bodyB ? bodyB.inverseInertia : 0), - resistanceTotal = massTotal + inertiaTotal, - torque, - share, - normal, - normalVelocity, - relativeVelocity; - - if (damping > 0) { - var zero = Vector.create(); - normal = Vector.div(delta, currentLength); - - relativeVelocity = Vector.sub( - bodyB && Vector.sub(bodyB.position, bodyB.positionPrev) || zero, - bodyA && Vector.sub(bodyA.position, bodyA.positionPrev) || zero - ); - - normalVelocity = Vector.dot(normal, relativeVelocity); - } - - if (bodyA && !bodyA.isStatic) { - share = bodyA.inverseMass / massTotal; - - // keep track of applied impulses for post solving - bodyA.constraintImpulse.x -= force.x * share; - bodyA.constraintImpulse.y -= force.y * share; - - // apply forces - bodyA.position.x -= force.x * share; - bodyA.position.y -= force.y * share; - - // apply damping - if (damping > 0) { - bodyA.positionPrev.x -= damping * normal.x * normalVelocity * share; - bodyA.positionPrev.y -= damping * normal.y * normalVelocity * share; - } - - // apply torque - torque = (Vector.cross(pointA, force) / resistanceTotal) * Constraint._torqueDampen * bodyA.inverseInertia * (1 - constraint.angularStiffness); - bodyA.constraintImpulse.angle -= torque; - bodyA.angle -= torque; - } - - if (bodyB && !bodyB.isStatic) { - share = bodyB.inverseMass / massTotal; - - // keep track of applied impulses for post solving - bodyB.constraintImpulse.x += force.x * share; - bodyB.constraintImpulse.y += force.y * share; - - // apply forces - bodyB.position.x += force.x * share; - bodyB.position.y += force.y * share; - - // apply damping - if (damping > 0) { - bodyB.positionPrev.x += damping * normal.x * normalVelocity * share; - bodyB.positionPrev.y += damping * normal.y * normalVelocity * share; - } - - // apply torque - torque = (Vector.cross(pointB, force) / resistanceTotal) * Constraint._torqueDampen * bodyB.inverseInertia * (1 - constraint.angularStiffness); - bodyB.constraintImpulse.angle += torque; - bodyB.angle += torque; - } - - }; - - /** - * Performs body updates required after solving constraints. - * @private - * @method postSolveAll - * @param {body[]} bodies - */ - Constraint.postSolveAll = function(bodies) { - for (var i = 0; i < bodies.length; i++) { - var body = bodies[i], - impulse = body.constraintImpulse; - - if (body.isStatic || (impulse.x === 0 && impulse.y === 0 && impulse.angle === 0)) { - continue; - } - - Sleeping.set(body, false); - - // update geometry and reset - for (var j = 0; j < body.parts.length; j++) { - var part = body.parts[j]; - - Vertices.translate(part.vertices, impulse); - - if (j > 0) { - part.position.x += impulse.x; - part.position.y += impulse.y; - } - - if (impulse.angle !== 0) { - Vertices.rotate(part.vertices, impulse.angle, body.position); - Axes.rotate(part.axes, impulse.angle); - if (j > 0) { - Vector.rotateAbout(part.position, impulse.angle, body.position, part.position); - } - } - - Bounds.update(part.bounds, part.vertices, body.velocity); - } - - // dampen the cached impulse for warming next step - impulse.angle *= Constraint._warming; - impulse.x *= Constraint._warming; - impulse.y *= Constraint._warming; - } - }; - - /** - * Returns the world-space position of `constraint.pointA`, accounting for `constraint.bodyA`. - * @method pointAWorld - * @param {constraint} constraint - * @returns {vector} the world-space position - */ - Constraint.pointAWorld = function(constraint) { - return { - x: (constraint.bodyA ? constraint.bodyA.position.x : 0) - + (constraint.pointA ? constraint.pointA.x : 0), - y: (constraint.bodyA ? constraint.bodyA.position.y : 0) - + (constraint.pointA ? constraint.pointA.y : 0) - }; - }; - - /** - * Returns the world-space position of `constraint.pointB`, accounting for `constraint.bodyB`. - * @method pointBWorld - * @param {constraint} constraint - * @returns {vector} the world-space position - */ - Constraint.pointBWorld = function(constraint) { - return { - x: (constraint.bodyB ? constraint.bodyB.position.x : 0) - + (constraint.pointB ? constraint.pointB.x : 0), - y: (constraint.bodyB ? constraint.bodyB.position.y : 0) - + (constraint.pointB ? constraint.pointB.y : 0) - }; - }; - - /** - * Returns the current length of the constraint. - * This is the distance between both of the constraint's end points. - * See `constraint.length` for the target rest length. - * @method currentLength - * @param {constraint} constraint - * @returns {number} the current length - */ - Constraint.currentLength = function(constraint) { - var pointAX = (constraint.bodyA ? constraint.bodyA.position.x : 0) - + (constraint.pointA ? constraint.pointA.x : 0); - - var pointAY = (constraint.bodyA ? constraint.bodyA.position.y : 0) - + (constraint.pointA ? constraint.pointA.y : 0); - - var pointBX = (constraint.bodyB ? constraint.bodyB.position.x : 0) - + (constraint.pointB ? constraint.pointB.x : 0); - - var pointBY = (constraint.bodyB ? constraint.bodyB.position.y : 0) - + (constraint.pointB ? constraint.pointB.y : 0); - - var deltaX = pointAX - pointBX; - var deltaY = pointAY - pointBY; - - return Math.sqrt(deltaX * deltaX + deltaY * deltaY); - }; - - /* - * - * Properties Documentation - * - */ - - /** - * An integer `Number` uniquely identifying number generated in `Composite.create` by `Common.nextId`. - * - * @property id - * @type number - */ - - /** - * A `String` denoting the type of object. - * - * @property type - * @type string - * @default "constraint" - * @readOnly - */ - - /** - * An arbitrary `String` name to help the user identify and manage bodies. - * - * @property label - * @type string - * @default "Constraint" - */ - - /** - * 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 constraint should be rendered. - * - * @property render.visible - * @type boolean - * @default true - */ - - /** - * A `Number` that defines the line width to use when rendering the constraint outline. - * A value of `0` means no outline will be rendered. - * - * @property render.lineWidth - * @type number - * @default 2 - */ - - /** - * A `String` that defines the stroke style to use when rendering the constraint outline. - * 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 - */ - - /** - * A `String` that defines the constraint rendering type. - * The possible values are 'line', 'pin', 'spring'. - * An appropriate render type will be automatically chosen unless one is given in options. - * - * @property render.type - * @type string - * @default 'line' - */ - - /** - * A `Boolean` that defines if the constraint's anchor points should be rendered. - * - * @property render.anchors - * @type boolean - * @default true - */ - - /** - * The first possible `Body` that this constraint is attached to. - * - * @property bodyA - * @type body - * @default null - */ - - /** - * The second possible `Body` that this constraint is attached to. - * - * @property bodyB - * @type body - * @default null - */ - - /** - * A `Vector` that specifies the offset of the constraint from center of the `constraint.bodyA` if defined, otherwise a world-space position. - * - * @property pointA - * @type vector - * @default { x: 0, y: 0 } - */ - - /** - * A `Vector` that specifies the offset of the constraint from center of the `constraint.bodyB` if defined, otherwise a world-space position. - * - * @property pointB - * @type vector - * @default { x: 0, y: 0 } - */ - - /** - * A `Number` that specifies the stiffness of the constraint, i.e. the rate at which it returns to its resting `constraint.length`. - * A value of `1` means the constraint should be very stiff. - * A value of `0.2` means the constraint acts like a soft spring. - * - * @property stiffness - * @type number - * @default 1 - */ - - /** - * A `Number` that specifies the damping of the constraint, - * i.e. the amount of resistance applied to each body based on their velocities to limit the amount of oscillation. - * Damping will only be apparent when the constraint also has a very low `stiffness`. - * A value of `0.1` means the constraint will apply heavy damping, resulting in little to no oscillation. - * A value of `0` means the constraint will apply no damping. - * - * @property damping - * @type number - * @default 0 - */ - - /** - * A `Number` that specifies the target resting length of the constraint. - * It is calculated automatically in `Constraint.create` from initial positions of the `constraint.bodyA` and `constraint.bodyB`. - * - * @property length - * @type number - */ - - /** - * An object reserved for storing plugin-specific properties. - * - * @property plugin - * @type {} - */ - -})(); - - -/***/ }), -/* 11 */ -/***/ (function(module, exports, __webpack_require__) { - -/** -* The `Matter.Axes` module contains methods for creating and manipulating sets of axes. -* -* @class Axes -*/ - -var Axes = {}; - -module.exports = Axes; - -var Vector = __webpack_require__(2); -var Common = __webpack_require__(0); - -(function() { - - /** - * Creates a new set of axes from the given vertices. - * @method fromVertices - * @param {vertices} vertices - * @return {axes} A new axes from the given vertices - */ - Axes.fromVertices = function(vertices) { - var axes = {}; - - // find the unique axes, using edge normal gradients - for (var i = 0; i < vertices.length; i++) { - var j = (i + 1) % vertices.length, - normal = Vector.normalise({ - x: vertices[j].y - vertices[i].y, - y: vertices[i].x - vertices[j].x - }), - gradient = (normal.y === 0) ? Infinity : (normal.x / normal.y); - - // limit precision - gradient = gradient.toFixed(3).toString(); - axes[gradient] = normal; - } - - return Common.values(axes); - }; - - /** - * Rotates a set of axes by the given angle. - * @method rotate - * @param {axes} axes - * @param {number} angle - */ - Axes.rotate = function(axes, angle) { - if (angle === 0) - return; - - var cos = Math.cos(angle), - sin = Math.sin(angle); - - for (var i = 0; i < axes.length; i++) { - var axis = axes[i], - xx; - xx = axis.x * cos - axis.y * sin; - axis.y = axis.x * sin + axis.y * cos; - axis.x = xx; - } - }; - -})(); - - -/***/ }), -/* 12 */ -/***/ (function(module, exports, __webpack_require__) { - -/** -* The `Matter.Bodies` module contains factory methods for creating rigid body models -* with commonly used body configurations (such as rectangles, circles and other polygons). -* -* See the included usage [examples](https://github.com/liabru/matter-js/tree/master/examples). -* -* @class Bodies -*/ - -// TODO: true circle bodies - -var Bodies = {}; - -module.exports = Bodies; - -var Vertices = __webpack_require__(3); -var Common = __webpack_require__(0); -var Body = __webpack_require__(4); -var Bounds = __webpack_require__(1); -var Vector = __webpack_require__(2); - -(function() { - - /** - * Creates a new rigid body model with a rectangle hull. - * The options parameter is an object that specifies any properties you wish to override the defaults. - * See the properties section of the `Matter.Body` module for detailed information on what you can pass via the `options` object. - * @method rectangle - * @param {number} x - * @param {number} y - * @param {number} width - * @param {number} height - * @param {object} [options] - * @return {body} A new rectangle body - */ - Bodies.rectangle = function(x, y, width, height, options) { - options = options || {}; - - var rectangle = { - label: 'Rectangle Body', - position: { x: x, y: y }, - vertices: Vertices.fromPath('L 0 0 L ' + width + ' 0 L ' + width + ' ' + height + ' L 0 ' + height) - }; - - if (options.chamfer) { - var chamfer = options.chamfer; - rectangle.vertices = Vertices.chamfer(rectangle.vertices, chamfer.radius, - chamfer.quality, chamfer.qualityMin, chamfer.qualityMax); - delete options.chamfer; - } - - return Body.create(Common.extend({}, rectangle, options)); - }; - - /** - * Creates a new rigid body model with a trapezoid hull. - * The `slope` is parameterised as a fraction of `width` and must be < 1 to form a valid trapezoid. - * The options parameter is an object that specifies any properties you wish to override the defaults. - * See the properties section of the `Matter.Body` module for detailed information on what you can pass via the `options` object. - * @method trapezoid - * @param {number} x - * @param {number} y - * @param {number} width - * @param {number} height - * @param {number} slope Must be a number < 1. - * @param {object} [options] - * @return {body} A new trapezoid body - */ - Bodies.trapezoid = function(x, y, width, height, slope, options) { - options = options || {}; - - if (slope >= 1) { - Common.warn('Bodies.trapezoid: slope parameter must be < 1.'); - } - - slope *= 0.5; - var roof = (1 - (slope * 2)) * width; - - var x1 = width * slope, - x2 = x1 + roof, - x3 = x2 + x1, - verticesPath; - - if (slope < 0.5) { - verticesPath = 'L 0 0 L ' + x1 + ' ' + (-height) + ' L ' + x2 + ' ' + (-height) + ' L ' + x3 + ' 0'; - } else { - verticesPath = 'L 0 0 L ' + x2 + ' ' + (-height) + ' L ' + x3 + ' 0'; - } - - var trapezoid = { - label: 'Trapezoid Body', - position: { x: x, y: y }, - vertices: Vertices.fromPath(verticesPath) - }; - - if (options.chamfer) { - var chamfer = options.chamfer; - trapezoid.vertices = Vertices.chamfer(trapezoid.vertices, chamfer.radius, - chamfer.quality, chamfer.qualityMin, chamfer.qualityMax); - delete options.chamfer; - } - - return Body.create(Common.extend({}, trapezoid, options)); - }; - - /** - * Creates a new rigid body model with a circle hull. - * The options parameter is an object that specifies any properties you wish to override the defaults. - * See the properties section of the `Matter.Body` module for detailed information on what you can pass via the `options` object. - * @method circle - * @param {number} x - * @param {number} y - * @param {number} radius - * @param {object} [options] - * @param {number} [maxSides] - * @return {body} A new circle body - */ - Bodies.circle = function(x, y, radius, options, maxSides) { - options = options || {}; - - var circle = { - label: 'Circle Body', - circleRadius: radius - }; - - // approximate circles with polygons until true circles implemented in SAT - maxSides = maxSides || 25; - var sides = Math.ceil(Math.max(10, Math.min(maxSides, radius))); - - // optimisation: always use even number of sides (half the number of unique axes) - if (sides % 2 === 1) - sides += 1; - - return Bodies.polygon(x, y, sides, radius, Common.extend({}, circle, options)); - }; - - /** - * Creates a new rigid body model with a regular polygon hull with the given number of sides. - * The options parameter is an object that specifies any properties you wish to override the defaults. - * See the properties section of the `Matter.Body` module for detailed information on what you can pass via the `options` object. - * @method polygon - * @param {number} x - * @param {number} y - * @param {number} sides - * @param {number} radius - * @param {object} [options] - * @return {body} A new regular polygon body - */ - Bodies.polygon = function(x, y, sides, radius, options) { - options = options || {}; - - if (sides < 3) - return Bodies.circle(x, y, radius, options); - - var theta = 2 * Math.PI / sides, - path = '', - offset = theta * 0.5; - - for (var i = 0; i < sides; i += 1) { - var angle = offset + (i * theta), - xx = Math.cos(angle) * radius, - yy = Math.sin(angle) * radius; - - path += 'L ' + xx.toFixed(3) + ' ' + yy.toFixed(3) + ' '; - } - - var polygon = { - label: 'Polygon Body', - position: { x: x, y: y }, - vertices: Vertices.fromPath(path) - }; - - if (options.chamfer) { - var chamfer = options.chamfer; - polygon.vertices = Vertices.chamfer(polygon.vertices, chamfer.radius, - chamfer.quality, chamfer.qualityMin, chamfer.qualityMax); - delete options.chamfer; - } - - return Body.create(Common.extend({}, polygon, options)); - }; - - /** - * Utility to create a compound body based on set(s) of vertices. - * - * _Note:_ To optionally enable automatic concave vertices decomposition the [poly-decomp](https://github.com/schteppe/poly-decomp.js) - * package must be first installed and provided see `Common.setDecomp`, otherwise the convex hull of each vertex set will be used. - * - * The resulting vertices are reorientated about their centre of mass, - * and offset such that `body.position` corresponds to this point. - * - * The resulting offset may be found if needed by subtracting `body.bounds` from the original input bounds. - * To later move the centre of mass see `Body.setCentre`. - * - * Note that automatic conconcave decomposition results are not always optimal. - * For best results, simplify the input vertices as much as possible first. - * By default this function applies some addtional simplification to help. - * - * Some outputs may also require further manual processing afterwards to be robust. - * In particular some parts may need to be overlapped to avoid collision gaps. - * Thin parts and sharp points should be avoided or removed where possible. - * - * The options parameter object specifies any `Matter.Body` properties you wish to override the defaults. - * - * See the properties section of the `Matter.Body` module for detailed information on what you can pass via the `options` object. - * @method fromVertices - * @param {number} x - * @param {number} y - * @param {array} vertexSets One or more arrays of vertex points e.g. `[[{ x: 0, y: 0 }...], ...]`. - * @param {object} [options] The body options. - * @param {bool} [flagInternal=false] Optionally marks internal edges with `isInternal`. - * @param {number} [removeCollinear=0.01] Threshold when simplifying vertices along the same edge. - * @param {number} [minimumArea=10] Threshold when removing small parts. - * @param {number} [removeDuplicatePoints=0.01] Threshold when simplifying nearby vertices. - * @return {body} - */ - Bodies.fromVertices = function(x, y, vertexSets, options, flagInternal, removeCollinear, minimumArea, removeDuplicatePoints) { - var decomp = Common.getDecomp(), - canDecomp, - body, - parts, - isConvex, - isConcave, - vertices, - i, - j, - k, - v, - z; - - // check decomp is as expected - canDecomp = Boolean(decomp && decomp.quickDecomp); - - options = options || {}; - parts = []; - - flagInternal = typeof flagInternal !== 'undefined' ? flagInternal : false; - removeCollinear = typeof removeCollinear !== 'undefined' ? removeCollinear : 0.01; - minimumArea = typeof minimumArea !== 'undefined' ? minimumArea : 10; - removeDuplicatePoints = typeof removeDuplicatePoints !== 'undefined' ? removeDuplicatePoints : 0.01; - - // ensure vertexSets is an array of arrays - if (!Common.isArray(vertexSets[0])) { - vertexSets = [vertexSets]; - } - - for (v = 0; v < vertexSets.length; v += 1) { - vertices = vertexSets[v]; - isConvex = Vertices.isConvex(vertices); - isConcave = !isConvex; - - if (isConcave && !canDecomp) { - Common.warnOnce( - 'Bodies.fromVertices: Install the \'poly-decomp\' library and use Common.setDecomp or provide \'decomp\' as a global to decompose concave vertices.' - ); - } - - if (isConvex || !canDecomp) { - if (isConvex) { - vertices = Vertices.clockwiseSort(vertices); - } else { - // fallback to convex hull when decomposition is not possible - vertices = Vertices.hull(vertices); - } - - parts.push({ - position: { x: x, y: y }, - vertices: vertices - }); - } else { - // initialise a decomposition - var concave = vertices.map(function(vertex) { - return [vertex.x, vertex.y]; - }); - - // vertices are concave and simple, we can decompose into parts - decomp.makeCCW(concave); - if (removeCollinear !== false) - decomp.removeCollinearPoints(concave, removeCollinear); - if (removeDuplicatePoints !== false && decomp.removeDuplicatePoints) - decomp.removeDuplicatePoints(concave, removeDuplicatePoints); - - // use the quick decomposition algorithm (Bayazit) - var decomposed = decomp.quickDecomp(concave); - - // for each decomposed chunk - for (i = 0; i < decomposed.length; i++) { - var chunk = decomposed[i]; - - // convert vertices into the correct structure - var chunkVertices = chunk.map(function(vertices) { - return { - x: vertices[0], - y: vertices[1] - }; - }); - - // skip small chunks - if (minimumArea > 0 && Vertices.area(chunkVertices) < minimumArea) - continue; - - // create a compound part - parts.push({ - position: Vertices.centre(chunkVertices), - vertices: chunkVertices - }); - } - } - } - - // create body parts - for (i = 0; i < parts.length; i++) { - parts[i] = Body.create(Common.extend(parts[i], options)); - } - - // flag internal edges (coincident part edges) - if (flagInternal) { - var coincident_max_dist = 5; - - for (i = 0; i < parts.length; i++) { - var partA = parts[i]; - - for (j = i + 1; j < parts.length; j++) { - var partB = parts[j]; - - if (Bounds.overlaps(partA.bounds, partB.bounds)) { - var pav = partA.vertices, - pbv = partB.vertices; - - // iterate vertices of both parts - for (k = 0; k < partA.vertices.length; k++) { - for (z = 0; z < partB.vertices.length; z++) { - // find distances between the vertices - var da = Vector.magnitudeSquared(Vector.sub(pav[(k + 1) % pav.length], pbv[z])), - db = Vector.magnitudeSquared(Vector.sub(pav[k], pbv[(z + 1) % pbv.length])); - - // if both vertices are very close, consider the edge concident (internal) - if (da < coincident_max_dist && db < coincident_max_dist) { - pav[k].isInternal = true; - pbv[z].isInternal = true; - } - } - } - - } - } - } - } - - if (parts.length > 1) { - // create the parent body to be returned, that contains generated compound parts - body = Body.create(Common.extend({ parts: parts.slice(0) }, options)); - - // offset such that body.position is at the centre off mass - Body.setPosition(body, { x: x, y: y }); - - return body; - } else { - return parts[0]; - } - }; - -})(); - - -/***/ }), -/* 13 */ -/***/ (function(module, exports, __webpack_require__) { - -/** -* The `Matter.Detector` module contains methods for efficiently detecting collisions between a list of bodies using a broadphase algorithm. -* -* @class Detector -*/ - -var Detector = {}; - -module.exports = Detector; - -var Common = __webpack_require__(0); -var Collision = __webpack_require__(8); - -(function() { - - /** - * Creates a new collision detector. - * @method create - * @param {} options - * @return {detector} A new collision detector - */ - Detector.create = function(options) { - var defaults = { - bodies: [], - pairs: null - }; - - return Common.extend(defaults, options); - }; - - /** - * Sets the list of bodies in the detector. - * @method setBodies - * @param {detector} detector - * @param {body[]} bodies - */ - Detector.setBodies = function(detector, bodies) { - detector.bodies = bodies.slice(0); - }; - - /** - * Clears the detector including its list of bodies. - * @method clear - * @param {detector} detector - */ - Detector.clear = function(detector) { - detector.bodies = []; - }; - - /** - * Efficiently finds all collisions among all the bodies in `detector.bodies` using a broadphase algorithm. - * - * _Note:_ The specific ordering of collisions returned is not guaranteed between releases and may change for performance reasons. - * If a specific ordering is required then apply a sort to the resulting array. - * @method collisions - * @param {detector} detector - * @return {collision[]} collisions - */ - Detector.collisions = function(detector) { - var collisions = [], - pairs = detector.pairs, - bodies = detector.bodies, - bodiesLength = bodies.length, - canCollide = Detector.canCollide, - collides = Collision.collides, - i, - j; - - bodies.sort(Detector._compareBoundsX); - - for (i = 0; i < bodiesLength; i++) { - var bodyA = bodies[i], - boundsA = bodyA.bounds, - boundXMax = bodyA.bounds.max.x, - boundYMax = bodyA.bounds.max.y, - boundYMin = bodyA.bounds.min.y, - bodyAStatic = bodyA.isStatic || bodyA.isSleeping, - partsALength = bodyA.parts.length, - partsASingle = partsALength === 1; - - for (j = i + 1; j < bodiesLength; j++) { - var bodyB = bodies[j], - boundsB = bodyB.bounds; - - if (boundsB.min.x > boundXMax) { - break; - } - - if (boundYMax < boundsB.min.y || boundYMin > boundsB.max.y) { - continue; - } - - if (bodyAStatic && (bodyB.isStatic || bodyB.isSleeping)) { - continue; - } - - if (!canCollide(bodyA.collisionFilter, bodyB.collisionFilter)) { - continue; - } - - var partsBLength = bodyB.parts.length; - - if (partsASingle && partsBLength === 1) { - var collision = collides(bodyA, bodyB, pairs); - - if (collision) { - collisions.push(collision); - } - } else { - var partsAStart = partsALength > 1 ? 1 : 0, - partsBStart = partsBLength > 1 ? 1 : 0; - - for (var k = partsAStart; k < partsALength; k++) { - var partA = bodyA.parts[k], - boundsA = partA.bounds; - - for (var z = partsBStart; z < partsBLength; z++) { - var partB = bodyB.parts[z], - boundsB = partB.bounds; - - if (boundsA.min.x > boundsB.max.x || boundsA.max.x < boundsB.min.x - || boundsA.max.y < boundsB.min.y || boundsA.min.y > boundsB.max.y) { - continue; - } - - var collision = collides(partA, partB, pairs); - - if (collision) { - collisions.push(collision); - } - } - } - } - } - } - - return collisions; - }; - - /** - * Returns `true` if both supplied collision filters will allow a collision to occur. - * See `body.collisionFilter` for more information. - * @method canCollide - * @param {} filterA - * @param {} filterB - * @return {bool} `true` if collision can occur - */ - Detector.canCollide = function(filterA, filterB) { - if (filterA.group === filterB.group && filterA.group !== 0) - return filterA.group > 0; - - return (filterA.mask & filterB.category) !== 0 && (filterB.mask & filterA.category) !== 0; - }; - - /** - * The comparison function used in the broadphase algorithm. - * Returns the signed delta of the bodies bounds on the x-axis. - * @private - * @method _sortCompare - * @param {body} bodyA - * @param {body} bodyB - * @return {number} The signed delta used for sorting - */ - Detector._compareBoundsX = function(bodyA, bodyB) { - return bodyA.bounds.min.x - bodyB.bounds.min.x; - }; - - /* - * - * Properties Documentation - * - */ - - /** - * The array of `Matter.Body` between which the detector finds collisions. - * - * _Note:_ The order of bodies in this array _is not fixed_ and will be continually managed by the detector. - * @property bodies - * @type body[] - * @default [] - */ - - /** - * Optional. A `Matter.Pairs` object from which previous collision objects may be reused. Intended for internal `Matter.Engine` usage. - * @property pairs - * @type {pairs|null} - * @default null - */ - -})(); - - -/***/ }), -/* 14 */ -/***/ (function(module, exports, __webpack_require__) { - -/** -* The `Matter.Mouse` module contains methods for creating and manipulating mouse inputs. -* -* @class Mouse -*/ - -var Mouse = {}; - -module.exports = Mouse; - -var Common = __webpack_require__(0); - -(function() { - - /** - * Creates a mouse input. - * @method create - * @param {HTMLElement} element - * @return {mouse} A new mouse - */ - Mouse.create = function(element) { - var mouse = {}; - - if (!element) { - Common.log('Mouse.create: element was undefined, defaulting to document.body', 'warn'); - } - - mouse.element = element || document.body; - mouse.absolute = { x: 0, y: 0 }; - mouse.position = { x: 0, y: 0 }; - mouse.mousedownPosition = { x: 0, y: 0 }; - mouse.mouseupPosition = { x: 0, y: 0 }; - mouse.offset = { x: 0, y: 0 }; - mouse.scale = { x: 1, y: 1 }; - mouse.wheelDelta = 0; - mouse.button = -1; - mouse.pixelRatio = parseInt(mouse.element.getAttribute('data-pixel-ratio'), 10) || 1; - - mouse.sourceEvents = { - mousemove: null, - mousedown: null, - mouseup: null, - mousewheel: null - }; - - mouse.mousemove = function(event) { - var position = Mouse._getRelativeMousePosition(event, mouse.element, mouse.pixelRatio), - touches = event.changedTouches; - - if (touches) { - mouse.button = 0; - event.preventDefault(); - } - - mouse.absolute.x = position.x; - mouse.absolute.y = position.y; - mouse.position.x = mouse.absolute.x * mouse.scale.x + mouse.offset.x; - mouse.position.y = mouse.absolute.y * mouse.scale.y + mouse.offset.y; - mouse.sourceEvents.mousemove = event; - }; - - mouse.mousedown = function(event) { - var position = Mouse._getRelativeMousePosition(event, mouse.element, mouse.pixelRatio), - touches = event.changedTouches; - - if (touches) { - mouse.button = 0; - event.preventDefault(); - } else { - mouse.button = event.button; - } - - mouse.absolute.x = position.x; - mouse.absolute.y = position.y; - mouse.position.x = mouse.absolute.x * mouse.scale.x + mouse.offset.x; - mouse.position.y = mouse.absolute.y * mouse.scale.y + mouse.offset.y; - mouse.mousedownPosition.x = mouse.position.x; - mouse.mousedownPosition.y = mouse.position.y; - mouse.sourceEvents.mousedown = event; - }; - - mouse.mouseup = function(event) { - var position = Mouse._getRelativeMousePosition(event, mouse.element, mouse.pixelRatio), - touches = event.changedTouches; - - if (touches) { - event.preventDefault(); - } - - mouse.button = -1; - mouse.absolute.x = position.x; - mouse.absolute.y = position.y; - mouse.position.x = mouse.absolute.x * mouse.scale.x + mouse.offset.x; - mouse.position.y = mouse.absolute.y * mouse.scale.y + mouse.offset.y; - mouse.mouseupPosition.x = mouse.position.x; - mouse.mouseupPosition.y = mouse.position.y; - mouse.sourceEvents.mouseup = event; - }; - - mouse.mousewheel = function(event) { - mouse.wheelDelta = Math.max(-1, Math.min(1, event.wheelDelta || -event.detail)); - event.preventDefault(); - mouse.sourceEvents.mousewheel = event; - }; - - Mouse.setElement(mouse, mouse.element); - - return mouse; - }; - - /** - * Sets the element the mouse is bound to (and relative to). - * @method setElement - * @param {mouse} mouse - * @param {HTMLElement} element - */ - Mouse.setElement = function(mouse, element) { - mouse.element = element; - - element.addEventListener('mousemove', mouse.mousemove, { passive: true }); - element.addEventListener('mousedown', mouse.mousedown, { passive: true }); - element.addEventListener('mouseup', mouse.mouseup, { passive: true }); - - element.addEventListener('wheel', mouse.mousewheel, { passive: false }); - - element.addEventListener('touchmove', mouse.mousemove, { passive: false }); - element.addEventListener('touchstart', mouse.mousedown, { passive: false }); - element.addEventListener('touchend', mouse.mouseup, { passive: false }); - }; - - /** - * Clears all captured source events. - * @method clearSourceEvents - * @param {mouse} mouse - */ - Mouse.clearSourceEvents = function(mouse) { - mouse.sourceEvents.mousemove = null; - mouse.sourceEvents.mousedown = null; - mouse.sourceEvents.mouseup = null; - mouse.sourceEvents.mousewheel = null; - mouse.wheelDelta = 0; - }; - - /** - * Sets the mouse position offset. - * @method setOffset - * @param {mouse} mouse - * @param {vector} offset - */ - Mouse.setOffset = function(mouse, offset) { - mouse.offset.x = offset.x; - mouse.offset.y = offset.y; - mouse.position.x = mouse.absolute.x * mouse.scale.x + mouse.offset.x; - mouse.position.y = mouse.absolute.y * mouse.scale.y + mouse.offset.y; - }; - - /** - * Sets the mouse position scale. - * @method setScale - * @param {mouse} mouse - * @param {vector} scale - */ - Mouse.setScale = function(mouse, scale) { - mouse.scale.x = scale.x; - mouse.scale.y = scale.y; - mouse.position.x = mouse.absolute.x * mouse.scale.x + mouse.offset.x; - mouse.position.y = mouse.absolute.y * mouse.scale.y + mouse.offset.y; - }; - - /** - * Gets the mouse position relative to an element given a screen pixel ratio. - * @method _getRelativeMousePosition - * @private - * @param {} event - * @param {} element - * @param {number} pixelRatio - * @return {} - */ - Mouse._getRelativeMousePosition = function(event, element, pixelRatio) { - var elementBounds = element.getBoundingClientRect(), - rootNode = (document.documentElement || document.body.parentNode || document.body), - scrollX = (window.pageXOffset !== undefined) ? window.pageXOffset : rootNode.scrollLeft, - scrollY = (window.pageYOffset !== undefined) ? window.pageYOffset : rootNode.scrollTop, - touches = event.changedTouches, - x, y; - - if (touches) { - x = touches[0].pageX - elementBounds.left - scrollX; - y = touches[0].pageY - elementBounds.top - scrollY; - } else { - x = event.pageX - elementBounds.left - scrollX; - y = event.pageY - elementBounds.top - scrollY; - } - - return { - x: x / (element.clientWidth / (element.width || element.clientWidth) * pixelRatio), - y: y / (element.clientHeight / (element.height || element.clientHeight) * pixelRatio) - }; - }; - -})(); - - -/***/ }), -/* 15 */ -/***/ (function(module, exports, __webpack_require__) { - -/** -* The `Matter.Plugin` module contains functions for registering and installing plugins on modules. -* -* @class Plugin -*/ - -var Plugin = {}; - -module.exports = Plugin; - -var Common = __webpack_require__(0); - -(function() { - - Plugin._registry = {}; - - /** - * Registers a plugin object so it can be resolved later by name. - * @method register - * @param plugin {} The plugin to register. - * @return {object} The plugin. - */ - Plugin.register = function(plugin) { - if (!Plugin.isPlugin(plugin)) { - Common.warn('Plugin.register:', Plugin.toString(plugin), 'does not implement all required fields.'); - } - - if (plugin.name in Plugin._registry) { - var registered = Plugin._registry[plugin.name], - pluginVersion = Plugin.versionParse(plugin.version).number, - registeredVersion = Plugin.versionParse(registered.version).number; - - if (pluginVersion > registeredVersion) { - Common.warn('Plugin.register:', Plugin.toString(registered), 'was upgraded to', Plugin.toString(plugin)); - Plugin._registry[plugin.name] = plugin; - } else if (pluginVersion < registeredVersion) { - Common.warn('Plugin.register:', Plugin.toString(registered), 'can not be downgraded to', Plugin.toString(plugin)); - } else if (plugin !== registered) { - Common.warn('Plugin.register:', Plugin.toString(plugin), 'is already registered to different plugin object'); - } - } else { - Plugin._registry[plugin.name] = plugin; - } - - return plugin; - }; - - /** - * Resolves a dependency to a plugin object from the registry if it exists. - * The `dependency` may contain a version, but only the name matters when resolving. - * @method resolve - * @param dependency {string} The dependency. - * @return {object} The plugin if resolved, otherwise `undefined`. - */ - Plugin.resolve = function(dependency) { - return Plugin._registry[Plugin.dependencyParse(dependency).name]; - }; - - /** - * Returns a pretty printed plugin name and version. - * @method toString - * @param plugin {} The plugin. - * @return {string} Pretty printed plugin name and version. - */ - Plugin.toString = function(plugin) { - return typeof plugin === 'string' ? plugin : (plugin.name || 'anonymous') + '@' + (plugin.version || plugin.range || '0.0.0'); - }; - - /** - * Returns `true` if the object meets the minimum standard to be considered a plugin. - * This means it must define the following properties: - * - `name` - * - `version` - * - `install` - * @method isPlugin - * @param obj {} The obj to test. - * @return {boolean} `true` if the object can be considered a plugin otherwise `false`. - */ - Plugin.isPlugin = function(obj) { - return obj && obj.name && obj.version && obj.install; - }; - - /** - * Returns `true` if a plugin with the given `name` been installed on `module`. - * @method isUsed - * @param module {} The module. - * @param name {string} The plugin name. - * @return {boolean} `true` if a plugin with the given `name` been installed on `module`, otherwise `false`. - */ - Plugin.isUsed = function(module, name) { - return module.used.indexOf(name) > -1; - }; - - /** - * Returns `true` if `plugin.for` is applicable to `module` by comparing against `module.name` and `module.version`. - * If `plugin.for` is not specified then it is assumed to be applicable. - * The value of `plugin.for` is a string of the format `'module-name'` or `'module-name@version'`. - * @method isFor - * @param plugin {} The plugin. - * @param module {} The module. - * @return {boolean} `true` if `plugin.for` is applicable to `module`, otherwise `false`. - */ - Plugin.isFor = function(plugin, module) { - var parsed = plugin.for && Plugin.dependencyParse(plugin.for); - return !plugin.for || (module.name === parsed.name && Plugin.versionSatisfies(module.version, parsed.range)); - }; - - /** - * Installs the plugins by calling `plugin.install` on each plugin specified in `plugins` if passed, otherwise `module.uses`. - * For installing plugins on `Matter` see the convenience function `Matter.use`. - * Plugins may be specified either by their name or a reference to the plugin object. - * Plugins themselves may specify further dependencies, but each plugin is installed only once. - * Order is important, a topological sort is performed to find the best resulting order of installation. - * This sorting attempts to satisfy every dependency's requested ordering, but may not be exact in all cases. - * This function logs the resulting status of each dependency in the console, along with any warnings. - * - A green tick ✅ indicates a dependency was resolved and installed. - * - An orange diamond 🔶 indicates a dependency was resolved but a warning was thrown for it or one if its dependencies. - * - A red cross ❌ indicates a dependency could not be resolved. - * Avoid calling this function multiple times on the same module unless you intend to manually control installation order. - * @method use - * @param module {} The module install plugins on. - * @param [plugins=module.uses] {} The plugins to install on module (optional, defaults to `module.uses`). - */ - Plugin.use = function(module, plugins) { - module.uses = (module.uses || []).concat(plugins || []); - - if (module.uses.length === 0) { - Common.warn('Plugin.use:', Plugin.toString(module), 'does not specify any dependencies to install.'); - return; - } - - var dependencies = Plugin.dependencies(module), - sortedDependencies = Common.topologicalSort(dependencies), - status = []; - - for (var i = 0; i < sortedDependencies.length; i += 1) { - if (sortedDependencies[i] === module.name) { - continue; - } - - var plugin = Plugin.resolve(sortedDependencies[i]); - - if (!plugin) { - status.push('❌ ' + sortedDependencies[i]); - continue; - } - - if (Plugin.isUsed(module, plugin.name)) { - continue; - } - - if (!Plugin.isFor(plugin, module)) { - Common.warn('Plugin.use:', Plugin.toString(plugin), 'is for', plugin.for, 'but installed on', Plugin.toString(module) + '.'); - plugin._warned = true; - } - - if (plugin.install) { - plugin.install(module); - } else { - Common.warn('Plugin.use:', Plugin.toString(plugin), 'does not specify an install function.'); - plugin._warned = true; - } - - if (plugin._warned) { - status.push('🔶 ' + Plugin.toString(plugin)); - delete plugin._warned; - } else { - status.push('✅ ' + Plugin.toString(plugin)); - } - - module.used.push(plugin.name); - } - - if (status.length > 0) { - Common.info(status.join(' ')); - } - }; - - /** - * Recursively finds all of a module's dependencies and returns a flat dependency graph. - * @method dependencies - * @param module {} The module. - * @return {object} A dependency graph. - */ - Plugin.dependencies = function(module, tracked) { - var parsedBase = Plugin.dependencyParse(module), - name = parsedBase.name; - - tracked = tracked || {}; - - if (name in tracked) { - return; - } - - module = Plugin.resolve(module) || module; - - tracked[name] = Common.map(module.uses || [], function(dependency) { - if (Plugin.isPlugin(dependency)) { - Plugin.register(dependency); - } - - var parsed = Plugin.dependencyParse(dependency), - resolved = Plugin.resolve(dependency); - - if (resolved && !Plugin.versionSatisfies(resolved.version, parsed.range)) { - Common.warn( - 'Plugin.dependencies:', Plugin.toString(resolved), 'does not satisfy', - Plugin.toString(parsed), 'used by', Plugin.toString(parsedBase) + '.' - ); - - resolved._warned = true; - module._warned = true; - } else if (!resolved) { - Common.warn( - 'Plugin.dependencies:', Plugin.toString(dependency), 'used by', - Plugin.toString(parsedBase), 'could not be resolved.' - ); - - module._warned = true; - } - - return parsed.name; - }); - - for (var i = 0; i < tracked[name].length; i += 1) { - Plugin.dependencies(tracked[name][i], tracked); - } - - return tracked; - }; - - /** - * Parses a dependency string into its components. - * The `dependency` is a string of the format `'module-name'` or `'module-name@version'`. - * See documentation for `Plugin.versionParse` for a description of the format. - * This function can also handle dependencies that are already resolved (e.g. a module object). - * @method dependencyParse - * @param dependency {string} The dependency of the format `'module-name'` or `'module-name@version'`. - * @return {object} The dependency parsed into its components. - */ - Plugin.dependencyParse = function(dependency) { - if (Common.isString(dependency)) { - var pattern = /^[\w-]+(@(\*|[\^~]?\d+\.\d+\.\d+(-[0-9A-Za-z-+]+)?))?$/; - - if (!pattern.test(dependency)) { - Common.warn('Plugin.dependencyParse:', dependency, 'is not a valid dependency string.'); - } - - return { - name: dependency.split('@')[0], - range: dependency.split('@')[1] || '*' - }; - } - - return { - name: dependency.name, - range: dependency.range || dependency.version - }; - }; - - /** - * Parses a version string into its components. - * Versions are strictly of the format `x.y.z` (as in [semver](http://semver.org/)). - * Versions may optionally have a prerelease tag in the format `x.y.z-alpha`. - * Ranges are a strict subset of [npm ranges](https://docs.npmjs.com/misc/semver#advanced-range-syntax). - * Only the following range types are supported: - * - Tilde ranges e.g. `~1.2.3` - * - Caret ranges e.g. `^1.2.3` - * - Greater than ranges e.g. `>1.2.3` - * - Greater than or equal ranges e.g. `>=1.2.3` - * - Exact version e.g. `1.2.3` - * - Any version `*` - * @method versionParse - * @param range {string} The version string. - * @return {object} The version range parsed into its components. - */ - Plugin.versionParse = function(range) { - var pattern = /^(\*)|(\^|~|>=|>)?\s*((\d+)\.(\d+)\.(\d+))(-[0-9A-Za-z-+]+)?$/; - - if (!pattern.test(range)) { - Common.warn('Plugin.versionParse:', range, 'is not a valid version or range.'); - } - - var parts = pattern.exec(range); - var major = Number(parts[4]); - var minor = Number(parts[5]); - var patch = Number(parts[6]); - - return { - isRange: Boolean(parts[1] || parts[2]), - version: parts[3], - range: range, - operator: parts[1] || parts[2] || '', - major: major, - minor: minor, - patch: patch, - parts: [major, minor, patch], - prerelease: parts[7], - number: major * 1e8 + minor * 1e4 + patch - }; - }; - - /** - * Returns `true` if `version` satisfies the given `range`. - * See documentation for `Plugin.versionParse` for a description of the format. - * If a version or range is not specified, then any version (`*`) is assumed to satisfy. - * @method versionSatisfies - * @param version {string} The version string. - * @param range {string} The range string. - * @return {boolean} `true` if `version` satisfies `range`, otherwise `false`. - */ - Plugin.versionSatisfies = function(version, range) { - range = range || '*'; - - var r = Plugin.versionParse(range), - v = Plugin.versionParse(version); - - if (r.isRange) { - if (r.operator === '*' || version === '*') { - return true; - } - - if (r.operator === '>') { - return v.number > r.number; - } - - if (r.operator === '>=') { - return v.number >= r.number; - } - - if (r.operator === '~') { - return v.major === r.major && v.minor === r.minor && v.patch >= r.patch; - } - - if (r.operator === '^') { - if (r.major > 0) { - return v.major === r.major && v.number >= r.number; - } - - if (r.minor > 0) { - return v.minor === r.minor && v.patch >= r.patch; - } - - return v.patch === r.patch; - } - } - - return version === range || version === '*'; - }; - -})(); - - -/***/ }), -/* 16 */ -/***/ (function(module, exports) { - -/** -* The `Matter.Contact` module contains methods for creating and manipulating collision contacts. -* -* @class Contact -*/ - -var Contact = {}; - -module.exports = Contact; - -(function() { - - /** - * Creates a new contact. - * @method create - * @param {vertex} vertex - * @return {contact} A new contact - */ - Contact.create = function(vertex) { - return { - vertex: vertex, - normalImpulse: 0, - tangentImpulse: 0 - }; - }; - -})(); - - -/***/ }), -/* 17 */ -/***/ (function(module, exports, __webpack_require__) { - -/** -* 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 Sleeping = __webpack_require__(7); -var Resolver = __webpack_require__(18); -var Detector = __webpack_require__(13); -var Pairs = __webpack_require__(19); -var Events = __webpack_require__(5); -var Composite = __webpack_require__(6); -var Constraint = __webpack_require__(10); -var Common = __webpack_require__(0); -var Body = __webpack_require__(4); - -(function() { - - Engine._deltaMax = 1000 / 60; - - /** - * 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(options) { - options = options || {}; - - var defaults = { - positionIterations: 6, - velocityIterations: 4, - constraintIterations: 2, - enableSleeping: false, - events: [], - plugin: {}, - gravity: { - x: 0, - y: 1, - scale: 0.001 - }, - timing: { - timestamp: 0, - timeScale: 1, - lastDelta: 0, - lastElapsed: 0, - lastUpdatesPerFrame: 0 - } - }; - - var engine = Common.extend(defaults, options); - - engine.world = options.world || Composite.create({ label: 'World' }); - engine.pairs = options.pairs || Pairs.create(); - engine.detector = options.detector || Detector.create(); - - // for temporary back compatibility only - engine.grid = { buckets: [] }; - engine.world.gravity = engine.gravity; - engine.broadphase = engine.grid; - engine.metrics = {}; - - return engine; - }; - - /** - * Moves the simulation forward in time by `delta` milliseconds. - * Triggers `beforeUpdate`, `beforeSolve` and `afterUpdate` events. - * Triggers `collisionStart`, `collisionActive` and `collisionEnd` events. - * @method update - * @param {engine} engine - * @param {number} [delta=16.666] - */ - Engine.update = function(engine, delta) { - var startTime = Common.now(); - - var world = engine.world, - detector = engine.detector, - pairs = engine.pairs, - timing = engine.timing, - timestamp = timing.timestamp, - i; - - // warn if high delta - if (delta > Engine._deltaMax) { - Common.warnOnce( - 'Matter.Engine.update: delta argument is recommended to be less than or equal to', Engine._deltaMax.toFixed(3), 'ms.' - ); - } - - delta = typeof delta !== 'undefined' ? delta : Common._baseDelta; - delta *= timing.timeScale; - - // increment timestamp - timing.timestamp += delta; - timing.lastDelta = delta; - - // create an event object - var event = { - timestamp: timing.timestamp, - delta: delta - }; - - Events.trigger(engine, 'beforeUpdate', event); - - // get all bodies and all constraints in the world - var allBodies = Composite.allBodies(world), - allConstraints = Composite.allConstraints(world); - - // if the world has changed - if (world.isModified) { - // update the detector bodies - Detector.setBodies(detector, allBodies); - - // reset all composite modified flags - Composite.setModified(world, false, false, true); - } - - // update sleeping if enabled - if (engine.enableSleeping) - Sleeping.update(allBodies, delta); - - // apply gravity to all bodies - Engine._bodiesApplyGravity(allBodies, engine.gravity); - - // update all body position and rotation by integration - if (delta > 0) { - Engine._bodiesUpdate(allBodies, delta); - } - - Events.trigger(engine, 'beforeSolve', event); - - // update all constraints (first pass) - Constraint.preSolveAll(allBodies); - for (i = 0; i < engine.constraintIterations; i++) { - Constraint.solveAll(allConstraints, delta); - } - Constraint.postSolveAll(allBodies); - - // find all collisions - detector.pairs = engine.pairs; - var collisions = Detector.collisions(detector); - - // update collision pairs - Pairs.update(pairs, collisions, timestamp); - - // wake up bodies involved in collisions - if (engine.enableSleeping) - Sleeping.afterCollisions(pairs.list); - - // trigger collision events - if (pairs.collisionStart.length > 0) { - Events.trigger(engine, 'collisionStart', { - pairs: pairs.collisionStart, - timestamp: timing.timestamp, - delta: delta - }); - } - - // iteratively resolve position between collisions - var positionDamping = Common.clamp(20 / engine.positionIterations, 0, 1); - - Resolver.preSolvePosition(pairs.list); - for (i = 0; i < engine.positionIterations; i++) { - Resolver.solvePosition(pairs.list, delta, positionDamping); - } - Resolver.postSolvePosition(allBodies); - - // update all constraints (second pass) - Constraint.preSolveAll(allBodies); - for (i = 0; i < engine.constraintIterations; i++) { - Constraint.solveAll(allConstraints, delta); - } - Constraint.postSolveAll(allBodies); - - // iteratively resolve velocity between collisions - Resolver.preSolveVelocity(pairs.list); - for (i = 0; i < engine.velocityIterations; i++) { - Resolver.solveVelocity(pairs.list, delta); - } - - // update body speed and velocity properties - Engine._bodiesUpdateVelocities(allBodies); - - // trigger collision events - if (pairs.collisionActive.length > 0) { - Events.trigger(engine, 'collisionActive', { - pairs: pairs.collisionActive, - timestamp: timing.timestamp, - delta: delta - }); - } - - if (pairs.collisionEnd.length > 0) { - Events.trigger(engine, 'collisionEnd', { - pairs: pairs.collisionEnd, - timestamp: timing.timestamp, - delta: delta - }); - } - - // clear force buffers - Engine._bodiesClearForces(allBodies); - - Events.trigger(engine, 'afterUpdate', event); - - // log the time elapsed computing this update - engine.timing.lastElapsed = Common.now() - startTime; - - 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 pairs and detector. - * @method clear - * @param {engine} engine - */ - Engine.clear = function(engine) { - Pairs.clear(engine.pairs); - Detector.clear(engine.detector); - }; - - /** - * Zeroes the `body.force` and `body.torque` force buffers. - * @method _bodiesClearForces - * @private - * @param {body[]} bodies - */ - Engine._bodiesClearForces = function(bodies) { - var bodiesLength = bodies.length; - - for (var i = 0; i < bodiesLength; i++) { - var body = bodies[i]; - - // reset force buffers - body.force.x = 0; - body.force.y = 0; - body.torque = 0; - } - }; - - /** - * Applies gravitational acceleration to all `bodies`. - * This models a [uniform gravitational field](https://en.wikipedia.org/wiki/Gravity_of_Earth), similar to near the surface of a planet. - * - * @method _bodiesApplyGravity - * @private - * @param {body[]} bodies - * @param {vector} gravity - */ - Engine._bodiesApplyGravity = function(bodies, gravity) { - var gravityScale = typeof gravity.scale !== 'undefined' ? gravity.scale : 0.001, - bodiesLength = bodies.length; - - if ((gravity.x === 0 && gravity.y === 0) || gravityScale === 0) { - return; - } - - for (var i = 0; i < bodiesLength; i++) { - var body = bodies[i]; - - if (body.isStatic || body.isSleeping) - continue; - - // add the resultant force of gravity - body.force.y += body.mass * gravity.y * gravityScale; - body.force.x += body.mass * gravity.x * gravityScale; - } - }; - - /** - * Applies `Body.update` to all given `bodies`. - * @method _bodiesUpdate - * @private - * @param {body[]} bodies - * @param {number} delta The amount of time elapsed between updates - */ - Engine._bodiesUpdate = function(bodies, delta) { - var bodiesLength = bodies.length; - - for (var i = 0; i < bodiesLength; i++) { - var body = bodies[i]; - - if (body.isStatic || body.isSleeping) - continue; - - Body.update(body, delta); - } - }; - - /** - * Applies `Body.updateVelocities` to all given `bodies`. - * @method _bodiesUpdateVelocities - * @private - * @param {body[]} bodies - */ - Engine._bodiesUpdateVelocities = function(bodies) { - var bodiesLength = bodies.length; - - for (var i = 0; i < bodiesLength; i++) { - Body.updateVelocities(bodies[i]); - } - }; - - /** - * A deprecated alias for `Runner.run`, use `Matter.Runner.run(engine)` instead and see `Matter.Runner` for more information. - * @deprecated use Matter.Runner.run(engine) instead - * @method run - * @param {engine} engine - */ - - /** - * Fired just before an update - * - * @event beforeUpdate - * @param {object} event An event object - * @param {number} event.timestamp The engine.timing.timestamp of the event - * @param {number} event.delta The delta time in milliseconds value used in the update - * @param {engine} event.source The source object of the event - * @param {string} event.name The name of the event - */ - - /** - * Fired after bodies updated based on their velocity and forces, but before any collision detection, constraints and resolving etc. - * - * @event beforeSolve - * @param {object} event An event object - * @param {number} event.timestamp The engine.timing.timestamp of the event - * @param {number} event.delta The delta time in milliseconds value used in the update - * @param {engine} event.source The source object of the event - * @param {string} event.name The name of the event - */ - - /** - * Fired after engine update and all collision events - * - * @event afterUpdate - * @param {object} event An event object - * @param {number} event.timestamp The engine.timing.timestamp of the event - * @param {number} event.delta The delta time in milliseconds value used in the update - * @param {engine} event.source The source object of the event - * @param {string} 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 {object} event An event object - * @param {pair[]} event.pairs List of affected pairs - * @param {number} event.timestamp The engine.timing.timestamp of the event - * @param {number} event.delta The delta time in milliseconds value used in the update - * @param {engine} event.source The source object of the event - * @param {string} 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 {object} event An event object - * @param {pair[]} event.pairs List of affected pairs - * @param {number} event.timestamp The engine.timing.timestamp of the event - * @param {number} event.delta The delta time in milliseconds value used in the update - * @param {engine} event.source The source object of the event - * @param {string} 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 {object} event An event object - * @param {pair[]} event.pairs List of affected pairs - * @param {number} event.timestamp The engine.timing.timestamp of the event - * @param {number} event.delta The delta time in milliseconds value used in the update - * @param {engine} event.source The source object of the event - * @param {string} 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 - */ - - /** - * A `Number` that represents the total execution time elapsed during the last `Engine.update` in milliseconds. - * It is updated by timing from the start of the last `Engine.update` call until it ends. - * - * This value will also include the total execution time of all event handlers directly or indirectly triggered by the engine update. - * - * @property timing.lastElapsed - * @type number - * @default 0 - */ - - /** - * A `Number` that represents the `delta` value used in the last engine update. - * - * @property timing.lastDelta - * @type number - * @default 0 - */ - - /** - * A `Matter.Detector` instance. - * - * @property detector - * @type detector - * @default a Matter.Detector instance - */ - - /** - * A `Matter.Grid` instance. - * - * @deprecated replaced by `engine.detector` - * @property grid - * @type grid - * @default a Matter.Grid instance - */ - - /** - * Replaced by and now alias for `engine.grid`. - * - * @deprecated replaced by `engine.detector` - * @property broadphase - * @type grid - * @default a Matter.Grid instance - */ - - /** - * The root `Matter.Composite` instance that will contain all bodies, constraints and other composites to be simulated by this engine. - * - * @property world - * @type composite - * @default a Matter.Composite instance - */ - - /** - * An object reserved for storing plugin-specific properties. - * - * @property plugin - * @type {} - */ - - /** - * An optional gravitational acceleration applied to all bodies in `engine.world` on every update. - * - * This models a [uniform gravitational field](https://en.wikipedia.org/wiki/Gravity_of_Earth), similar to near the surface of a planet. For gravity in other contexts, disable this and apply forces as needed. - * - * To disable set the `scale` component to `0`. - * - * This is split into three components for ease of use: - * a normalised direction (`x` and `y`) and magnitude (`scale`). - * - * @property gravity - * @type object - */ - - /** - * The gravitational direction normal `x` component, to be multiplied by `gravity.scale`. - * - * @property gravity.x - * @type object - * @default 0 - */ - - /** - * The gravitational direction normal `y` component, to be multiplied by `gravity.scale`. - * - * @property gravity.y - * @type object - * @default 1 - */ - - /** - * The magnitude of the gravitational acceleration. - * - * @property gravity.scale - * @type object - * @default 0.001 - */ - -})(); - - -/***/ }), -/* 18 */ -/***/ (function(module, exports, __webpack_require__) { - -/** -* The `Matter.Resolver` module contains methods for resolving collision pairs. -* -* @class Resolver -*/ - -var Resolver = {}; - -module.exports = Resolver; - -var Vertices = __webpack_require__(3); -var Common = __webpack_require__(0); -var Bounds = __webpack_require__(1); - -(function() { - - Resolver._restingThresh = 2; - Resolver._restingThreshTangent = Math.sqrt(6); - Resolver._positionDampen = 0.9; - Resolver._positionWarming = 0.8; - Resolver._frictionNormalMultiplier = 5; - Resolver._frictionMaxStatic = Number.MAX_VALUE; - - /** - * Prepare pairs for position solving. - * @method preSolvePosition - * @param {pair[]} pairs - */ - Resolver.preSolvePosition = function(pairs) { - var i, - pair, - activeCount, - pairsLength = pairs.length; - - // find total contacts on each body - for (i = 0; i < pairsLength; i++) { - pair = pairs[i]; - - if (!pair.isActive) - continue; - - activeCount = pair.activeContacts.length; - pair.collision.parentA.totalContacts += activeCount; - pair.collision.parentB.totalContacts += activeCount; - } - }; - - /** - * Find a solution for pair positions. - * @method solvePosition - * @param {pair[]} pairs - * @param {number} delta - * @param {number} [damping=1] - */ - Resolver.solvePosition = function(pairs, delta, damping) { - var i, - pair, - collision, - bodyA, - bodyB, - normal, - contactShare, - positionImpulse, - positionDampen = Resolver._positionDampen * (damping || 1), - slopDampen = Common.clamp(delta / Common._baseDelta, 0, 1), - pairsLength = pairs.length; - - // find impulses required to resolve penetration - for (i = 0; i < pairsLength; i++) { - pair = pairs[i]; - - if (!pair.isActive || pair.isSensor) - continue; - - collision = pair.collision; - bodyA = collision.parentA; - bodyB = collision.parentB; - normal = collision.normal; - - // get current separation between body edges involved in collision - pair.separation = - normal.x * (bodyB.positionImpulse.x + collision.penetration.x - bodyA.positionImpulse.x) - + normal.y * (bodyB.positionImpulse.y + collision.penetration.y - bodyA.positionImpulse.y); - } - - for (i = 0; i < pairsLength; i++) { - pair = pairs[i]; - - if (!pair.isActive || pair.isSensor) - continue; - - collision = pair.collision; - bodyA = collision.parentA; - bodyB = collision.parentB; - normal = collision.normal; - positionImpulse = pair.separation - pair.slop * slopDampen; - - if (bodyA.isStatic || bodyB.isStatic) - positionImpulse *= 2; - - if (!(bodyA.isStatic || bodyA.isSleeping)) { - contactShare = positionDampen / bodyA.totalContacts; - bodyA.positionImpulse.x += normal.x * positionImpulse * contactShare; - bodyA.positionImpulse.y += normal.y * positionImpulse * contactShare; - } - - if (!(bodyB.isStatic || bodyB.isSleeping)) { - contactShare = positionDampen / bodyB.totalContacts; - bodyB.positionImpulse.x -= normal.x * positionImpulse * contactShare; - bodyB.positionImpulse.y -= normal.y * positionImpulse * contactShare; - } - } - }; - - /** - * Apply position resolution. - * @method postSolvePosition - * @param {body[]} bodies - */ - Resolver.postSolvePosition = function(bodies) { - var positionWarming = Resolver._positionWarming, - bodiesLength = bodies.length, - verticesTranslate = Vertices.translate, - boundsUpdate = Bounds.update; - - for (var i = 0; i < bodiesLength; i++) { - var body = bodies[i], - positionImpulse = body.positionImpulse, - positionImpulseX = positionImpulse.x, - positionImpulseY = positionImpulse.y, - velocity = body.velocity; - - // reset contact count - body.totalContacts = 0; - - if (positionImpulseX !== 0 || positionImpulseY !== 0) { - // update body geometry - for (var j = 0; j < body.parts.length; j++) { - var part = body.parts[j]; - verticesTranslate(part.vertices, positionImpulse); - boundsUpdate(part.bounds, part.vertices, velocity); - part.position.x += positionImpulseX; - part.position.y += positionImpulseY; - } - - // move the body without changing velocity - body.positionPrev.x += positionImpulseX; - body.positionPrev.y += positionImpulseY; - - if (positionImpulseX * velocity.x + positionImpulseY * velocity.y < 0) { - // reset cached impulse if the body has velocity along it - positionImpulse.x = 0; - positionImpulse.y = 0; - } else { - // warm the next iteration - positionImpulse.x *= positionWarming; - positionImpulse.y *= positionWarming; - } - } - } - }; - - /** - * Prepare pairs for velocity solving. - * @method preSolveVelocity - * @param {pair[]} pairs - */ - Resolver.preSolveVelocity = function(pairs) { - var pairsLength = pairs.length, - i, - j; - - for (i = 0; i < pairsLength; i++) { - var pair = pairs[i]; - - if (!pair.isActive || pair.isSensor) - continue; - - var contacts = pair.activeContacts, - contactsLength = contacts.length, - collision = pair.collision, - bodyA = collision.parentA, - bodyB = collision.parentB, - normal = collision.normal, - tangent = collision.tangent; - - // resolve each contact - for (j = 0; j < contactsLength; j++) { - var contact = contacts[j], - contactVertex = contact.vertex, - normalImpulse = contact.normalImpulse, - tangentImpulse = contact.tangentImpulse; - - if (normalImpulse !== 0 || tangentImpulse !== 0) { - // total impulse from contact - var impulseX = normal.x * normalImpulse + tangent.x * tangentImpulse, - impulseY = normal.y * normalImpulse + tangent.y * tangentImpulse; - - // apply impulse from contact - if (!(bodyA.isStatic || bodyA.isSleeping)) { - bodyA.positionPrev.x += impulseX * bodyA.inverseMass; - bodyA.positionPrev.y += impulseY * bodyA.inverseMass; - bodyA.anglePrev += bodyA.inverseInertia * ( - (contactVertex.x - bodyA.position.x) * impulseY - - (contactVertex.y - bodyA.position.y) * impulseX - ); - } - - if (!(bodyB.isStatic || bodyB.isSleeping)) { - bodyB.positionPrev.x -= impulseX * bodyB.inverseMass; - bodyB.positionPrev.y -= impulseY * bodyB.inverseMass; - bodyB.anglePrev -= bodyB.inverseInertia * ( - (contactVertex.x - bodyB.position.x) * impulseY - - (contactVertex.y - bodyB.position.y) * impulseX - ); - } - } - } - } - }; - - /** - * Find a solution for pair velocities. - * @method solveVelocity - * @param {pair[]} pairs - * @param {number} delta - */ - Resolver.solveVelocity = function(pairs, delta) { - var timeScale = delta / Common._baseDelta, - timeScaleSquared = timeScale * timeScale, - timeScaleCubed = timeScaleSquared * timeScale, - restingThresh = -Resolver._restingThresh * timeScale, - restingThreshTangent = Resolver._restingThreshTangent, - frictionNormalMultiplier = Resolver._frictionNormalMultiplier * timeScale, - frictionMaxStatic = Resolver._frictionMaxStatic, - pairsLength = pairs.length, - tangentImpulse, - maxFriction, - i, - j; - - for (i = 0; i < pairsLength; i++) { - var pair = pairs[i]; - - if (!pair.isActive || pair.isSensor) - continue; - - var collision = pair.collision, - bodyA = collision.parentA, - bodyB = collision.parentB, - bodyAVelocity = bodyA.velocity, - bodyBVelocity = bodyB.velocity, - normalX = collision.normal.x, - normalY = collision.normal.y, - tangentX = collision.tangent.x, - tangentY = collision.tangent.y, - contacts = pair.activeContacts, - contactsLength = contacts.length, - contactShare = 1 / contactsLength, - inverseMassTotal = bodyA.inverseMass + bodyB.inverseMass, - friction = pair.friction * pair.frictionStatic * frictionNormalMultiplier; - - // update body velocities - bodyAVelocity.x = bodyA.position.x - bodyA.positionPrev.x; - bodyAVelocity.y = bodyA.position.y - bodyA.positionPrev.y; - bodyBVelocity.x = bodyB.position.x - bodyB.positionPrev.x; - bodyBVelocity.y = bodyB.position.y - bodyB.positionPrev.y; - bodyA.angularVelocity = bodyA.angle - bodyA.anglePrev; - bodyB.angularVelocity = bodyB.angle - bodyB.anglePrev; - - // resolve each contact - for (j = 0; j < contactsLength; j++) { - var contact = contacts[j], - contactVertex = contact.vertex; - - var offsetAX = contactVertex.x - bodyA.position.x, - offsetAY = contactVertex.y - bodyA.position.y, - offsetBX = contactVertex.x - bodyB.position.x, - offsetBY = contactVertex.y - bodyB.position.y; - - var velocityPointAX = bodyAVelocity.x - offsetAY * bodyA.angularVelocity, - velocityPointAY = bodyAVelocity.y + offsetAX * bodyA.angularVelocity, - velocityPointBX = bodyBVelocity.x - offsetBY * bodyB.angularVelocity, - velocityPointBY = bodyBVelocity.y + offsetBX * bodyB.angularVelocity; - - var relativeVelocityX = velocityPointAX - velocityPointBX, - relativeVelocityY = velocityPointAY - velocityPointBY; - - var normalVelocity = normalX * relativeVelocityX + normalY * relativeVelocityY, - tangentVelocity = tangentX * relativeVelocityX + tangentY * relativeVelocityY; - - // coulomb friction - var normalOverlap = pair.separation + normalVelocity; - var normalForce = Math.min(normalOverlap, 1); - normalForce = normalOverlap < 0 ? 0 : normalForce; - - var frictionLimit = normalForce * friction; - - if (tangentVelocity < -frictionLimit || tangentVelocity > frictionLimit) { - maxFriction = (tangentVelocity > 0 ? tangentVelocity : -tangentVelocity); - tangentImpulse = pair.friction * (tangentVelocity > 0 ? 1 : -1) * timeScaleCubed; - - if (tangentImpulse < -maxFriction) { - tangentImpulse = -maxFriction; - } else if (tangentImpulse > maxFriction) { - tangentImpulse = maxFriction; - } - } else { - tangentImpulse = tangentVelocity; - maxFriction = frictionMaxStatic; - } - - // account for mass, inertia and contact offset - var oAcN = offsetAX * normalY - offsetAY * normalX, - oBcN = offsetBX * normalY - offsetBY * normalX, - share = contactShare / (inverseMassTotal + bodyA.inverseInertia * oAcN * oAcN + bodyB.inverseInertia * oBcN * oBcN); - - // raw impulses - var normalImpulse = (1 + pair.restitution) * normalVelocity * share; - tangentImpulse *= share; - - // handle high velocity and resting collisions separately - if (normalVelocity < restingThresh) { - // high normal velocity so clear cached contact normal impulse - contact.normalImpulse = 0; - } else { - // solve resting collision constraints using Erin Catto's method (GDC08) - // impulse constraint tends to 0 - var contactNormalImpulse = contact.normalImpulse; - contact.normalImpulse += normalImpulse; - if (contact.normalImpulse > 0) contact.normalImpulse = 0; - normalImpulse = contact.normalImpulse - contactNormalImpulse; - } - - // handle high velocity and resting collisions separately - if (tangentVelocity < -restingThreshTangent || tangentVelocity > restingThreshTangent) { - // high tangent velocity so clear cached contact tangent impulse - contact.tangentImpulse = 0; - } else { - // solve resting collision constraints using Erin Catto's method (GDC08) - // tangent impulse tends to -tangentSpeed or +tangentSpeed - var contactTangentImpulse = contact.tangentImpulse; - contact.tangentImpulse += tangentImpulse; - if (contact.tangentImpulse < -maxFriction) contact.tangentImpulse = -maxFriction; - if (contact.tangentImpulse > maxFriction) contact.tangentImpulse = maxFriction; - tangentImpulse = contact.tangentImpulse - contactTangentImpulse; - } - - // total impulse from contact - var impulseX = normalX * normalImpulse + tangentX * tangentImpulse, - impulseY = normalY * normalImpulse + tangentY * tangentImpulse; - - // apply impulse from contact - if (!(bodyA.isStatic || bodyA.isSleeping)) { - bodyA.positionPrev.x += impulseX * bodyA.inverseMass; - bodyA.positionPrev.y += impulseY * bodyA.inverseMass; - bodyA.anglePrev += (offsetAX * impulseY - offsetAY * impulseX) * bodyA.inverseInertia; - } - - if (!(bodyB.isStatic || bodyB.isSleeping)) { - bodyB.positionPrev.x -= impulseX * bodyB.inverseMass; - bodyB.positionPrev.y -= impulseY * bodyB.inverseMass; - bodyB.anglePrev -= (offsetBX * impulseY - offsetBY * impulseX) * bodyB.inverseInertia; - } - } - } - }; - -})(); - - -/***/ }), -/* 19 */ -/***/ (function(module, exports, __webpack_require__) { - -/** -* The `Matter.Pairs` module contains methods for creating and manipulating collision pair sets. -* -* @class Pairs -*/ - -var Pairs = {}; - -module.exports = Pairs; - -var Pair = __webpack_require__(9); -var Common = __webpack_require__(0); - -(function() { - - /** - * Creates a new pairs structure. - * @method create - * @param {object} options - * @return {pairs} A new pairs structure - */ - Pairs.create = function(options) { - return Common.extend({ - table: {}, - list: [], - collisionStart: [], - collisionActive: [], - collisionEnd: [] - }, options); - }; - - /** - * Updates pairs given a list of collisions. - * @method update - * @param {object} pairs - * @param {collision[]} collisions - * @param {number} timestamp - */ - Pairs.update = function(pairs, collisions, timestamp) { - var pairsList = pairs.list, - pairsListLength = pairsList.length, - pairsTable = pairs.table, - collisionsLength = collisions.length, - collisionStart = pairs.collisionStart, - collisionEnd = pairs.collisionEnd, - collisionActive = pairs.collisionActive, - collision, - pairIndex, - pair, - i; - - // clear collision state arrays, but maintain old reference - collisionStart.length = 0; - collisionEnd.length = 0; - collisionActive.length = 0; - - for (i = 0; i < pairsListLength; i++) { - pairsList[i].confirmedActive = false; - } - - for (i = 0; i < collisionsLength; i++) { - collision = collisions[i]; - pair = collision.pair; - - if (pair) { - // pair already exists (but may or may not be active) - if (pair.isActive) { - // pair exists and is active - collisionActive.push(pair); - } else { - // pair exists but was inactive, so a collision has just started again - collisionStart.push(pair); - } - - // update the pair - Pair.update(pair, collision, timestamp); - pair.confirmedActive = true; - } else { - // pair did not exist, create a new pair - pair = Pair.create(collision, timestamp); - pairsTable[pair.id] = pair; - - // push the new pair - collisionStart.push(pair); - pairsList.push(pair); - } - } - - // find pairs that are no longer active - var removePairIndex = []; - pairsListLength = pairsList.length; - - for (i = 0; i < pairsListLength; i++) { - pair = pairsList[i]; - - if (!pair.confirmedActive) { - Pair.setActive(pair, false, timestamp); - collisionEnd.push(pair); - - if (!pair.collision.bodyA.isSleeping && !pair.collision.bodyB.isSleeping) { - removePairIndex.push(i); - } - } - } - - // remove inactive pairs - for (i = 0; i < removePairIndex.length; i++) { - pairIndex = removePairIndex[i] - i; - pair = pairsList[pairIndex]; - pairsList.splice(pairIndex, 1); - delete pairsTable[pair.id]; - } - }; - - /** - * Clears the given pairs structure. - * @method clear - * @param {pairs} pairs - * @return {pairs} pairs - */ - Pairs.clear = function(pairs) { - pairs.table = {}; - pairs.list.length = 0; - pairs.collisionStart.length = 0; - pairs.collisionActive.length = 0; - pairs.collisionEnd.length = 0; - return pairs; - }; - -})(); - - -/***/ }), -/* 20 */ -/***/ (function(module, exports, __webpack_require__) { - -var Matter = module.exports = __webpack_require__(21); - -Matter.Axes = __webpack_require__(11); -Matter.Bodies = __webpack_require__(12); -Matter.Body = __webpack_require__(4); -Matter.Bounds = __webpack_require__(1); -Matter.Collision = __webpack_require__(8); -Matter.Common = __webpack_require__(0); -Matter.Composite = __webpack_require__(6); -Matter.Composites = __webpack_require__(22); -Matter.Constraint = __webpack_require__(10); -Matter.Contact = __webpack_require__(16); -Matter.Detector = __webpack_require__(13); -Matter.Engine = __webpack_require__(17); -Matter.Events = __webpack_require__(5); -Matter.Grid = __webpack_require__(23); -Matter.Mouse = __webpack_require__(14); -Matter.MouseConstraint = __webpack_require__(24); -Matter.Pair = __webpack_require__(9); -Matter.Pairs = __webpack_require__(19); -Matter.Plugin = __webpack_require__(15); -Matter.Query = __webpack_require__(25); -Matter.Render = __webpack_require__(26); -Matter.Resolver = __webpack_require__(18); -Matter.Runner = __webpack_require__(27); -Matter.SAT = __webpack_require__(28); -Matter.Sleeping = __webpack_require__(7); -Matter.Svg = __webpack_require__(29); -Matter.Vector = __webpack_require__(2); -Matter.Vertices = __webpack_require__(3); -Matter.World = __webpack_require__(30); - -// temporary back compatibility -Matter.Engine.run = Matter.Runner.run; -Matter.Common.deprecated(Matter.Engine, 'run', 'Engine.run ➤ use Matter.Runner.run(engine) instead'); - - -/***/ }), -/* 21 */ -/***/ (function(module, exports, __webpack_require__) { - -/** -* The `Matter` module is the top level namespace. It also includes a function for installing plugins on top of the library. -* -* @class Matter -*/ - -var Matter = {}; - -module.exports = Matter; - -var Plugin = __webpack_require__(15); -var Common = __webpack_require__(0); - -(function() { - - /** - * The library name. - * @property name - * @readOnly - * @type {String} - */ - Matter.name = 'matter-js'; - - /** - * The library version. - * @property version - * @readOnly - * @type {String} - */ - Matter.version = true ? "0.19.0-alpha+205aaa5" : undefined; - - /** - * A list of plugin dependencies to be installed. These are normally set and installed through `Matter.use`. - * Alternatively you may set `Matter.uses` manually and install them by calling `Plugin.use(Matter)`. - * @property uses - * @type {Array} - */ - Matter.uses = []; - - /** - * The plugins that have been installed through `Matter.Plugin.install`. Read only. - * @property used - * @readOnly - * @type {Array} - */ - Matter.used = []; - - /** - * Installs the given plugins on the `Matter` namespace. - * This is a short-hand for `Plugin.use`, see it for more information. - * Call this function once at the start of your code, with all of the plugins you wish to install as arguments. - * Avoid calling this function multiple times unless you intend to manually control installation order. - * @method use - * @param ...plugin {Function} The plugin(s) to install on `base` (multi-argument). - */ - Matter.use = function() { - Plugin.use(Matter, Array.prototype.slice.call(arguments)); - }; - - /** - * Chains a function to excute before the original function on the given `path` relative to `Matter`. - * See also docs for `Common.chain`. - * @method before - * @param {string} path The path relative to `Matter` - * @param {function} func The function to chain before the original - * @return {function} The chained function that replaced the original - */ - Matter.before = function(path, func) { - path = path.replace(/^Matter./, ''); - return Common.chainPathBefore(Matter, path, func); - }; - - /** - * Chains a function to excute after the original function on the given `path` relative to `Matter`. - * See also docs for `Common.chain`. - * @method after - * @param {string} path The path relative to `Matter` - * @param {function} func The function to chain after the original - * @return {function} The chained function that replaced the original - */ - Matter.after = function(path, func) { - path = path.replace(/^Matter./, ''); - return Common.chainPathAfter(Matter, path, func); - }; - -})(); - - -/***/ }), -/* 22 */ -/***/ (function(module, exports, __webpack_require__) { - -/** -* The `Matter.Composites` module contains factory methods for creating composite bodies -* with commonly used configurations (such as stacks and chains). -* -* See the included usage [examples](https://github.com/liabru/matter-js/tree/master/examples). -* -* @class Composites -*/ - -var Composites = {}; - -module.exports = Composites; - -var Composite = __webpack_require__(6); -var Constraint = __webpack_require__(10); -var Common = __webpack_require__(0); -var Body = __webpack_require__(4); -var Bodies = __webpack_require__(12); -var deprecated = Common.deprecated; - -(function() { - - /** - * Create a new composite containing bodies created in the callback in a grid arrangement. - * This function uses the body's bounds to prevent overlaps. - * @method stack - * @param {number} x Starting position in X. - * @param {number} y Starting position in Y. - * @param {number} columns - * @param {number} rows - * @param {number} columnGap - * @param {number} rowGap - * @param {function} callback - * @return {composite} A new composite containing objects created in the callback - */ - Composites.stack = function(x, y, columns, rows, columnGap, rowGap, callback) { - var stack = Composite.create({ label: 'Stack' }), - currentX = x, - currentY = y, - lastBody, - i = 0; - - for (var row = 0; row < rows; row++) { - var maxHeight = 0; - - for (var column = 0; column < columns; column++) { - var body = callback(currentX, currentY, column, row, lastBody, i); - - if (body) { - var bodyHeight = body.bounds.max.y - body.bounds.min.y, - bodyWidth = body.bounds.max.x - body.bounds.min.x; - - if (bodyHeight > maxHeight) - maxHeight = bodyHeight; - - Body.translate(body, { x: bodyWidth * 0.5, y: bodyHeight * 0.5 }); - - currentX = body.bounds.max.x + columnGap; - - Composite.addBody(stack, body); - - lastBody = body; - i += 1; - } else { - currentX += columnGap; - } - } - - currentY += maxHeight + rowGap; - currentX = x; - } - - return stack; - }; - - /** - * Chains all bodies in the given composite together using constraints. - * @method chain - * @param {composite} composite - * @param {number} xOffsetA - * @param {number} yOffsetA - * @param {number} xOffsetB - * @param {number} yOffsetB - * @param {object} options - * @return {composite} A new composite containing objects chained together with constraints - */ - Composites.chain = function(composite, xOffsetA, yOffsetA, xOffsetB, yOffsetB, options) { - var bodies = composite.bodies; - - for (var i = 1; i < bodies.length; i++) { - var bodyA = bodies[i - 1], - bodyB = bodies[i], - bodyAHeight = bodyA.bounds.max.y - bodyA.bounds.min.y, - bodyAWidth = bodyA.bounds.max.x - bodyA.bounds.min.x, - bodyBHeight = bodyB.bounds.max.y - bodyB.bounds.min.y, - bodyBWidth = bodyB.bounds.max.x - bodyB.bounds.min.x; - - var defaults = { - bodyA: bodyA, - pointA: { x: bodyAWidth * xOffsetA, y: bodyAHeight * yOffsetA }, - bodyB: bodyB, - pointB: { x: bodyBWidth * xOffsetB, y: bodyBHeight * yOffsetB } - }; - - var constraint = Common.extend(defaults, options); - - Composite.addConstraint(composite, Constraint.create(constraint)); - } - - composite.label += ' Chain'; - - return composite; - }; - - /** - * Connects bodies in the composite with constraints in a grid pattern, with optional cross braces. - * @method mesh - * @param {composite} composite - * @param {number} columns - * @param {number} rows - * @param {boolean} crossBrace - * @param {object} options - * @return {composite} The composite containing objects meshed together with constraints - */ - Composites.mesh = function(composite, columns, rows, crossBrace, options) { - var bodies = composite.bodies, - row, - col, - bodyA, - bodyB, - bodyC; - - for (row = 0; row < rows; row++) { - for (col = 1; col < columns; col++) { - bodyA = bodies[(col - 1) + (row * columns)]; - bodyB = bodies[col + (row * columns)]; - Composite.addConstraint(composite, Constraint.create(Common.extend({ bodyA: bodyA, bodyB: bodyB }, options))); - } - - if (row > 0) { - for (col = 0; col < columns; col++) { - bodyA = bodies[col + ((row - 1) * columns)]; - bodyB = bodies[col + (row * columns)]; - Composite.addConstraint(composite, Constraint.create(Common.extend({ bodyA: bodyA, bodyB: bodyB }, options))); - - if (crossBrace && col > 0) { - bodyC = bodies[(col - 1) + ((row - 1) * columns)]; - Composite.addConstraint(composite, Constraint.create(Common.extend({ bodyA: bodyC, bodyB: bodyB }, options))); - } - - if (crossBrace && col < columns - 1) { - bodyC = bodies[(col + 1) + ((row - 1) * columns)]; - Composite.addConstraint(composite, Constraint.create(Common.extend({ bodyA: bodyC, bodyB: bodyB }, options))); - } - } - } - } - - composite.label += ' Mesh'; - - return composite; - }; - - /** - * Create a new composite containing bodies created in the callback in a pyramid arrangement. - * This function uses the body's bounds to prevent overlaps. - * @method pyramid - * @param {number} x Starting position in X. - * @param {number} y Starting position in Y. - * @param {number} columns - * @param {number} rows - * @param {number} columnGap - * @param {number} rowGap - * @param {function} callback - * @return {composite} A new composite containing objects created in the callback - */ - Composites.pyramid = function(x, y, columns, rows, columnGap, rowGap, callback) { - return Composites.stack(x, y, columns, rows, columnGap, rowGap, function(stackX, stackY, column, row, lastBody, i) { - var actualRows = Math.min(rows, Math.ceil(columns / 2)), - lastBodyWidth = lastBody ? lastBody.bounds.max.x - lastBody.bounds.min.x : 0; - - if (row > actualRows) - return; - - // reverse row order - row = actualRows - row; - - var start = row, - end = columns - 1 - row; - - if (column < start || column > end) - return; - - // retroactively fix the first body's position, since width was unknown - if (i === 1) { - Body.translate(lastBody, { x: (column + (columns % 2 === 1 ? 1 : -1)) * lastBodyWidth, y: 0 }); - } - - var xOffset = lastBody ? column * lastBodyWidth : 0; - - return callback(x + xOffset + column * columnGap, stackY, column, row, lastBody, i); - }); - }; - - /** - * This has now moved to the [newtonsCradle example](https://github.com/liabru/matter-js/blob/master/examples/newtonsCradle.js), follow that instead as this function is deprecated here. - * @deprecated moved to newtonsCradle example - * @method newtonsCradle - * @param {number} x Starting position in X. - * @param {number} y Starting position in Y. - * @param {number} number - * @param {number} size - * @param {number} length - * @return {composite} A new composite newtonsCradle body - */ - Composites.newtonsCradle = function(x, y, number, size, length) { - var newtonsCradle = Composite.create({ label: 'Newtons Cradle' }); - - for (var i = 0; i < number; i++) { - var separation = 1.9, - circle = Bodies.circle(x + i * (size * separation), y + length, size, - { inertia: Infinity, restitution: 1, friction: 0, frictionAir: 0.0001, slop: 1 }), - constraint = Constraint.create({ pointA: { x: x + i * (size * separation), y: y }, bodyB: circle }); - - Composite.addBody(newtonsCradle, circle); - Composite.addConstraint(newtonsCradle, constraint); - } - - return newtonsCradle; - }; - - deprecated(Composites, 'newtonsCradle', 'Composites.newtonsCradle ➤ moved to newtonsCradle example'); - - /** - * This has now moved to the [car example](https://github.com/liabru/matter-js/blob/master/examples/car.js), follow that instead as this function is deprecated here. - * @deprecated moved to car example - * @method car - * @param {number} x Starting position in X. - * @param {number} y Starting position in Y. - * @param {number} width - * @param {number} height - * @param {number} wheelSize - * @return {composite} A new composite car body - */ - Composites.car = function(x, y, width, height, wheelSize) { - var group = Body.nextGroup(true), - wheelBase = 20, - wheelAOffset = -width * 0.5 + wheelBase, - wheelBOffset = width * 0.5 - wheelBase, - wheelYOffset = 0; - - var car = Composite.create({ label: 'Car' }), - body = Bodies.rectangle(x, y, width, height, { - collisionFilter: { - group: group - }, - chamfer: { - radius: height * 0.5 - }, - density: 0.0002 - }); - - var wheelA = Bodies.circle(x + wheelAOffset, y + wheelYOffset, wheelSize, { - collisionFilter: { - group: group - }, - friction: 0.8 - }); - - var wheelB = Bodies.circle(x + wheelBOffset, y + wheelYOffset, wheelSize, { - collisionFilter: { - group: group - }, - friction: 0.8 - }); - - var axelA = Constraint.create({ - bodyB: body, - pointB: { x: wheelAOffset, y: wheelYOffset }, - bodyA: wheelA, - stiffness: 1, - length: 0 - }); - - var axelB = Constraint.create({ - bodyB: body, - pointB: { x: wheelBOffset, y: wheelYOffset }, - bodyA: wheelB, - stiffness: 1, - length: 0 - }); - - Composite.addBody(car, body); - Composite.addBody(car, wheelA); - Composite.addBody(car, wheelB); - Composite.addConstraint(car, axelA); - Composite.addConstraint(car, axelB); - - return car; - }; - - deprecated(Composites, 'car', 'Composites.car ➤ moved to car example'); - - /** - * This has now moved to the [softBody example](https://github.com/liabru/matter-js/blob/master/examples/softBody.js) - * and the [cloth example](https://github.com/liabru/matter-js/blob/master/examples/cloth.js), follow those instead as this function is deprecated here. - * @deprecated moved to softBody and cloth examples - * @method softBody - * @param {number} x Starting position in X. - * @param {number} y Starting position in Y. - * @param {number} columns - * @param {number} rows - * @param {number} columnGap - * @param {number} rowGap - * @param {boolean} crossBrace - * @param {number} particleRadius - * @param {} particleOptions - * @param {} constraintOptions - * @return {composite} A new composite softBody - */ - Composites.softBody = function(x, y, columns, rows, columnGap, rowGap, crossBrace, particleRadius, particleOptions, constraintOptions) { - particleOptions = Common.extend({ inertia: Infinity }, particleOptions); - constraintOptions = Common.extend({ stiffness: 0.2, render: { type: 'line', anchors: false } }, constraintOptions); - - var softBody = Composites.stack(x, y, columns, rows, columnGap, rowGap, function(stackX, stackY) { - return Bodies.circle(stackX, stackY, particleRadius, particleOptions); - }); - - Composites.mesh(softBody, columns, rows, crossBrace, constraintOptions); - - softBody.label = 'Soft Body'; - - return softBody; - }; - - deprecated(Composites, 'softBody', 'Composites.softBody ➤ moved to softBody and cloth examples'); -})(); - - -/***/ }), -/* 23 */ -/***/ (function(module, exports, __webpack_require__) { - -/** -* This module has now been replaced by `Matter.Detector`. -* -* All usage should be migrated to `Matter.Detector` or another alternative. -* For back-compatibility purposes this module will remain for a short term and then later removed in a future release. -* -* The `Matter.Grid` module contains methods for creating and manipulating collision broadphase grid structures. -* -* @class Grid -* @deprecated -*/ - -var Grid = {}; - -module.exports = Grid; - -var Pair = __webpack_require__(9); -var Common = __webpack_require__(0); -var deprecated = Common.deprecated; - -(function() { - - /** - * Creates a new grid. - * @deprecated replaced by Matter.Detector - * @method create - * @param {} options - * @return {grid} A new grid - */ - Grid.create = function(options) { - var defaults = { - buckets: {}, - pairs: {}, - pairsList: [], - bucketWidth: 48, - bucketHeight: 48 - }; - - return Common.extend(defaults, options); - }; - - /** - * The width of a single grid bucket. - * - * @property bucketWidth - * @type number - * @default 48 - */ - - /** - * The height of a single grid bucket. - * - * @property bucketHeight - * @type number - * @default 48 - */ - - /** - * Updates the grid. - * @deprecated replaced by Matter.Detector - * @method update - * @param {grid} grid - * @param {body[]} bodies - * @param {engine} engine - * @param {boolean} forceUpdate - */ - Grid.update = function(grid, bodies, engine, forceUpdate) { - var i, col, row, - world = engine.world, - buckets = grid.buckets, - bucket, - bucketId, - gridChanged = false; - - for (i = 0; i < bodies.length; i++) { - var body = bodies[i]; - - if (body.isSleeping && !forceUpdate) - continue; - - // temporary back compatibility bounds check - if (world.bounds && (body.bounds.max.x < world.bounds.min.x || body.bounds.min.x > world.bounds.max.x - || body.bounds.max.y < world.bounds.min.y || body.bounds.min.y > world.bounds.max.y)) - continue; - - var newRegion = Grid._getRegion(grid, body); - - // if the body has changed grid region - if (!body.region || newRegion.id !== body.region.id || forceUpdate) { - - if (!body.region || forceUpdate) - body.region = newRegion; - - var union = Grid._regionUnion(newRegion, body.region); - - // update grid buckets affected by region change - // iterate over the union of both regions - for (col = union.startCol; col <= union.endCol; col++) { - for (row = union.startRow; row <= union.endRow; row++) { - bucketId = Grid._getBucketId(col, row); - bucket = buckets[bucketId]; - - var isInsideNewRegion = (col >= newRegion.startCol && col <= newRegion.endCol - && row >= newRegion.startRow && row <= newRegion.endRow); - - var isInsideOldRegion = (col >= body.region.startCol && col <= body.region.endCol - && row >= body.region.startRow && row <= body.region.endRow); - - // remove from old region buckets - if (!isInsideNewRegion && isInsideOldRegion) { - if (isInsideOldRegion) { - if (bucket) - Grid._bucketRemoveBody(grid, bucket, body); - } - } - - // add to new region buckets - if (body.region === newRegion || (isInsideNewRegion && !isInsideOldRegion) || forceUpdate) { - if (!bucket) - bucket = Grid._createBucket(buckets, bucketId); - Grid._bucketAddBody(grid, bucket, body); - } - } - } - - // set the new region - body.region = newRegion; - - // flag changes so we can update pairs - gridChanged = true; - } - } - - // update pairs list only if pairs changed (i.e. a body changed region) - if (gridChanged) - grid.pairsList = Grid._createActivePairsList(grid); - }; - - deprecated(Grid, 'update', 'Grid.update ➤ replaced by Matter.Detector'); - - /** - * Clears the grid. - * @deprecated replaced by Matter.Detector - * @method clear - * @param {grid} grid - */ - Grid.clear = function(grid) { - grid.buckets = {}; - grid.pairs = {}; - grid.pairsList = []; - }; - - deprecated(Grid, 'clear', 'Grid.clear ➤ replaced by Matter.Detector'); - - /** - * Finds the union of two regions. - * @method _regionUnion - * @deprecated replaced by Matter.Detector - * @private - * @param {} regionA - * @param {} regionB - * @return {} region - */ - Grid._regionUnion = function(regionA, regionB) { - var startCol = Math.min(regionA.startCol, regionB.startCol), - endCol = Math.max(regionA.endCol, regionB.endCol), - startRow = Math.min(regionA.startRow, regionB.startRow), - endRow = Math.max(regionA.endRow, regionB.endRow); - - return Grid._createRegion(startCol, endCol, startRow, endRow); - }; - - /** - * Gets the region a given body falls in for a given grid. - * @method _getRegion - * @deprecated replaced by Matter.Detector - * @private - * @param {} grid - * @param {} body - * @return {} region - */ - Grid._getRegion = function(grid, body) { - var bounds = body.bounds, - startCol = Math.floor(bounds.min.x / grid.bucketWidth), - endCol = Math.floor(bounds.max.x / grid.bucketWidth), - startRow = Math.floor(bounds.min.y / grid.bucketHeight), - endRow = Math.floor(bounds.max.y / grid.bucketHeight); - - return Grid._createRegion(startCol, endCol, startRow, endRow); - }; - - /** - * Creates a region. - * @method _createRegion - * @deprecated replaced by Matter.Detector - * @private - * @param {} startCol - * @param {} endCol - * @param {} startRow - * @param {} endRow - * @return {} region - */ - Grid._createRegion = function(startCol, endCol, startRow, endRow) { - return { - id: startCol + ',' + endCol + ',' + startRow + ',' + endRow, - startCol: startCol, - endCol: endCol, - startRow: startRow, - endRow: endRow - }; - }; - - /** - * Gets the bucket id at the given position. - * @method _getBucketId - * @deprecated replaced by Matter.Detector - * @private - * @param {} column - * @param {} row - * @return {string} bucket id - */ - Grid._getBucketId = function(column, row) { - return 'C' + column + 'R' + row; - }; - - /** - * Creates a bucket. - * @method _createBucket - * @deprecated replaced by Matter.Detector - * @private - * @param {} buckets - * @param {} bucketId - * @return {} bucket - */ - Grid._createBucket = function(buckets, bucketId) { - var bucket = buckets[bucketId] = []; - return bucket; - }; - - /** - * Adds a body to a bucket. - * @method _bucketAddBody - * @deprecated replaced by Matter.Detector - * @private - * @param {} grid - * @param {} bucket - * @param {} body - */ - Grid._bucketAddBody = function(grid, bucket, body) { - var gridPairs = grid.pairs, - pairId = Pair.id, - bucketLength = bucket.length, - i; - - // add new pairs - for (i = 0; i < bucketLength; i++) { - var bodyB = bucket[i]; - - if (body.id === bodyB.id || (body.isStatic && bodyB.isStatic)) - continue; - - // keep track of the number of buckets the pair exists in - // important for Grid.update to work - var id = pairId(body, bodyB), - pair = gridPairs[id]; - - if (pair) { - pair[2] += 1; - } else { - gridPairs[id] = [body, bodyB, 1]; - } - } - - // add to bodies (after pairs, otherwise pairs with self) - bucket.push(body); - }; - - /** - * Removes a body from a bucket. - * @method _bucketRemoveBody - * @deprecated replaced by Matter.Detector - * @private - * @param {} grid - * @param {} bucket - * @param {} body - */ - Grid._bucketRemoveBody = function(grid, bucket, body) { - var gridPairs = grid.pairs, - pairId = Pair.id, - i; - - // remove from bucket - bucket.splice(Common.indexOf(bucket, body), 1); - - var bucketLength = bucket.length; - - // update pair counts - for (i = 0; i < bucketLength; i++) { - // keep track of the number of buckets the pair exists in - // important for _createActivePairsList to work - var pair = gridPairs[pairId(body, bucket[i])]; - - if (pair) - pair[2] -= 1; - } - }; - - /** - * Generates a list of the active pairs in the grid. - * @method _createActivePairsList - * @deprecated replaced by Matter.Detector - * @private - * @param {} grid - * @return [] pairs - */ - Grid._createActivePairsList = function(grid) { - var pair, - gridPairs = grid.pairs, - pairKeys = Common.keys(gridPairs), - pairKeysLength = pairKeys.length, - pairs = [], - k; - - // iterate over grid.pairs - for (k = 0; k < pairKeysLength; k++) { - pair = gridPairs[pairKeys[k]]; - - // if pair exists in at least one bucket - // it is a pair that needs further collision testing so push it - if (pair[2] > 0) { - pairs.push(pair); - } else { - delete gridPairs[pairKeys[k]]; - } - } - - return pairs; - }; - -})(); - - -/***/ }), -/* 24 */ -/***/ (function(module, exports, __webpack_require__) { - -/** -* The `Matter.MouseConstraint` module contains methods for creating mouse constraints. -* Mouse constraints are used for allowing user interaction, providing the ability to move bodies via the mouse or touch. -* -* See the included usage [examples](https://github.com/liabru/matter-js/tree/master/examples). -* -* @class MouseConstraint -*/ - -var MouseConstraint = {}; - -module.exports = MouseConstraint; - -var Vertices = __webpack_require__(3); -var Sleeping = __webpack_require__(7); -var Mouse = __webpack_require__(14); -var Events = __webpack_require__(5); -var Detector = __webpack_require__(13); -var Constraint = __webpack_require__(10); -var Composite = __webpack_require__(6); -var Common = __webpack_require__(0); -var Bounds = __webpack_require__(1); - -(function() { - - /** - * Creates a new mouse constraint. - * 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 {engine} engine - * @param {} options - * @return {MouseConstraint} A new MouseConstraint - */ - MouseConstraint.create = function(engine, options) { - var mouse = (engine ? engine.mouse : null) || (options ? options.mouse : null); - - if (!mouse) { - if (engine && engine.render && engine.render.canvas) { - mouse = Mouse.create(engine.render.canvas); - } else if (options && options.element) { - mouse = Mouse.create(options.element); - } else { - mouse = Mouse.create(); - Common.warn('MouseConstraint.create: options.mouse was undefined, options.element was undefined, may not function as expected'); - } - } - - var constraint = Constraint.create({ - label: 'Mouse Constraint', - pointA: mouse.position, - pointB: { x: 0, y: 0 }, - length: 0.01, - stiffness: 0.1, - angularStiffness: 1, - render: { - strokeStyle: '#90EE90', - lineWidth: 3 - } - }); - - var defaults = { - type: 'mouseConstraint', - mouse: mouse, - element: null, - body: null, - constraint: constraint, - collisionFilter: { - category: 0x0001, - mask: 0xFFFFFFFF, - group: 0 - } - }; - - var mouseConstraint = Common.extend(defaults, options); - - Events.on(engine, 'beforeUpdate', function() { - var allBodies = Composite.allBodies(engine.world); - MouseConstraint.update(mouseConstraint, allBodies); - MouseConstraint._triggerEvents(mouseConstraint); - }); - - return mouseConstraint; - }; - - /** - * Updates the given mouse constraint. - * @private - * @method update - * @param {MouseConstraint} mouseConstraint - * @param {body[]} bodies - */ - MouseConstraint.update = function(mouseConstraint, bodies) { - var mouse = mouseConstraint.mouse, - constraint = mouseConstraint.constraint, - body = mouseConstraint.body; - - if (mouse.button === 0) { - if (!constraint.bodyB) { - for (var i = 0; i < bodies.length; i++) { - body = bodies[i]; - if (Bounds.contains(body.bounds, mouse.position) - && Detector.canCollide(body.collisionFilter, mouseConstraint.collisionFilter)) { - for (var j = body.parts.length > 1 ? 1 : 0; j < body.parts.length; j++) { - var part = body.parts[j]; - if (Vertices.contains(part.vertices, mouse.position)) { - constraint.pointA = mouse.position; - constraint.bodyB = mouseConstraint.body = body; - constraint.pointB = { x: mouse.position.x - body.position.x, y: mouse.position.y - body.position.y }; - constraint.angleB = body.angle; - - Sleeping.set(body, false); - Events.trigger(mouseConstraint, 'startdrag', { mouse: mouse, body: body }); - - break; - } - } - } - } - } else { - Sleeping.set(constraint.bodyB, false); - constraint.pointA = mouse.position; - } - } else { - constraint.bodyB = mouseConstraint.body = null; - constraint.pointB = null; - - if (body) - Events.trigger(mouseConstraint, 'enddrag', { mouse: mouse, body: body }); - } - }; - - /** - * Triggers mouse constraint events. - * @method _triggerEvents - * @private - * @param {mouse} mouseConstraint - */ - MouseConstraint._triggerEvents = function(mouseConstraint) { - var mouse = mouseConstraint.mouse, - mouseEvents = mouse.sourceEvents; - - if (mouseEvents.mousemove) - Events.trigger(mouseConstraint, 'mousemove', { mouse: mouse }); - - if (mouseEvents.mousedown) - Events.trigger(mouseConstraint, 'mousedown', { mouse: mouse }); - - if (mouseEvents.mouseup) - Events.trigger(mouseConstraint, 'mouseup', { mouse: mouse }); - - // reset the mouse state ready for the next step - Mouse.clearSourceEvents(mouse); - }; - - /* - * - * Events Documentation - * - */ - - /** - * Fired when the mouse has moved (or a touch moves) during the last step - * - * @event mousemove - * @param {} event An event object - * @param {mouse} event.mouse The engine's mouse instance - * @param {} event.source The source object of the event - * @param {} event.name The name of the event - */ - - /** - * Fired when the mouse is down (or a touch has started) during the last step - * - * @event mousedown - * @param {} event An event object - * @param {mouse} event.mouse The engine's mouse instance - * @param {} event.source The source object of the event - * @param {} event.name The name of the event - */ - - /** - * Fired when the mouse is up (or a touch has ended) during the last step - * - * @event mouseup - * @param {} event An event object - * @param {mouse} event.mouse The engine's mouse instance - * @param {} event.source The source object of the event - * @param {} event.name The name of the event - */ - - /** - * Fired when the user starts dragging a body - * - * @event startdrag - * @param {} event An event object - * @param {mouse} event.mouse The engine's mouse instance - * @param {body} event.body The body being dragged - * @param {} event.source The source object of the event - * @param {} event.name The name of the event - */ - - /** - * Fired when the user ends dragging a body - * - * @event enddrag - * @param {} event An event object - * @param {mouse} event.mouse The engine's mouse instance - * @param {body} event.body The body that has stopped being dragged - * @param {} event.source The source object of the event - * @param {} event.name The name of the event - */ - - /* - * - * Properties Documentation - * - */ - - /** - * A `String` denoting the type of object. - * - * @property type - * @type string - * @default "constraint" - * @readOnly - */ - - /** - * The `Mouse` instance in use. If not supplied in `MouseConstraint.create`, one will be created. - * - * @property mouse - * @type mouse - * @default mouse - */ - - /** - * The `Body` that is currently being moved by the user, or `null` if no body. - * - * @property body - * @type body - * @default null - */ - - /** - * The `Constraint` object that is used to move the body during interaction. - * - * @property constraint - * @type constraint - */ - - /** - * An `Object` that specifies the collision filter properties. - * The collision filter allows the user to define which types of body this mouse constraint can interact with. - * See `body.collisionFilter` for more information. - * - * @property collisionFilter - * @type object - */ - -})(); - - -/***/ }), -/* 25 */ -/***/ (function(module, exports, __webpack_require__) { - -/** -* The `Matter.Query` module contains methods for performing collision queries. -* -* See the included usage [examples](https://github.com/liabru/matter-js/tree/master/examples). -* -* @class Query -*/ - -var Query = {}; - -module.exports = Query; - -var Vector = __webpack_require__(2); -var Collision = __webpack_require__(8); -var Bounds = __webpack_require__(1); -var Bodies = __webpack_require__(12); -var Vertices = __webpack_require__(3); - -(function() { - - /** - * Returns a list of collisions between `body` and `bodies`. - * @method collides - * @param {body} body - * @param {body[]} bodies - * @return {collision[]} Collisions - */ - Query.collides = function(body, bodies) { - var collisions = [], - bodiesLength = bodies.length, - bounds = body.bounds, - collides = Collision.collides, - overlaps = Bounds.overlaps; - - for (var i = 0; i < bodiesLength; i++) { - var bodyA = bodies[i], - partsALength = bodyA.parts.length, - partsAStart = partsALength === 1 ? 0 : 1; - - if (overlaps(bodyA.bounds, bounds)) { - for (var j = partsAStart; j < partsALength; j++) { - var part = bodyA.parts[j]; - - if (overlaps(part.bounds, bounds)) { - var collision = collides(part, body); - - if (collision) { - collisions.push(collision); - break; - } - } - } - } - } - - return collisions; - }; - - /** - * Casts a ray segment against a set of bodies and returns all collisions, ray width is optional. Intersection points are not provided. - * @method ray - * @param {body[]} bodies - * @param {vector} startPoint - * @param {vector} endPoint - * @param {number} [rayWidth] - * @return {collision[]} Collisions - */ - Query.ray = function(bodies, startPoint, endPoint, rayWidth) { - rayWidth = rayWidth || 1e-100; - - var rayAngle = Vector.angle(startPoint, endPoint), - rayLength = Vector.magnitude(Vector.sub(startPoint, endPoint)), - rayX = (endPoint.x + startPoint.x) * 0.5, - rayY = (endPoint.y + startPoint.y) * 0.5, - ray = Bodies.rectangle(rayX, rayY, rayLength, rayWidth, { angle: rayAngle }), - collisions = Query.collides(ray, bodies); - - for (var i = 0; i < collisions.length; i += 1) { - var collision = collisions[i]; - collision.body = collision.bodyB = collision.bodyA; - } - - return collisions; - }; - - /** - * Returns all bodies whose bounds are inside (or outside if set) the given set of bounds, from the given set of bodies. - * @method region - * @param {body[]} bodies - * @param {bounds} bounds - * @param {bool} [outside=false] - * @return {body[]} The bodies matching the query - */ - Query.region = function(bodies, bounds, outside) { - var result = []; - - for (var i = 0; i < bodies.length; i++) { - var body = bodies[i], - overlaps = Bounds.overlaps(body.bounds, bounds); - if ((overlaps && !outside) || (!overlaps && outside)) - result.push(body); - } - - return result; - }; - - /** - * Returns all bodies whose vertices contain the given point, from the given set of bodies. - * @method point - * @param {body[]} bodies - * @param {vector} point - * @return {body[]} The bodies matching the query - */ - Query.point = function(bodies, point) { - var result = []; - - for (var i = 0; i < bodies.length; i++) { - var body = bodies[i]; - - if (Bounds.contains(body.bounds, point)) { - for (var j = body.parts.length === 1 ? 0 : 1; j < body.parts.length; j++) { - var part = body.parts[j]; - - if (Bounds.contains(part.bounds, point) - && Vertices.contains(part.vertices, point)) { - result.push(body); - break; - } - } - } - } - - return result; - }; - -})(); - - -/***/ }), -/* 26 */ -/***/ (function(module, exports, __webpack_require__) { - -/** -* The `Matter.Render` module is a lightweight, optional utility which provides a simple canvas based renderer for visualising instances of `Matter.Engine`. -* It is intended for development and debugging purposes, but may also be suitable for simple games. -* It includes a number of drawing options including wireframe, vector with support for sprites and viewports. -* -* @class Render -*/ - -var Render = {}; - -module.exports = Render; - -var Body = __webpack_require__(4); -var Common = __webpack_require__(0); -var Composite = __webpack_require__(6); -var Bounds = __webpack_require__(1); -var Events = __webpack_require__(5); -var Vector = __webpack_require__(2); -var Mouse = __webpack_require__(14); - -(function() { - - var _requestAnimationFrame, - _cancelAnimationFrame; - - if (typeof window !== 'undefined') { - _requestAnimationFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame - || window.mozRequestAnimationFrame || window.msRequestAnimationFrame - || function(callback){ window.setTimeout(function() { callback(Common.now()); }, 1000 / 60); }; - - _cancelAnimationFrame = window.cancelAnimationFrame || window.mozCancelAnimationFrame - || window.webkitCancelAnimationFrame || window.msCancelAnimationFrame; - } - - Render._goodFps = 30; - Render._goodDelta = 1000 / 60; - - /** - * Creates a new renderer. 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 {render} A new renderer - */ - Render.create = function(options) { - var defaults = { - engine: null, - element: null, - canvas: null, - mouse: null, - frameRequestId: null, - timing: { - historySize: 60, - delta: 0, - deltaHistory: [], - lastTime: 0, - lastTimestamp: 0, - lastElapsed: 0, - timestampElapsed: 0, - timestampElapsedHistory: [], - engineDeltaHistory: [], - engineElapsedHistory: [], - engineUpdatesHistory: [], - elapsedHistory: [] - }, - options: { - width: 800, - height: 600, - pixelRatio: 1, - background: '#14151f', - wireframeBackground: '#14151f', - wireframeStrokeStyle: '#bbb', - hasBounds: !!options.bounds, - enabled: true, - wireframes: true, - showSleeping: true, - showDebug: false, - showStats: false, - showPerformance: false, - showBounds: false, - showVelocity: false, - showCollisions: false, - showSeparations: false, - showAxes: false, - showPositions: false, - showAngleIndicator: false, - showIds: false, - showVertexNumbers: false, - showConvexHulls: false, - showInternalEdges: false, - showMousePosition: false - } - }; - - var render = Common.extend(defaults, options); - - if (render.canvas) { - render.canvas.width = render.options.width || render.canvas.width; - render.canvas.height = render.options.height || render.canvas.height; - } - - render.mouse = options.mouse; - render.engine = options.engine; - render.canvas = render.canvas || _createCanvas(render.options.width, render.options.height); - render.context = render.canvas.getContext('2d'); - render.textures = {}; - - render.bounds = render.bounds || { - min: { - x: 0, - y: 0 - }, - max: { - x: render.canvas.width, - y: render.canvas.height - } - }; - - // for temporary back compatibility only - render.controller = Render; - render.options.showBroadphase = false; - - if (render.options.pixelRatio !== 1) { - Render.setPixelRatio(render, render.options.pixelRatio); - } - - if (Common.isElement(render.element)) { - render.element.appendChild(render.canvas); - } - - return render; - }; - - /** - * Continuously updates the render canvas on the `requestAnimationFrame` event. - * @method run - * @param {render} render - */ - Render.run = function(render) { - (function loop(time){ - render.frameRequestId = _requestAnimationFrame(loop); - - _updateTiming(render, time); - - Render.world(render, time); - - render.context.setTransform(render.options.pixelRatio, 0, 0, render.options.pixelRatio, 0, 0); - - if (render.options.showStats || render.options.showDebug) { - Render.stats(render, render.context, time); - } - - if (render.options.showPerformance || render.options.showDebug) { - Render.performance(render, render.context, time); - } - - render.context.setTransform(1, 0, 0, 1, 0, 0); - })(); - }; - - /** - * Ends execution of `Render.run` on the given `render`, by canceling the animation frame request event loop. - * @method stop - * @param {render} render - */ - Render.stop = function(render) { - _cancelAnimationFrame(render.frameRequestId); - }; - - /** - * Sets the pixel ratio of the renderer and updates the canvas. - * To automatically detect the correct ratio, pass the string `'auto'` for `pixelRatio`. - * @method setPixelRatio - * @param {render} render - * @param {number} pixelRatio - */ - Render.setPixelRatio = function(render, pixelRatio) { - var options = render.options, - canvas = render.canvas; - - if (pixelRatio === 'auto') { - pixelRatio = _getPixelRatio(canvas); - } - - options.pixelRatio = pixelRatio; - canvas.setAttribute('data-pixel-ratio', pixelRatio); - canvas.width = options.width * pixelRatio; - canvas.height = options.height * pixelRatio; - canvas.style.width = options.width + 'px'; - canvas.style.height = options.height + 'px'; - }; - - /** - * Sets the render `width` and `height`. - * - * Updates the canvas accounting for `render.options.pixelRatio`. - * - * Updates the bottom right render bound `render.bounds.max` relative to the provided `width` and `height`. - * The top left render bound `render.bounds.min` isn't changed. - * - * Follow this call with `Render.lookAt` if you need to change the render bounds. - * - * See also `Render.setPixelRatio`. - * @method setSize - * @param {render} render - * @param {number} width The width (in CSS pixels) - * @param {number} height The height (in CSS pixels) - */ - Render.setSize = function(render, width, height) { - render.options.width = width; - render.options.height = height; - render.bounds.max.x = render.bounds.min.x + width; - render.bounds.max.y = render.bounds.min.y + height; - - if (render.options.pixelRatio !== 1) { - Render.setPixelRatio(render, render.options.pixelRatio); - } else { - render.canvas.width = width; - render.canvas.height = height; - } - }; - - /** - * Positions and sizes the viewport around the given object bounds. - * Objects must have at least one of the following properties: - * - `object.bounds` - * - `object.position` - * - `object.min` and `object.max` - * - `object.x` and `object.y` - * @method lookAt - * @param {render} render - * @param {object[]} objects - * @param {vector} [padding] - * @param {bool} [center=true] - */ - Render.lookAt = function(render, objects, padding, center) { - center = typeof center !== 'undefined' ? center : true; - objects = Common.isArray(objects) ? objects : [objects]; - padding = padding || { - x: 0, - y: 0 - }; - - // find bounds of all objects - var bounds = { - min: { x: Infinity, y: Infinity }, - max: { x: -Infinity, y: -Infinity } - }; - - for (var i = 0; i < objects.length; i += 1) { - var object = objects[i], - min = object.bounds ? object.bounds.min : (object.min || object.position || object), - max = object.bounds ? object.bounds.max : (object.max || object.position || object); - - if (min && max) { - if (min.x < bounds.min.x) - bounds.min.x = min.x; - - if (max.x > bounds.max.x) - bounds.max.x = max.x; - - if (min.y < bounds.min.y) - bounds.min.y = min.y; - - if (max.y > bounds.max.y) - bounds.max.y = max.y; - } - } - - // find ratios - var width = (bounds.max.x - bounds.min.x) + 2 * padding.x, - height = (bounds.max.y - bounds.min.y) + 2 * padding.y, - viewHeight = render.canvas.height, - viewWidth = render.canvas.width, - outerRatio = viewWidth / viewHeight, - innerRatio = width / height, - scaleX = 1, - scaleY = 1; - - // find scale factor - if (innerRatio > outerRatio) { - scaleY = innerRatio / outerRatio; - } else { - scaleX = outerRatio / innerRatio; - } - - // enable bounds - render.options.hasBounds = true; - - // position and size - render.bounds.min.x = bounds.min.x; - render.bounds.max.x = bounds.min.x + width * scaleX; - render.bounds.min.y = bounds.min.y; - render.bounds.max.y = bounds.min.y + height * scaleY; - - // center - if (center) { - render.bounds.min.x += width * 0.5 - (width * scaleX) * 0.5; - render.bounds.max.x += width * 0.5 - (width * scaleX) * 0.5; - render.bounds.min.y += height * 0.5 - (height * scaleY) * 0.5; - render.bounds.max.y += height * 0.5 - (height * scaleY) * 0.5; - } - - // padding - render.bounds.min.x -= padding.x; - render.bounds.max.x -= padding.x; - render.bounds.min.y -= padding.y; - render.bounds.max.y -= padding.y; - - // update mouse - if (render.mouse) { - Mouse.setScale(render.mouse, { - x: (render.bounds.max.x - render.bounds.min.x) / render.canvas.width, - y: (render.bounds.max.y - render.bounds.min.y) / render.canvas.height - }); - - Mouse.setOffset(render.mouse, render.bounds.min); - } - }; - - /** - * Applies viewport transforms based on `render.bounds` to a render context. - * @method startViewTransform - * @param {render} render - */ - Render.startViewTransform = function(render) { - var boundsWidth = render.bounds.max.x - render.bounds.min.x, - boundsHeight = render.bounds.max.y - render.bounds.min.y, - boundsScaleX = boundsWidth / render.options.width, - boundsScaleY = boundsHeight / render.options.height; - - render.context.setTransform( - render.options.pixelRatio / boundsScaleX, 0, 0, - render.options.pixelRatio / boundsScaleY, 0, 0 - ); - - render.context.translate(-render.bounds.min.x, -render.bounds.min.y); - }; - - /** - * Resets all transforms on the render context. - * @method endViewTransform - * @param {render} render - */ - Render.endViewTransform = function(render) { - render.context.setTransform(render.options.pixelRatio, 0, 0, render.options.pixelRatio, 0, 0); - }; - - /** - * Renders the given `engine`'s `Matter.World` object. - * This is the entry point for all rendering and should be called every time the scene changes. - * @method world - * @param {render} render - */ - Render.world = function(render, time) { - var startTime = Common.now(), - engine = render.engine, - world = engine.world, - canvas = render.canvas, - context = render.context, - options = render.options, - timing = render.timing; - - var allBodies = Composite.allBodies(world), - allConstraints = Composite.allConstraints(world), - background = options.wireframes ? options.wireframeBackground : options.background, - bodies = [], - constraints = [], - i; - - var event = { - timestamp: engine.timing.timestamp - }; - - Events.trigger(render, 'beforeRender', event); - - // apply background if it has changed - if (render.currentBackground !== background) - _applyBackground(render, background); - - // clear the canvas with a transparent fill, to allow the canvas background to show - context.globalCompositeOperation = 'source-in'; - context.fillStyle = "transparent"; - context.fillRect(0, 0, canvas.width, canvas.height); - context.globalCompositeOperation = 'source-over'; - - // handle bounds - if (options.hasBounds) { - // filter out bodies that are not in view - for (i = 0; i < allBodies.length; i++) { - var body = allBodies[i]; - if (Bounds.overlaps(body.bounds, render.bounds)) - bodies.push(body); - } - - // filter out constraints that are not in view - for (i = 0; i < allConstraints.length; i++) { - var constraint = allConstraints[i], - bodyA = constraint.bodyA, - bodyB = constraint.bodyB, - pointAWorld = constraint.pointA, - pointBWorld = constraint.pointB; - - if (bodyA) pointAWorld = Vector.add(bodyA.position, constraint.pointA); - if (bodyB) pointBWorld = Vector.add(bodyB.position, constraint.pointB); - - if (!pointAWorld || !pointBWorld) - continue; - - if (Bounds.contains(render.bounds, pointAWorld) || Bounds.contains(render.bounds, pointBWorld)) - constraints.push(constraint); - } - - // transform the view - Render.startViewTransform(render); - - // update mouse - if (render.mouse) { - Mouse.setScale(render.mouse, { - x: (render.bounds.max.x - render.bounds.min.x) / render.options.width, - y: (render.bounds.max.y - render.bounds.min.y) / render.options.height - }); - - Mouse.setOffset(render.mouse, render.bounds.min); - } - } else { - constraints = allConstraints; - bodies = allBodies; - - if (render.options.pixelRatio !== 1) { - render.context.setTransform(render.options.pixelRatio, 0, 0, render.options.pixelRatio, 0, 0); - } - } - - if (!options.wireframes || (engine.enableSleeping && options.showSleeping)) { - // fully featured rendering of bodies - Render.bodies(render, bodies, context); - } else { - if (options.showConvexHulls) - Render.bodyConvexHulls(render, bodies, context); - - // optimised method for wireframes only - Render.bodyWireframes(render, bodies, context); - } - - if (options.showBounds) - Render.bodyBounds(render, bodies, context); - - if (options.showAxes || options.showAngleIndicator) - Render.bodyAxes(render, bodies, context); - - if (options.showPositions) - Render.bodyPositions(render, bodies, context); - - if (options.showVelocity) - Render.bodyVelocity(render, bodies, context); - - if (options.showIds) - Render.bodyIds(render, bodies, context); - - if (options.showSeparations) - Render.separations(render, engine.pairs.list, context); - - if (options.showCollisions) - Render.collisions(render, engine.pairs.list, context); - - if (options.showVertexNumbers) - Render.vertexNumbers(render, bodies, context); - - if (options.showMousePosition) - Render.mousePosition(render, render.mouse, context); - - Render.constraints(constraints, context); - - if (options.hasBounds) { - // revert view transforms - Render.endViewTransform(render); - } - - Events.trigger(render, 'afterRender', event); - - // log the time elapsed computing this update - timing.lastElapsed = Common.now() - startTime; - }; - - /** - * Renders statistics about the engine and world useful for debugging. - * @private - * @method stats - * @param {render} render - * @param {RenderingContext} context - * @param {Number} time - */ - Render.stats = function(render, context, time) { - var engine = render.engine, - world = engine.world, - bodies = Composite.allBodies(world), - parts = 0, - width = 55, - height = 44, - x = 0, - y = 0; - - // count parts - for (var i = 0; i < bodies.length; i += 1) { - parts += bodies[i].parts.length; - } - - // sections - var sections = { - 'Part': parts, - 'Body': bodies.length, - 'Cons': Composite.allConstraints(world).length, - 'Comp': Composite.allComposites(world).length, - 'Pair': engine.pairs.list.length - }; - - // background - context.fillStyle = '#0e0f19'; - context.fillRect(x, y, width * 5.5, height); - - context.font = '12px Arial'; - context.textBaseline = 'top'; - context.textAlign = 'right'; - - // sections - for (var key in sections) { - var section = sections[key]; - // label - context.fillStyle = '#aaa'; - context.fillText(key, x + width, y + 8); - - // value - context.fillStyle = '#eee'; - context.fillText(section, x + width, y + 26); - - x += width; - } - }; - - /** - * Renders engine and render performance information. - * @private - * @method performance - * @param {render} render - * @param {RenderingContext} context - */ - Render.performance = function(render, context) { - var engine = render.engine, - timing = render.timing, - deltaHistory = timing.deltaHistory, - elapsedHistory = timing.elapsedHistory, - timestampElapsedHistory = timing.timestampElapsedHistory, - engineDeltaHistory = timing.engineDeltaHistory, - engineUpdatesHistory = timing.engineUpdatesHistory, - engineElapsedHistory = timing.engineElapsedHistory, - lastEngineUpdatesPerFrame = engine.timing.lastUpdatesPerFrame, - lastEngineDelta = engine.timing.lastDelta; - - var deltaMean = _mean(deltaHistory), - elapsedMean = _mean(elapsedHistory), - engineDeltaMean = _mean(engineDeltaHistory), - engineUpdatesMean = _mean(engineUpdatesHistory), - engineElapsedMean = _mean(engineElapsedHistory), - timestampElapsedMean = _mean(timestampElapsedHistory), - rateMean = (timestampElapsedMean / deltaMean) || 0, - neededUpdatesPerFrame = Math.round(deltaMean / lastEngineDelta), - fps = (1000 / deltaMean) || 0; - - var graphHeight = 4, - gap = 12, - width = 60, - height = 34, - x = 10, - y = 69; - - // background - context.fillStyle = '#0e0f19'; - context.fillRect(0, 50, gap * 5 + width * 6 + 22, height); - - // show FPS - Render.status( - context, x, y, width, graphHeight, deltaHistory.length, - Math.round(fps) + ' fps', - fps / Render._goodFps, - function(i) { return (deltaHistory[i] / deltaMean) - 1; } - ); - - // show engine delta - Render.status( - context, x + gap + width, y, width, graphHeight, engineDeltaHistory.length, - lastEngineDelta.toFixed(2) + ' dt', - Render._goodDelta / lastEngineDelta, - function(i) { return (engineDeltaHistory[i] / engineDeltaMean) - 1; } - ); - - // show engine updates per frame - Render.status( - context, x + (gap + width) * 2, y, width, graphHeight, engineUpdatesHistory.length, - lastEngineUpdatesPerFrame + ' upf', - Math.pow(Common.clamp((engineUpdatesMean / neededUpdatesPerFrame) || 1, 0, 1), 4), - function(i) { return (engineUpdatesHistory[i] / engineUpdatesMean) - 1; } - ); - - // show engine update time - Render.status( - context, x + (gap + width) * 3, y, width, graphHeight, engineElapsedHistory.length, - engineElapsedMean.toFixed(2) + ' ut', - 1 - (lastEngineUpdatesPerFrame * engineElapsedMean / Render._goodFps), - function(i) { return (engineElapsedHistory[i] / engineElapsedMean) - 1; } - ); - - // show render time - Render.status( - context, x + (gap + width) * 4, y, width, graphHeight, elapsedHistory.length, - elapsedMean.toFixed(2) + ' rt', - 1 - (elapsedMean / Render._goodFps), - function(i) { return (elapsedHistory[i] / elapsedMean) - 1; } - ); - - // show effective speed - Render.status( - context, x + (gap + width) * 5, y, width, graphHeight, timestampElapsedHistory.length, - rateMean.toFixed(2) + ' x', - rateMean * rateMean * rateMean, - function(i) { return (((timestampElapsedHistory[i] / deltaHistory[i]) / rateMean) || 0) - 1; } - ); - }; - - /** - * Renders a label, indicator and a chart. - * @private - * @method status - * @param {RenderingContext} context - * @param {number} x - * @param {number} y - * @param {number} width - * @param {number} height - * @param {number} count - * @param {string} label - * @param {string} indicator - * @param {function} plotY - */ - Render.status = function(context, x, y, width, height, count, label, indicator, plotY) { - // background - context.strokeStyle = '#888'; - context.fillStyle = '#444'; - context.lineWidth = 1; - context.fillRect(x, y + 7, width, 1); - - // chart - context.beginPath(); - context.moveTo(x, y + 7 - height * Common.clamp(0.4 * plotY(0), -2, 2)); - for (var i = 0; i < width; i += 1) { - context.lineTo(x + i, y + 7 - (i < count ? height * Common.clamp(0.4 * plotY(i), -2, 2) : 0)); - } - context.stroke(); - - // indicator - context.fillStyle = 'hsl(' + Common.clamp(25 + 95 * indicator, 0, 120) + ',100%,60%)'; - context.fillRect(x, y - 7, 4, 4); - - // label - context.font = '12px Arial'; - context.textBaseline = 'middle'; - context.textAlign = 'right'; - context.fillStyle = '#eee'; - context.fillText(label, x + width, y - 5); - }; - - /** - * Description - * @private - * @method constraints - * @param {constraint[]} constraints - * @param {RenderingContext} context - */ - Render.constraints = function(constraints, context) { - var c = context; - - for (var i = 0; i < constraints.length; i++) { - var constraint = constraints[i]; - - if (!constraint.render.visible || !constraint.pointA || !constraint.pointB) - continue; - - var bodyA = constraint.bodyA, - bodyB = constraint.bodyB, - start, - end; - - if (bodyA) { - start = Vector.add(bodyA.position, constraint.pointA); - } else { - start = constraint.pointA; - } - - if (constraint.render.type === 'pin') { - c.beginPath(); - c.arc(start.x, start.y, 3, 0, 2 * Math.PI); - c.closePath(); - } else { - if (bodyB) { - end = Vector.add(bodyB.position, constraint.pointB); - } else { - end = constraint.pointB; - } - - c.beginPath(); - c.moveTo(start.x, start.y); - - if (constraint.render.type === 'spring') { - var delta = Vector.sub(end, start), - normal = Vector.perp(Vector.normalise(delta)), - coils = Math.ceil(Common.clamp(constraint.length / 5, 12, 20)), - offset; - - for (var j = 1; j < coils; j += 1) { - offset = j % 2 === 0 ? 1 : -1; - - c.lineTo( - start.x + delta.x * (j / coils) + normal.x * offset * 4, - start.y + delta.y * (j / coils) + normal.y * offset * 4 - ); - } - } - - c.lineTo(end.x, end.y); - } - - if (constraint.render.lineWidth) { - c.lineWidth = constraint.render.lineWidth; - c.strokeStyle = constraint.render.strokeStyle; - c.stroke(); - } - - if (constraint.render.anchors) { - c.fillStyle = constraint.render.strokeStyle; - c.beginPath(); - c.arc(start.x, start.y, 3, 0, 2 * Math.PI); - c.arc(end.x, end.y, 3, 0, 2 * Math.PI); - c.closePath(); - c.fill(); - } - } - }; - - /** - * Description - * @private - * @method bodies - * @param {render} render - * @param {body[]} bodies - * @param {RenderingContext} context - */ - Render.bodies = function(render, bodies, context) { - var c = context, - engine = render.engine, - options = render.options, - showInternalEdges = options.showInternalEdges || !options.wireframes, - body, - part, - i, - k; - - for (i = 0; i < bodies.length; i++) { - body = bodies[i]; - - if (!body.render.visible) - continue; - - // handle compound parts - for (k = body.parts.length > 1 ? 1 : 0; k < body.parts.length; k++) { - part = body.parts[k]; - - if (!part.render.visible) - continue; - - if (options.showSleeping && body.isSleeping) { - c.globalAlpha = 0.5 * part.render.opacity; - } else if (part.render.opacity !== 1) { - c.globalAlpha = part.render.opacity; - } - - if (part.render.sprite && part.render.sprite.texture && !options.wireframes) { - // part sprite - var sprite = part.render.sprite, - texture = _getTexture(render, sprite.texture); - - c.translate(part.position.x, part.position.y); - c.rotate(part.angle); - - c.drawImage( - texture, - texture.width * -sprite.xOffset * sprite.xScale, - texture.height * -sprite.yOffset * sprite.yScale, - texture.width * sprite.xScale, - texture.height * sprite.yScale - ); - - // revert translation, hopefully faster than save / restore - c.rotate(-part.angle); - c.translate(-part.position.x, -part.position.y); - } else { - // part polygon - if (part.circleRadius) { - c.beginPath(); - c.arc(part.position.x, part.position.y, part.circleRadius, 0, 2 * Math.PI); - } else { - c.beginPath(); - c.moveTo(part.vertices[0].x, part.vertices[0].y); - - for (var j = 1; j < part.vertices.length; j++) { - if (!part.vertices[j - 1].isInternal || showInternalEdges) { - c.lineTo(part.vertices[j].x, part.vertices[j].y); - } else { - c.moveTo(part.vertices[j].x, part.vertices[j].y); - } - - if (part.vertices[j].isInternal && !showInternalEdges) { - c.moveTo(part.vertices[(j + 1) % part.vertices.length].x, part.vertices[(j + 1) % part.vertices.length].y); - } - } - - c.lineTo(part.vertices[0].x, part.vertices[0].y); - c.closePath(); - } - - if (!options.wireframes) { - c.fillStyle = part.render.fillStyle; - - if (part.render.lineWidth) { - c.lineWidth = part.render.lineWidth; - c.strokeStyle = part.render.strokeStyle; - c.stroke(); - } - - c.fill(); - } else { - c.lineWidth = 1; - c.strokeStyle = render.options.wireframeStrokeStyle; - c.stroke(); - } - } - - c.globalAlpha = 1; - } - } - }; - - /** - * Optimised method for drawing body wireframes in one pass - * @private - * @method bodyWireframes - * @param {render} render - * @param {body[]} bodies - * @param {RenderingContext} context - */ - Render.bodyWireframes = function(render, bodies, context) { - var c = context, - showInternalEdges = render.options.showInternalEdges, - body, - part, - i, - j, - k; - - c.beginPath(); - - // render all bodies - for (i = 0; i < bodies.length; i++) { - body = bodies[i]; - - if (!body.render.visible) - continue; - - // handle compound parts - for (k = body.parts.length > 1 ? 1 : 0; k < body.parts.length; k++) { - part = body.parts[k]; - - c.moveTo(part.vertices[0].x, part.vertices[0].y); - - for (j = 1; j < part.vertices.length; j++) { - if (!part.vertices[j - 1].isInternal || showInternalEdges) { - c.lineTo(part.vertices[j].x, part.vertices[j].y); - } else { - c.moveTo(part.vertices[j].x, part.vertices[j].y); - } - - if (part.vertices[j].isInternal && !showInternalEdges) { - c.moveTo(part.vertices[(j + 1) % part.vertices.length].x, part.vertices[(j + 1) % part.vertices.length].y); - } - } - - c.lineTo(part.vertices[0].x, part.vertices[0].y); - } - } - - c.lineWidth = 1; - c.strokeStyle = render.options.wireframeStrokeStyle; - c.stroke(); - }; - - /** - * Optimised method for drawing body convex hull wireframes in one pass - * @private - * @method bodyConvexHulls - * @param {render} render - * @param {body[]} bodies - * @param {RenderingContext} context - */ - Render.bodyConvexHulls = function(render, bodies, context) { - var c = context, - body, - part, - i, - j, - k; - - c.beginPath(); - - // render convex hulls - for (i = 0; i < bodies.length; i++) { - body = bodies[i]; - - if (!body.render.visible || body.parts.length === 1) - continue; - - c.moveTo(body.vertices[0].x, body.vertices[0].y); - - for (j = 1; j < body.vertices.length; j++) { - c.lineTo(body.vertices[j].x, body.vertices[j].y); - } - - c.lineTo(body.vertices[0].x, body.vertices[0].y); - } - - c.lineWidth = 1; - c.strokeStyle = 'rgba(255,255,255,0.2)'; - c.stroke(); - }; - - /** - * Renders body vertex numbers. - * @private - * @method vertexNumbers - * @param {render} render - * @param {body[]} bodies - * @param {RenderingContext} context - */ - Render.vertexNumbers = function(render, bodies, context) { - var c = context, - i, - j, - k; - - for (i = 0; i < bodies.length; i++) { - var parts = bodies[i].parts; - for (k = parts.length > 1 ? 1 : 0; k < parts.length; k++) { - var part = parts[k]; - for (j = 0; j < part.vertices.length; j++) { - c.fillStyle = 'rgba(255,255,255,0.2)'; - c.fillText(i + '_' + j, part.position.x + (part.vertices[j].x - part.position.x) * 0.8, part.position.y + (part.vertices[j].y - part.position.y) * 0.8); - } - } - } - }; - - /** - * Renders mouse position. - * @private - * @method mousePosition - * @param {render} render - * @param {mouse} mouse - * @param {RenderingContext} context - */ - Render.mousePosition = function(render, mouse, context) { - var c = context; - c.fillStyle = 'rgba(255,255,255,0.8)'; - c.fillText(mouse.position.x + ' ' + mouse.position.y, mouse.position.x + 5, mouse.position.y - 5); - }; - - /** - * Draws body bounds - * @private - * @method bodyBounds - * @param {render} render - * @param {body[]} bodies - * @param {RenderingContext} context - */ - Render.bodyBounds = function(render, bodies, context) { - var c = context, - engine = render.engine, - options = render.options; - - c.beginPath(); - - for (var i = 0; i < bodies.length; i++) { - var body = bodies[i]; - - if (body.render.visible) { - var parts = bodies[i].parts; - for (var j = parts.length > 1 ? 1 : 0; j < parts.length; j++) { - var part = parts[j]; - c.rect(part.bounds.min.x, part.bounds.min.y, part.bounds.max.x - part.bounds.min.x, part.bounds.max.y - part.bounds.min.y); - } - } - } - - if (options.wireframes) { - c.strokeStyle = 'rgba(255,255,255,0.08)'; - } else { - c.strokeStyle = 'rgba(0,0,0,0.1)'; - } - - c.lineWidth = 1; - c.stroke(); - }; - - /** - * Draws body angle indicators and axes - * @private - * @method bodyAxes - * @param {render} render - * @param {body[]} bodies - * @param {RenderingContext} context - */ - Render.bodyAxes = function(render, bodies, context) { - var c = context, - engine = render.engine, - options = render.options, - part, - i, - j, - k; - - c.beginPath(); - - for (i = 0; i < bodies.length; i++) { - var body = bodies[i], - parts = body.parts; - - if (!body.render.visible) - continue; - - if (options.showAxes) { - // render all axes - for (j = parts.length > 1 ? 1 : 0; j < parts.length; j++) { - part = parts[j]; - for (k = 0; k < part.axes.length; k++) { - var axis = part.axes[k]; - c.moveTo(part.position.x, part.position.y); - c.lineTo(part.position.x + axis.x * 20, part.position.y + axis.y * 20); - } - } - } else { - for (j = parts.length > 1 ? 1 : 0; j < parts.length; j++) { - part = parts[j]; - for (k = 0; k < part.axes.length; k++) { - // render a single axis indicator - c.moveTo(part.position.x, part.position.y); - c.lineTo((part.vertices[0].x + part.vertices[part.vertices.length-1].x) / 2, - (part.vertices[0].y + part.vertices[part.vertices.length-1].y) / 2); - } - } - } - } - - if (options.wireframes) { - c.strokeStyle = 'indianred'; - c.lineWidth = 1; - } else { - c.strokeStyle = 'rgba(255, 255, 255, 0.4)'; - c.globalCompositeOperation = 'overlay'; - c.lineWidth = 2; - } - - c.stroke(); - c.globalCompositeOperation = 'source-over'; - }; - - /** - * Draws body positions - * @private - * @method bodyPositions - * @param {render} render - * @param {body[]} bodies - * @param {RenderingContext} context - */ - Render.bodyPositions = function(render, bodies, context) { - var c = context, - engine = render.engine, - options = render.options, - body, - part, - i, - k; - - c.beginPath(); - - // render current positions - for (i = 0; i < bodies.length; i++) { - body = bodies[i]; - - if (!body.render.visible) - continue; - - // handle compound parts - for (k = 0; k < body.parts.length; k++) { - part = body.parts[k]; - c.arc(part.position.x, part.position.y, 3, 0, 2 * Math.PI, false); - c.closePath(); - } - } - - if (options.wireframes) { - c.fillStyle = 'indianred'; - } else { - c.fillStyle = 'rgba(0,0,0,0.5)'; - } - c.fill(); - - c.beginPath(); - - // render previous positions - for (i = 0; i < bodies.length; i++) { - body = bodies[i]; - if (body.render.visible) { - c.arc(body.positionPrev.x, body.positionPrev.y, 2, 0, 2 * Math.PI, false); - c.closePath(); - } - } - - c.fillStyle = 'rgba(255,165,0,0.8)'; - c.fill(); - }; - - /** - * Draws body velocity - * @private - * @method bodyVelocity - * @param {render} render - * @param {body[]} bodies - * @param {RenderingContext} context - */ - Render.bodyVelocity = function(render, bodies, context) { - var c = context; - - c.beginPath(); - - for (var i = 0; i < bodies.length; i++) { - var body = bodies[i]; - - if (!body.render.visible) - continue; - - var velocity = Body.getVelocity(body); - - c.moveTo(body.position.x, body.position.y); - c.lineTo(body.position.x + velocity.x, body.position.y + velocity.y); - } - - c.lineWidth = 3; - c.strokeStyle = 'cornflowerblue'; - c.stroke(); - }; - - /** - * Draws body ids - * @private - * @method bodyIds - * @param {render} render - * @param {body[]} bodies - * @param {RenderingContext} context - */ - Render.bodyIds = function(render, bodies, context) { - var c = context, - i, - j; - - for (i = 0; i < bodies.length; i++) { - if (!bodies[i].render.visible) - continue; - - var parts = bodies[i].parts; - for (j = parts.length > 1 ? 1 : 0; j < parts.length; j++) { - var part = parts[j]; - c.font = "12px Arial"; - c.fillStyle = 'rgba(255,255,255,0.5)'; - c.fillText(part.id, part.position.x + 10, part.position.y - 10); - } - } - }; - - /** - * Description - * @private - * @method collisions - * @param {render} render - * @param {pair[]} pairs - * @param {RenderingContext} context - */ - Render.collisions = function(render, pairs, context) { - var c = context, - options = render.options, - pair, - collision, - corrected, - bodyA, - bodyB, - i, - j; - - c.beginPath(); - - // render collision positions - for (i = 0; i < pairs.length; i++) { - pair = pairs[i]; - - if (!pair.isActive) - continue; - - collision = pair.collision; - for (j = 0; j < pair.activeContacts.length; j++) { - var contact = pair.activeContacts[j], - vertex = contact.vertex; - c.rect(vertex.x - 1.5, vertex.y - 1.5, 3.5, 3.5); - } - } - - if (options.wireframes) { - c.fillStyle = 'rgba(255,255,255,0.7)'; - } else { - c.fillStyle = 'orange'; - } - c.fill(); - - c.beginPath(); - - // render collision normals - for (i = 0; i < pairs.length; i++) { - pair = pairs[i]; - - if (!pair.isActive) - continue; - - collision = pair.collision; - - if (pair.activeContacts.length > 0) { - var normalPosX = pair.activeContacts[0].vertex.x, - normalPosY = pair.activeContacts[0].vertex.y; - - if (pair.activeContacts.length === 2) { - normalPosX = (pair.activeContacts[0].vertex.x + pair.activeContacts[1].vertex.x) / 2; - normalPosY = (pair.activeContacts[0].vertex.y + pair.activeContacts[1].vertex.y) / 2; - } - - if (collision.bodyB === collision.supports[0].body || collision.bodyA.isStatic === true) { - c.moveTo(normalPosX - collision.normal.x * 8, normalPosY - collision.normal.y * 8); - } else { - c.moveTo(normalPosX + collision.normal.x * 8, normalPosY + collision.normal.y * 8); - } - - c.lineTo(normalPosX, normalPosY); - } - } - - if (options.wireframes) { - c.strokeStyle = 'rgba(255,165,0,0.7)'; - } else { - c.strokeStyle = 'orange'; - } - - c.lineWidth = 1; - c.stroke(); - }; - - /** - * Description - * @private - * @method separations - * @param {render} render - * @param {pair[]} pairs - * @param {RenderingContext} context - */ - Render.separations = function(render, pairs, context) { - var c = context, - options = render.options, - pair, - collision, - corrected, - bodyA, - bodyB, - i, - j; - - c.beginPath(); - - // render separations - for (i = 0; i < pairs.length; i++) { - pair = pairs[i]; - - if (!pair.isActive) - continue; - - collision = pair.collision; - bodyA = collision.bodyA; - bodyB = collision.bodyB; - - var k = 1; - - if (!bodyB.isStatic && !bodyA.isStatic) k = 0.5; - if (bodyB.isStatic) k = 0; - - c.moveTo(bodyB.position.x, bodyB.position.y); - c.lineTo(bodyB.position.x - collision.penetration.x * k, bodyB.position.y - collision.penetration.y * k); - - k = 1; - - if (!bodyB.isStatic && !bodyA.isStatic) k = 0.5; - if (bodyA.isStatic) k = 0; - - c.moveTo(bodyA.position.x, bodyA.position.y); - c.lineTo(bodyA.position.x + collision.penetration.x * k, bodyA.position.y + collision.penetration.y * k); - } - - if (options.wireframes) { - c.strokeStyle = 'rgba(255,165,0,0.5)'; - } else { - c.strokeStyle = 'orange'; - } - c.stroke(); - }; - - /** - * Description - * @private - * @method inspector - * @param {inspector} inspector - * @param {RenderingContext} context - */ - Render.inspector = function(inspector, context) { - var engine = inspector.engine, - selected = inspector.selected, - render = inspector.render, - options = render.options, - bounds; - - if (options.hasBounds) { - var boundsWidth = render.bounds.max.x - render.bounds.min.x, - boundsHeight = render.bounds.max.y - render.bounds.min.y, - boundsScaleX = boundsWidth / render.options.width, - boundsScaleY = boundsHeight / render.options.height; - - context.scale(1 / boundsScaleX, 1 / boundsScaleY); - context.translate(-render.bounds.min.x, -render.bounds.min.y); - } - - for (var i = 0; i < selected.length; i++) { - var item = selected[i].data; - - context.translate(0.5, 0.5); - context.lineWidth = 1; - context.strokeStyle = 'rgba(255,165,0,0.9)'; - context.setLineDash([1,2]); - - switch (item.type) { - - case 'body': - - // render body selections - bounds = item.bounds; - context.beginPath(); - context.rect(Math.floor(bounds.min.x - 3), Math.floor(bounds.min.y - 3), - Math.floor(bounds.max.x - bounds.min.x + 6), Math.floor(bounds.max.y - bounds.min.y + 6)); - context.closePath(); - context.stroke(); - - break; - - case 'constraint': - - // render constraint selections - var point = item.pointA; - if (item.bodyA) - point = item.pointB; - context.beginPath(); - context.arc(point.x, point.y, 10, 0, 2 * Math.PI); - context.closePath(); - context.stroke(); - - break; - - } - - context.setLineDash([]); - context.translate(-0.5, -0.5); - } - - // render selection region - if (inspector.selectStart !== null) { - context.translate(0.5, 0.5); - context.lineWidth = 1; - context.strokeStyle = 'rgba(255,165,0,0.6)'; - context.fillStyle = 'rgba(255,165,0,0.1)'; - bounds = inspector.selectBounds; - context.beginPath(); - context.rect(Math.floor(bounds.min.x), Math.floor(bounds.min.y), - Math.floor(bounds.max.x - bounds.min.x), Math.floor(bounds.max.y - bounds.min.y)); - context.closePath(); - context.stroke(); - context.fill(); - context.translate(-0.5, -0.5); - } - - if (options.hasBounds) - context.setTransform(1, 0, 0, 1, 0, 0); - }; - - /** - * Updates render timing. - * @method _updateTiming - * @private - * @param {render} render - * @param {number} time - */ - var _updateTiming = function(render, time) { - var engine = render.engine, - timing = render.timing, - historySize = timing.historySize, - timestamp = engine.timing.timestamp; - - timing.delta = time - timing.lastTime || Render._goodDelta; - timing.lastTime = time; - - timing.timestampElapsed = timestamp - timing.lastTimestamp || 0; - timing.lastTimestamp = timestamp; - - timing.deltaHistory.unshift(timing.delta); - timing.deltaHistory.length = Math.min(timing.deltaHistory.length, historySize); - - timing.engineDeltaHistory.unshift(engine.timing.lastDelta); - timing.engineDeltaHistory.length = Math.min(timing.engineDeltaHistory.length, historySize); - - timing.timestampElapsedHistory.unshift(timing.timestampElapsed); - timing.timestampElapsedHistory.length = Math.min(timing.timestampElapsedHistory.length, historySize); - - timing.engineUpdatesHistory.unshift(engine.timing.lastUpdatesPerFrame); - timing.engineUpdatesHistory.length = Math.min(timing.engineUpdatesHistory.length, historySize); - - timing.engineElapsedHistory.unshift(engine.timing.lastElapsed); - timing.engineElapsedHistory.length = Math.min(timing.engineElapsedHistory.length, historySize); - - timing.elapsedHistory.unshift(timing.lastElapsed); - timing.elapsedHistory.length = Math.min(timing.elapsedHistory.length, historySize); - }; - - /** - * Returns the mean value of the given numbers. - * @method _mean - * @private - * @param {Number[]} values - * @return {Number} the mean of given values - */ - var _mean = function(values) { - var result = 0; - for (var i = 0; i < values.length; i += 1) { - result += values[i]; - } - return (result / values.length) || 0; - }; - - /** - * @method _createCanvas - * @private - * @param {} width - * @param {} height - * @return canvas - */ - var _createCanvas = function(width, height) { - var canvas = document.createElement('canvas'); - canvas.width = width; - canvas.height = height; - canvas.oncontextmenu = function() { return false; }; - canvas.onselectstart = function() { return false; }; - return canvas; - }; - - /** - * Gets the pixel ratio of the canvas. - * @method _getPixelRatio - * @private - * @param {HTMLElement} canvas - * @return {Number} pixel ratio - */ - var _getPixelRatio = function(canvas) { - var context = canvas.getContext('2d'), - devicePixelRatio = window.devicePixelRatio || 1, - backingStorePixelRatio = context.webkitBackingStorePixelRatio || context.mozBackingStorePixelRatio - || context.msBackingStorePixelRatio || context.oBackingStorePixelRatio - || context.backingStorePixelRatio || 1; - - return devicePixelRatio / backingStorePixelRatio; - }; - - /** - * Gets the requested texture (an Image) via its path - * @method _getTexture - * @private - * @param {render} render - * @param {string} imagePath - * @return {Image} texture - */ - var _getTexture = function(render, imagePath) { - var image = render.textures[imagePath]; - - if (image) - return image; - - image = render.textures[imagePath] = new Image(); - image.src = imagePath; - - return image; - }; - - /** - * Applies the background to the canvas using CSS. - * @method applyBackground - * @private - * @param {render} render - * @param {string} background - */ - var _applyBackground = function(render, background) { - var cssBackground = background; - - if (/(jpg|gif|png)$/.test(background)) - cssBackground = 'url(' + background + ')'; - - render.canvas.style.background = cssBackground; - render.canvas.style.backgroundSize = "contain"; - render.currentBackground = background; - }; - - /* - * - * Events Documentation - * - */ - - /** - * Fired before rendering - * - * @event beforeRender - * @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 rendering - * - * @event afterRender - * @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 - */ - - /* - * - * Properties Documentation - * - */ - - /** - * A back-reference to the `Matter.Render` module. - * - * @deprecated - * @property controller - * @type render - */ - - /** - * A reference to the `Matter.Engine` instance to be used. - * - * @property engine - * @type engine - */ - - /** - * A reference to the element where the canvas is to be inserted (if `render.canvas` has not been specified) - * - * @property element - * @type HTMLElement - * @default null - */ - - /** - * The canvas element to render to. If not specified, one will be created if `render.element` has been specified. - * - * @property canvas - * @type HTMLCanvasElement - * @default null - */ - - /** - * A `Bounds` object that specifies the drawing view region. - * Rendering will be automatically transformed and scaled to fit within the canvas size (`render.options.width` and `render.options.height`). - * This allows for creating views that can pan or zoom around the scene. - * You must also set `render.options.hasBounds` to `true` to enable bounded rendering. - * - * @property bounds - * @type bounds - */ - - /** - * The 2d rendering context from the `render.canvas` element. - * - * @property context - * @type CanvasRenderingContext2D - */ - - /** - * The sprite texture cache. - * - * @property textures - * @type {} - */ - - /** - * The mouse to render if `render.options.showMousePosition` is enabled. - * - * @property mouse - * @type mouse - * @default null - */ - - /** - * The configuration options of the renderer. - * - * @property options - * @type {} - */ - - /** - * The target width in pixels of the `render.canvas` to be created. - * See also the `options.pixelRatio` property to change render quality. - * - * @property options.width - * @type number - * @default 800 - */ - - /** - * The target height in pixels of the `render.canvas` to be created. - * See also the `options.pixelRatio` property to change render quality. - * - * @property options.height - * @type number - * @default 600 - */ - - /** - * The [pixel ratio](https://developer.mozilla.org/en-US/docs/Web/API/Window/devicePixelRatio) to use when rendering. - * - * @property options.pixelRatio - * @type number - * @default 1 - */ - - /** - * A CSS background color string to use when `render.options.wireframes` is disabled. - * This may be also set to `'transparent'` or equivalent. - * - * @property options.background - * @type string - * @default '#14151f' - */ - - /** - * A CSS color string to use for background when `render.options.wireframes` is enabled. - * This may be also set to `'transparent'` or equivalent. - * - * @property options.wireframeBackground - * @type string - * @default '#14151f' - */ - - /** - * A CSS color string to use for stroke when `render.options.wireframes` is enabled. - * This may be also set to `'transparent'` or equivalent. - * - * @property options.wireframeStrokeStyle - * @type string - * @default '#bbb' - */ - - /** - * A flag that specifies if `render.bounds` should be used when rendering. - * - * @property options.hasBounds - * @type boolean - * @default false - */ - - /** - * A flag to enable or disable all debug information overlays together. - * This includes and has priority over the values of: - * - * - `render.options.showStats` - * - `render.options.showPerformance` - * - * @property options.showDebug - * @type boolean - * @default false - */ - - /** - * A flag to enable or disable the engine stats info overlay. - * From left to right, the values shown are: - * - * - body parts total - * - body total - * - constraints total - * - composites total - * - collision pairs total - * - * @property options.showStats - * @type boolean - * @default false - */ - - /** - * A flag to enable or disable performance charts. - * From left to right, the values shown are: - * - * - average render frequency (e.g. 60 fps) - * - exact engine delta time used for last update (e.g. 16.66ms) - * - average updates per frame (e.g. 1) - * - average engine execution duration (e.g. 5.00ms) - * - average render execution duration (e.g. 0.40ms) - * - average effective play speed (e.g. '1.00x' is 'real-time') - * - * Each value is recorded over a fixed sample of past frames (60 frames). - * - * A chart shown below each value indicates the variance from the average over the sample. - * The more stable or fixed the value is the flatter the chart will appear. - * - * @property options.showPerformance - * @type boolean - * @default false - */ - - /** - * A flag to enable or disable rendering entirely. - * - * @property options.enabled - * @type boolean - * @default false - */ - - /** - * A flag to toggle wireframe rendering otherwise solid fill rendering is used. - * - * @property options.wireframes - * @type boolean - * @default true - */ - - /** - * A flag to enable or disable sleeping bodies indicators. - * - * @property options.showSleeping - * @type boolean - * @default true - */ - - /** - * A flag to enable or disable the debug information overlay. - * - * @property options.showDebug - * @type boolean - * @default false - */ - - /** - * A flag to enable or disable the collision broadphase debug overlay. - * - * @deprecated no longer implemented - * @property options.showBroadphase - * @type boolean - * @default false - */ - - /** - * A flag to enable or disable the body bounds debug overlay. - * - * @property options.showBounds - * @type boolean - * @default false - */ - - /** - * A flag to enable or disable the body velocity debug overlay. - * - * @property options.showVelocity - * @type boolean - * @default false - */ - - /** - * A flag to enable or disable the body collisions debug overlay. - * - * @property options.showCollisions - * @type boolean - * @default false - */ - - /** - * A flag to enable or disable the collision resolver separations debug overlay. - * - * @property options.showSeparations - * @type boolean - * @default false - */ - - /** - * A flag to enable or disable the body axes debug overlay. - * - * @property options.showAxes - * @type boolean - * @default false - */ - - /** - * A flag to enable or disable the body positions debug overlay. - * - * @property options.showPositions - * @type boolean - * @default false - */ - - /** - * A flag to enable or disable the body angle debug overlay. - * - * @property options.showAngleIndicator - * @type boolean - * @default false - */ - - /** - * A flag to enable or disable the body and part ids debug overlay. - * - * @property options.showIds - * @type boolean - * @default false - */ - - /** - * A flag to enable or disable the body vertex numbers debug overlay. - * - * @property options.showVertexNumbers - * @type boolean - * @default false - */ - - /** - * A flag to enable or disable the body convex hulls debug overlay. - * - * @property options.showConvexHulls - * @type boolean - * @default false - */ - - /** - * A flag to enable or disable the body internal edges debug overlay. - * - * @property options.showInternalEdges - * @type boolean - * @default false - */ - - /** - * A flag to enable or disable the mouse position debug overlay. - * - * @property options.showMousePosition - * @type boolean - * @default false - */ - -})(); - - -/***/ }), -/* 27 */ -/***/ (function(module, exports, __webpack_require__) { - -/** -* Pre-release beta version. -* -* The `Matter.Runner` module is a lightweight, optional utility which provides a game loop. -* It is intended for development and debugging purposes inside a browser environment. -* It will continuously update a `Matter.Engine` with a given fixed timestep whilst synchronising updates with the browser frame rate. -* This runner favours a smoother user experience over perfect time keeping. -* To directly step the engine as part of your own alternative game loop implementation, see `Engine.update`. -* -* See the included usage [examples](https://github.com/liabru/matter-js/tree/master/examples). -* -* @class Runner -*/ - -var Runner = {}; - -module.exports = Runner; - -var Events = __webpack_require__(5); -var Engine = __webpack_require__(17); -var Common = __webpack_require__(0); - -(function() { - - Runner._timeBufferMargin = 1.5; - Runner._smoothingLowerBound = 0.1; - Runner._smoothingUpperBound = 0.9; - - /** - * Creates a new Runner. - * See the properties section below for detailed information on what you can pass via the `options` object. - * @method create - * @param {} options - */ - Runner.create = function(options) { - var defaults = { - delta: 1000 / 60, - frameDelta: 0, - frameDeltaSmoothing: true, - frameDeltaSnapping: true, - frameDeltaHistory: [], - frameDeltaHistorySize: 100, - frameRequestId: null, - timeBuffer: 0, - timeLastTick: null, - maxUpdates: null, - maxFrameTime: 1000 / 50, - maxFrameDelta: 1000 / 10, - lastUpdatesDeferred: 0, - enabled: true - }; - - var runner = Common.extend(defaults, options); - - if (runner.maxUpdates === null) { - runner.maxUpdates = Math.ceil(runner.maxFrameTime / runner.delta); - } - - // for temporary back compatibility only - runner.fps = 0; - - return runner; - }; - - /** - * Continuously updates a `Matter.Engine` on every browser frame whilst synchronising updates with the browser frame rate. - * It is intended for development and debugging purposes inside a browser environment. - * This runner favours a smoother user experience over perfect time keeping. - * The number of updates per frame is kept within limits specified by `runner.maxFrameTime`, `runner.maxUpdates` and `runner.maxFrameDelta`. - * When device performance is too limited the simulation may appear to slow down compared to real time. - * As an alternative, to directly step the engine in your own game loop implementation, see `Engine.update`. - * @method run - * @param {runner} runner - * @param {engine} [engine] - * @return {runner} runner - */ - Runner.run = function(runner, engine) { - // initial time buffer for the first frame - runner.timeBuffer = runner.delta * Runner._timeBufferMargin; - - (function onFrame(time){ - runner.frameRequestId = Runner._onNextFrame(runner, onFrame); - - if (time && runner.enabled) { - Runner.tick(runner, engine, time); - } - })(); - - return runner; - }; - - /** - * Used by the game loop inside `Runner.run`. - * - * As an alternative to directly step the engine in your own game loop implementation, see `Engine.update`. - * @method tick - * @param {runner} runner - * @param {engine} engine - * @param {number} time - */ - Runner.tick = function(runner, engine, time) { - var tickStartTime = Common.now(), - engineDelta = runner.delta, - updateCount = 0; - - // find frame delta time since last call - var frameDelta = time - runner.timeLastTick; - - // fallback for unexpected frame delta values (e.g. 0, NaN or from long pauses) - if (!frameDelta || frameDelta > runner.maxFrameDelta) { - // reuse last accepted frame delta or fallback to one update - frameDelta = runner.frameDelta || engineDelta; - } - - if (runner.frameDeltaSmoothing) { - // record frame delta over a number of frames - runner.frameDeltaHistory.push(frameDelta); - runner.frameDeltaHistory = runner.frameDeltaHistory.slice(-runner.frameDeltaHistorySize); - - // sort frame delta history - var deltaHistorySorted = runner.frameDeltaHistory.slice(0).sort(); - - // sample a central window to limit outliers - var deltaHistoryWindow = runner.frameDeltaHistory.slice( - deltaHistorySorted.length * Runner._smoothingLowerBound, - deltaHistorySorted.length * Runner._smoothingUpperBound - ); - - // take the mean of the central window - var frameDeltaSmoothed = _mean(deltaHistoryWindow); - frameDelta = frameDeltaSmoothed || frameDelta; - } - - if (runner.frameDeltaSnapping) { - // snap frame delta to the nearest 1 Hz - frameDelta = 1000 / Math.round(1000 / frameDelta); - } - - // update runner values for next call - runner.frameDelta = frameDelta; - runner.timeLastTick = time; - - // accumulate elapsed time - runner.timeBuffer += runner.frameDelta; - - // limit time buffer size to a single frame of updates - runner.timeBuffer = Common.clamp( - runner.timeBuffer, 0, runner.frameDelta + engineDelta * Runner._timeBufferMargin - ); - - // reset count of over budget updates - runner.lastUpdatesDeferred = 0; - - // get max updates per second - var maxUpdates = runner.maxUpdates; - - // create event object - var event = { - timestamp: engine.timing.timestamp - }; - - // tick events before update - Events.trigger(runner, 'beforeTick', event); - Events.trigger(runner, 'tick', event); - - // simulate time elapsed between calls - while (engineDelta > 0 && runner.timeBuffer >= engineDelta * Runner._timeBufferMargin) { - var updateStartTime = Common.now(); - - // update the engine - Events.trigger(runner, 'beforeUpdate', event); - Engine.update(engine, engineDelta); - Events.trigger(runner, 'afterUpdate', event); - - // consume time simulated from buffer - runner.timeBuffer -= engineDelta; - updateCount += 1; - - // find elapsed time during this tick - var elapsedTimeTotal = Common.now() - tickStartTime, - elapsedTimeUpdate = Common.now() - updateStartTime; - - // defer updates if over performance budgets for this frame - if (updateCount >= maxUpdates || elapsedTimeTotal + elapsedTimeUpdate > runner.maxFrameTime) { - runner.lastUpdatesDeferred = Math.round(Math.max(0, (runner.timeBuffer / engineDelta) - Runner._timeBufferMargin)); - break; - } - } - - // track timing metrics - engine.timing.lastUpdatesPerFrame = updateCount; - - // tick events after update - Events.trigger(runner, 'afterTick', event); - - // show useful warnings if needed - if (runner.frameDeltaHistory.length >= 100) { - if (runner.lastUpdatesDeferred && Math.round(runner.frameDelta / engineDelta) > maxUpdates) { - Common.warnOnce('Matter.Runner: runner reached runner.maxUpdates, see docs.'); - } else if (runner.lastUpdatesDeferred) { - Common.warnOnce('Matter.Runner: runner reached runner.maxFrameTime, see docs.'); - } - - if (typeof runner.isFixed !== 'undefined') { - Common.warnOnce('Matter.Runner: runner.isFixed is now redundant, see docs.'); - } - - if (runner.deltaMin || runner.deltaMax) { - Common.warnOnce('Matter.Runner: runner.deltaMin and runner.deltaMax were removed, see docs.'); - } - - if (runner.fps !== 0) { - Common.warnOnce('Matter.Runner: runner.fps was replaced by runner.delta, see docs.'); - } - } - }; - - /** - * Ends execution of `Runner.run` on the given `runner`, by canceling the frame loop. - * - * To temporarily pause the runner, see `runner.enabled`. - * @method stop - * @param {runner} runner - */ - Runner.stop = function(runner) { - Runner._cancelNextFrame(runner); - }; - - /** - * Schedules a `callback` on this `runner` for the next animation frame. - * @private - * @method _onNextFrame - * @param {runner} runner - * @param {function} callback - * @return {number} frameRequestId - */ - Runner._onNextFrame = function(runner, callback) { - if (typeof window !== 'undefined') { - runner.frameRequestId = window.requestAnimationFrame(callback); - } else { - Common.warnOnce('Matter.Runner: missing required global window.requestAnimationFrame.'); - } - - return runner.frameRequestId; - }; - - /** - * Cancels the last callback scheduled on this `runner` by `Runner._onNextFrame`. - * @private - * @method _cancelNextFrame - * @param {runner} runner - */ - Runner._cancelNextFrame = function(runner) { - if (typeof window !== 'undefined') { - window.cancelAnimationFrame(runner.frameRequestId); - } else { - Common.warnOnce('Matter.Runner: missing required global window.cancelAnimationFrame.'); - } - }; - - /** - * Returns the mean of the given numbers. - * @method _mean - * @private - * @param {Number[]} values - * @return {Number} the mean of given values. - */ - var _mean = function(values) { - var result = 0, - valuesLength = values.length; - - for (var i = 0; i < valuesLength; i += 1) { - result += values[i]; - } - - return (result / valuesLength) || 0; - }; - - /* - * - * Events Documentation - * - */ - - /** - * Fired once at the start of the browser frame, before any engine updates. - * - * @event beforeTick - * @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 once at the start of the browser frame, after `beforeTick`. - * - * @event tick - * @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 once at the end of the browser frame, after `beforeTick`, `tick` and after any engine updates. - * - * @event afterTick - * @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 before each and every update in this browser frame (if any). - * There may be multiple calls per browser frame (or none), depending on framerate and engine delta. - * - * @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 each and every update in this browser frame (if any). - * There may be multiple calls per browser frame (or none), depending on framerate and engine delta. - * - * @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 - */ - - /* - * - * Properties Documentation - * - */ - - /** - * The fixed timestep size used for `Engine.update` calls in milliseconds. - * - * This `delta` value is recommended to be `16.666` ms or lower (equivalent to at least 60hz). - * - * Lower `delta` values provide a higher quality results at the cost of performance. - * - * This value should be held fixed during running, otherwise quality may be affected. - * - * For smoothest results choose an evenly divisible factor of your target framerates, this helps provide an equal number of updates per frame. - * - * Rounding to the nearest 1 Hz is recommended for smoother results (see `runner.frameDeltaSnapping`). - * - * For example with a `delta` of `1000 / 60` the runner will on average perform one update per frame for displays at 60 FPS, or one update every two frames for displays at 120 FPS. - * - * `Runner.run` will call multiple engine updates to simulate the time elapsed between frames, but the number of allowed calls may be limited by the runner's performance budgets. - * - * These performance budgets are specified by `runner.maxFrameTime`, `runner.maxUpdates`, `runner.maxFrameDelta`. See those properties for details. - * - * @property delta - * @type number - * @default 1000 / 60 - */ - - /** - * A flag that can be toggled to enable or disable tick calls on this runner, therefore pausing engine updates while the loop remains running. - * - * @property enabled - * @type boolean - * @default true - */ - - /** - * The accumulated time elapsed that has yet to be simulated, in milliseconds. - * This value is clamped within some limits (see `Runner.tick` code). - * - * @private - * @property timeBuffer - * @type number - * @default 0 - */ - - /** - * The measured time elapsed between the last two browser frames in milliseconds. - * This value is clamped inside `runner.maxFrameDelta`. - * - * You may use this to estimate the browser FPS (for the current instant) whilst running use `1000 / runner.frameDelta`. - * - * @readonly - * @property frameDelta - * @type number - */ - - /** - * This option applies averaging to the frame delta to smooth noisy frame rates. - * - * @property frameDeltaSmoothing - * @type boolean - * @default true - */ - - /** - * Rounds frame delta to the nearest 1 Hz. - * It follows that your choice of `runner.delta` should be rounded to the nearest 1 Hz for best results. - * This option helps smooth noisy refresh rates and simplify hardware differences e.g. 59.94Hz vs 60Hz display refresh rates. - * - * @property frameDeltaSnapping - * @type boolean - * @default true - */ - - /** - * Clamps the maximum `runner.frameDelta` in milliseconds. - * This is to avoid simulating periods where the browser thread is paused e.g. whilst minimised. - * - * @property maxFrameDelta - * @type number - * @default 500 - */ - - /** - * The runner will attempt to limit engine update rate should the browser frame rate drop below a set level (50 FPS using the default `runner.maxFrameTime` value `1000 / 50` milliseconds). - * - * This budget is intended to help maintain browser interactivity and help improve framerate recovery during temporary high CPU spikes. - * - * It will only cover time elapsed whilst executing the functions called in the scope of this runner, including `Engine.update` etc. and its related event callbacks. - * - * For any significant additional processing you perform on the same thread but outside the scope of this runner e.g. rendering time, you may wish to reduce this budget. - * - * See also `runner.maxUpdates`. - * - * @property maxFrameTime - * @type number - * @default 1000 / 50 - */ - - /** - * A hard limit for maximum engine updates allowed per frame. - * - * If not provided, it is automatically set by `Runner.create` based on `runner.delta` and `runner.maxFrameTime`. - * If you change `runner.delta` or `runner.maxFrameTime`, you may need to manually update this value afterwards. - * - * See also `runner.maxFrameTime`. - * - * @property maxUpdates - * @type number - * @default null - */ - - /** - * The timestamp of the last call to `Runner.tick`, used to measure `frameDelta`. - * - * @private - * @property timeLastTick - * @type number - * @default 0 - */ - - /** - * The id of the last call to `Runner._onNextFrame`. - * - * @private - * @property frameRequestId - * @type number - * @default null - */ - -})(); - - -/***/ }), -/* 28 */ -/***/ (function(module, exports, __webpack_require__) { - -/** -* This module has now been replaced by `Matter.Collision`. -* -* All usage should be migrated to `Matter.Collision`. -* For back-compatibility purposes this module will remain for a short term and then later removed in a future release. -* -* The `Matter.SAT` module contains methods for detecting collisions using the Separating Axis Theorem. -* -* @class SAT -* @deprecated -*/ - -var SAT = {}; - -module.exports = SAT; - -var Collision = __webpack_require__(8); -var Common = __webpack_require__(0); -var deprecated = Common.deprecated; - -(function() { - - /** - * Detect collision between two bodies using the Separating Axis Theorem. - * @deprecated replaced by Collision.collides - * @method collides - * @param {body} bodyA - * @param {body} bodyB - * @return {collision} collision - */ - SAT.collides = function(bodyA, bodyB) { - return Collision.collides(bodyA, bodyB); - }; - - deprecated(SAT, 'collides', 'SAT.collides ➤ replaced by Collision.collides'); - -})(); - - -/***/ }), -/* 29 */ -/***/ (function(module, exports, __webpack_require__) { - -/** -* The `Matter.Svg` module contains methods for converting SVG images into an array of vector points. -* -* To use this module you also need the SVGPathSeg polyfill: https://github.com/progers/pathseg -* -* See the included usage [examples](https://github.com/liabru/matter-js/tree/master/examples). -* -* @class Svg -*/ - -var Svg = {}; - -module.exports = Svg; - -var Bounds = __webpack_require__(1); -var Common = __webpack_require__(0); - -(function() { - - /** - * Converts an SVG path into an array of vector points. - * If the input path forms a concave shape, you must decompose the result into convex parts before use. - * See `Bodies.fromVertices` which provides support for this. - * Note that this function is not guaranteed to support complex paths (such as those with holes). - * You must load the `pathseg.js` polyfill on newer browsers. - * @method pathToVertices - * @param {SVGPathElement} path - * @param {Number} [sampleLength=15] - * @return {Vector[]} points - */ - Svg.pathToVertices = function(path, sampleLength) { - if (typeof window !== 'undefined' && !('SVGPathSeg' in window)) { - Common.warn('Svg.pathToVertices: SVGPathSeg not defined, a polyfill is required.'); - } - - // https://github.com/wout/svg.topoly.js/blob/master/svg.topoly.js - var i, il, total, point, segment, segments, - segmentsQueue, lastSegment, - lastPoint, segmentIndex, points = [], - lx, ly, length = 0, x = 0, y = 0; - - sampleLength = sampleLength || 15; - - var addPoint = function(px, py, pathSegType) { - // all odd-numbered path types are relative except PATHSEG_CLOSEPATH (1) - var isRelative = pathSegType % 2 === 1 && pathSegType > 1; - - // when the last point doesn't equal the current point add the current point - if (!lastPoint || px != lastPoint.x || py != lastPoint.y) { - if (lastPoint && isRelative) { - lx = lastPoint.x; - ly = lastPoint.y; - } else { - lx = 0; - ly = 0; - } - - var point = { - x: lx + px, - y: ly + py - }; - - // set last point - if (isRelative || !lastPoint) { - lastPoint = point; - } - - points.push(point); - - x = lx + px; - y = ly + py; - } - }; - - var addSegmentPoint = function(segment) { - var segType = segment.pathSegTypeAsLetter.toUpperCase(); - - // skip path ends - if (segType === 'Z') - return; - - // map segment to x and y - switch (segType) { - - case 'M': - case 'L': - case 'T': - case 'C': - case 'S': - case 'Q': - x = segment.x; - y = segment.y; - break; - case 'H': - x = segment.x; - break; - case 'V': - y = segment.y; - break; - } - - addPoint(x, y, segment.pathSegType); - }; - - // ensure path is absolute - Svg._svgPathToAbsolute(path); - - // get total length - total = path.getTotalLength(); - - // queue segments - segments = []; - for (i = 0; i < path.pathSegList.numberOfItems; i += 1) - segments.push(path.pathSegList.getItem(i)); - - segmentsQueue = segments.concat(); - - // sample through path - while (length < total) { - // get segment at position - segmentIndex = path.getPathSegAtLength(length); - segment = segments[segmentIndex]; - - // new segment - if (segment != lastSegment) { - while (segmentsQueue.length && segmentsQueue[0] != segment) - addSegmentPoint(segmentsQueue.shift()); - - lastSegment = segment; - } - - // add points in between when curving - // TODO: adaptive sampling - switch (segment.pathSegTypeAsLetter.toUpperCase()) { - - case 'C': - case 'T': - case 'S': - case 'Q': - case 'A': - point = path.getPointAtLength(length); - addPoint(point.x, point.y, 0); - break; - - } - - // increment by sample value - length += sampleLength; - } - - // add remaining segments not passed by sampling - for (i = 0, il = segmentsQueue.length; i < il; ++i) - addSegmentPoint(segmentsQueue[i]); - - return points; - }; - - Svg._svgPathToAbsolute = function(path) { - // http://phrogz.net/convert-svg-path-to-all-absolute-commands - // Copyright (c) Gavin Kistner - // http://phrogz.net/js/_ReuseLicense.txt - // Modifications: tidy formatting and naming - var x0, y0, x1, y1, x2, y2, segs = path.pathSegList, - x = 0, y = 0, len = segs.numberOfItems; - - for (var i = 0; i < len; ++i) { - var seg = segs.getItem(i), - segType = seg.pathSegTypeAsLetter; - - if (/[MLHVCSQTA]/.test(segType)) { - if ('x' in seg) x = seg.x; - if ('y' in seg) y = seg.y; - } else { - if ('x1' in seg) x1 = x + seg.x1; - if ('x2' in seg) x2 = x + seg.x2; - if ('y1' in seg) y1 = y + seg.y1; - if ('y2' in seg) y2 = y + seg.y2; - if ('x' in seg) x += seg.x; - if ('y' in seg) y += seg.y; - - switch (segType) { - - case 'm': - segs.replaceItem(path.createSVGPathSegMovetoAbs(x, y), i); - break; - case 'l': - segs.replaceItem(path.createSVGPathSegLinetoAbs(x, y), i); - break; - case 'h': - segs.replaceItem(path.createSVGPathSegLinetoHorizontalAbs(x), i); - break; - case 'v': - segs.replaceItem(path.createSVGPathSegLinetoVerticalAbs(y), i); - break; - case 'c': - segs.replaceItem(path.createSVGPathSegCurvetoCubicAbs(x, y, x1, y1, x2, y2), i); - break; - case 's': - segs.replaceItem(path.createSVGPathSegCurvetoCubicSmoothAbs(x, y, x2, y2), i); - break; - case 'q': - segs.replaceItem(path.createSVGPathSegCurvetoQuadraticAbs(x, y, x1, y1), i); - break; - case 't': - segs.replaceItem(path.createSVGPathSegCurvetoQuadraticSmoothAbs(x, y), i); - break; - case 'a': - segs.replaceItem(path.createSVGPathSegArcAbs(x, y, seg.r1, seg.r2, seg.angle, seg.largeArcFlag, seg.sweepFlag), i); - break; - case 'z': - case 'Z': - x = x0; - y = y0; - break; - - } - } - - if (segType == 'M' || segType == 'm') { - x0 = x; - y0 = y; - } - } - }; - -})(); - -/***/ }), -/* 30 */ -/***/ (function(module, exports, __webpack_require__) { - -/** -* This module has now been replaced by `Matter.Composite`. -* -* All usage should be migrated to the equivalent functions found on `Matter.Composite`. -* For example `World.add(world, body)` now becomes `Composite.add(world, body)`. -* -* The property `world.gravity` has been moved to `engine.gravity`. -* -* For back-compatibility purposes this module will remain as a direct alias to `Matter.Composite` in the short term during migration. -* Eventually this alias module will be marked as deprecated and then later removed in a future release. -* -* @class World -*/ - -var World = {}; - -module.exports = World; - -var Composite = __webpack_require__(6); -var Common = __webpack_require__(0); - -(function() { - - /** - * See above, aliases for back compatibility only - */ - World.create = Composite.create; - World.add = Composite.add; - World.remove = Composite.remove; - World.clear = Composite.clear; - World.addComposite = Composite.addComposite; - World.addBody = Composite.addBody; - World.addConstraint = Composite.addConstraint; - -})(); - - -/***/ }) -/******/ ]); -}); \ No newline at end of file diff --git a/build/matter.alpha.min.js b/build/matter.alpha.min.js deleted file mode 100644 index edcd202..0000000 --- a/build/matter.alpha.min.js +++ /dev/null @@ -1,7 +0,0 @@ -/*! - * matter-js 0.19.0-alpha+205aaa5 by @liabru - * Experimental pre-release build. - * http://brm.io/matter-js/ - * License MIT - */ -!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define("Matter",[],t):"object"==typeof exports?exports.Matter=t():e.Matter=t()}(this,(function(){return function(e){var t={};function n(i){if(t[i])return t[i].exports;var o=t[i]={i:i,l:!1,exports:{}};return e[i].call(o.exports,o,o.exports,n),o.l=!0,o.exports}return n.m=e,n.c=t,n.d=function(e,t,i){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:i})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var i=Object.create(null);if(n.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(i,o,function(t){return e[t]}.bind(null,o));return i},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=20)}([function(e,t){var n={};e.exports=n,function(){n._baseDelta=1e3/60,n._nextId=0,n._seed=0,n._nowStartTime=+new Date,n._warnedOnce={},n._decomp=null,n.extend=function(e,t){var i,o;"boolean"==typeof t?(i=2,o=t):(i=1,o=!0);for(var r=i;r0;t--){var i=Math.floor(n.random()*(t+1)),o=e[t];e[t]=e[i],e[i]=o}return e},n.choose=function(e){return e[Math.floor(n.random()*e.length)]},n.isElement=function(e){return"undefined"!=typeof HTMLElement?e instanceof HTMLElement:!!(e&&e.nodeType&&e.nodeName)},n.isArray=function(e){return"[object Array]"===Object.prototype.toString.call(e)},n.isFunction=function(e){return"function"==typeof e},n.isPlainObject=function(e){return"object"==typeof e&&e.constructor===Object},n.isString=function(e){return"[object String]"===toString.call(e)},n.clamp=function(e,t,n){return en?n:e},n.sign=function(e){return e<0?-1:1},n.now=function(){if("undefined"!=typeof window&&window.performance){if(window.performance.now)return window.performance.now();if(window.performance.webkitNow)return window.performance.webkitNow()}return Date.now?Date.now():new Date-n._nowStartTime},n.random=function(t,n){return n=void 0!==n?n:1,(t=void 0!==t?t:0)+e()*(n-t)};var e=function(){return n._seed=(9301*n._seed+49297)%233280,n._seed/233280};n.colorToNumber=function(e){return 3==(e=e.replace("#","")).length&&(e=e.charAt(0)+e.charAt(0)+e.charAt(1)+e.charAt(1)+e.charAt(2)+e.charAt(2)),parseInt(e,16)},n.logLevel=1,n.log=function(){console&&n.logLevel>0&&n.logLevel<=3&&console.log.apply(console,["matter-js:"].concat(Array.prototype.slice.call(arguments)))},n.info=function(){console&&n.logLevel>0&&n.logLevel<=2&&console.info.apply(console,["matter-js:"].concat(Array.prototype.slice.call(arguments)))},n.warn=function(){console&&n.logLevel>0&&n.logLevel<=3&&console.warn.apply(console,["matter-js:"].concat(Array.prototype.slice.call(arguments)))},n.warnOnce=function(){var e=Array.prototype.slice.call(arguments).join(" ");n._warnedOnce[e]||(n.warn(e),n._warnedOnce[e]=!0)},n.deprecated=function(e,t,i){e[t]=n.chain((function(){n.warnOnce("🔅 deprecated 🔅",i)}),e[t])},n.nextId=function(){return n._nextId++},n.indexOf=function(e,t){if(e.indexOf)return e.indexOf(t);for(var n=0;ne.max.x&&(e.max.x=o.x),o.xe.max.y&&(e.max.y=o.y),o.y0?e.max.x+=n.x:e.min.x+=n.x,n.y>0?e.max.y+=n.y:e.min.y+=n.y)},n.contains=function(e,t){return t.x>=e.min.x&&t.x<=e.max.x&&t.y>=e.min.y&&t.y<=e.max.y},n.overlaps=function(e,t){return e.min.x<=t.max.x&&e.max.x>=t.min.x&&e.max.y>=t.min.y&&e.min.y<=t.max.y},n.translate=function(e,t){e.min.x+=t.x,e.max.x+=t.x,e.min.y+=t.y,e.max.y+=t.y},n.shift=function(e,t){var n=e.max.x-e.min.x,i=e.max.y-e.min.y;e.min.x=t.x,e.max.x=t.x+n,e.min.y=t.y,e.max.y=t.y+i}},function(e,t){var n={};e.exports=n,n.create=function(e,t){return{x:e||0,y:t||0}},n.clone=function(e){return{x:e.x,y:e.y}},n.magnitude=function(e){return Math.sqrt(e.x*e.x+e.y*e.y)},n.magnitudeSquared=function(e){return e.x*e.x+e.y*e.y},n.rotate=function(e,t,n){var i=Math.cos(t),o=Math.sin(t);n||(n={});var r=e.x*i-e.y*o;return n.y=e.x*o+e.y*i,n.x=r,n},n.rotateAbout=function(e,t,n,i){var o=Math.cos(t),r=Math.sin(t);i||(i={});var a=n.x+((e.x-n.x)*o-(e.y-n.y)*r);return i.y=n.y+((e.x-n.x)*r+(e.y-n.y)*o),i.x=a,i},n.normalise=function(e){var t=n.magnitude(e);return 0===t?{x:0,y:0}:{x:e.x/t,y:e.y/t}},n.dot=function(e,t){return e.x*t.x+e.y*t.y},n.cross=function(e,t){return e.x*t.y-e.y*t.x},n.cross3=function(e,t,n){return(t.x-e.x)*(n.y-e.y)-(t.y-e.y)*(n.x-e.x)},n.add=function(e,t,n){return n||(n={}),n.x=e.x+t.x,n.y=e.y+t.y,n},n.sub=function(e,t,n){return n||(n={}),n.x=e.x-t.x,n.y=e.y-t.y,n},n.mult=function(e,t){return{x:e.x*t,y:e.y*t}},n.div=function(e,t){return{x:e.x/t,y:e.y/t}},n.perp=function(e,t){return{x:(t=!0===t?-1:1)*-e.y,y:t*e.x}},n.neg=function(e){return{x:-e.x,y:-e.y}},n.angle=function(e,t){return Math.atan2(t.y-e.y,t.x-e.x)},n._temp=[n.create(),n.create(),n.create(),n.create(),n.create(),n.create()]},function(e,t,n){var i={};e.exports=i;var o=n(2),r=n(0);i.create=function(e,t){for(var n=[],i=0;i0)return!1;a=n}return!0},i.scale=function(e,t,n,r){if(1===t&&1===n)return e;var a,s;r=r||i.centre(e);for(var l=0;l=0?l-1:e.length-1],u=e[l],d=e[(l+1)%e.length],p=t[l0&&(r|=2),3===r)return!1;return 0!==r||null},i.hull=function(e){var t,n,i=[],r=[];for((e=e.slice(0)).sort((function(e,t){var n=e.x-t.x;return 0!==n?n:e.y-t.y})),n=0;n=2&&o.cross3(r[r.length-2],r[r.length-1],t)<=0;)r.pop();r.push(t)}for(n=e.length-1;n>=0;n-=1){for(t=e[n];i.length>=2&&o.cross3(i[i.length-2],i[i.length-1],t)<=0;)i.pop();i.push(t)}return i.pop(),r.pop(),i.concat(r)}},function(e,t,n){var i={};e.exports=i;var o=n(3),r=n(2),a=n(7),s=n(0),l=n(1),c=n(11);!function(){i._timeCorrection=!0,i._inertiaScale=4,i._nextCollidingGroupId=1,i._nextNonCollidingGroupId=-1,i._nextCategory=1,i._baseDelta=1e3/60,i.create=function(t){var n={id:s.nextId(),type:"body",label:"Body",parts:[],plugin:{},angle:0,vertices:o.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:!1,isStatic:!1,isSleeping:!1,motion:0,sleepThreshold:60,density:.001,restitution:0,friction:.1,frictionStatic:.5,frictionAir:.01,collisionFilter:{category:1,mask:4294967295,group:0},slop:.05,timeScale:1,render:{visible:!0,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:1e3/60,_original:null},i=s.extend(n,t);return e(i,t),i},i.nextGroup=function(e){return e?i._nextNonCollidingGroupId--:i._nextCollidingGroupId++},i.nextCategory=function(){return i._nextCategory=i._nextCategory<<1,i._nextCategory};var e=function(e,t){t=t||{},i.set(e,{bounds:e.bounds||l.create(e.vertices),positionPrev:e.positionPrev||r.clone(e.position),anglePrev:e.anglePrev||e.angle,vertices:e.vertices,parts:e.parts||[e],isStatic:e.isStatic,isSleeping:e.isSleeping,parent:e.parent||e}),o.rotate(e.vertices,e.angle,e.position),c.rotate(e.axes,e.angle),l.update(e.bounds,e.vertices,e.velocity),i.set(e,{axes:t.axes||e.axes,area:t.area||e.area,mass:t.mass||e.mass,inertia:t.inertia||e.inertia});var n=e.isStatic?"#14151f":s.choose(["#f19648","#f5d259","#f55a3c","#063e7b","#ececd1"]),a=e.isStatic?"#555":"#ccc",u=e.isStatic&&null===e.render.fillStyle?1:0;e.render.fillStyle=e.render.fillStyle||n,e.render.strokeStyle=e.render.strokeStyle||a,e.render.lineWidth=e.render.lineWidth||u,e.render.sprite.xOffset+=-(e.bounds.min.x-e.position.x)/(e.bounds.max.x-e.bounds.min.x),e.render.sprite.yOffset+=-(e.bounds.min.y-e.position.y)/(e.bounds.max.y-e.bounds.min.y)};i.set=function(e,t,n){var o;for(o in"string"==typeof t&&(o=t,(t={})[o]=n),t)if(Object.prototype.hasOwnProperty.call(t,o))switch(n=t[o],o){case"isStatic":i.setStatic(e,n);break;case"isSleeping":a.set(e,n);break;case"mass":i.setMass(e,n);break;case"density":i.setDensity(e,n);break;case"inertia":i.setInertia(e,n);break;case"vertices":i.setVertices(e,n);break;case"position":i.setPosition(e,n);break;case"angle":i.setAngle(e,n);break;case"velocity":i.setVelocity(e,n);break;case"angularVelocity":i.setAngularVelocity(e,n);break;case"speed":i.setSpeed(e,n);break;case"angularSpeed":i.setAngularSpeed(e,n);break;case"parts":i.setParts(e,n);break;case"centre":i.setCentre(e,n);break;default:e[o]=n}},i.setStatic=function(e,t){for(var n=0;n0&&r.rotateAbout(s.position,i,e.position,s.position)}},i.setVelocity=function(e,t){var n=e.deltaTime/i._baseDelta;e.positionPrev.x=e.position.x-t.x*n,e.positionPrev.y=e.position.y-t.y*n,e.velocity.x=(e.position.x-e.positionPrev.x)/n,e.velocity.y=(e.position.y-e.positionPrev.y)/n,e.speed=r.magnitude(e.velocity)},i.getVelocity=function(e){var t=i._baseDelta/e.deltaTime;return{x:(e.position.x-e.positionPrev.x)*t,y:(e.position.y-e.positionPrev.y)*t}},i.getSpeed=function(e){return r.magnitude(i.getVelocity(e))},i.setSpeed=function(e,t){i.setVelocity(e,r.mult(r.normalise(i.getVelocity(e)),t))},i.setAngularVelocity=function(e,t){var n=e.deltaTime/i._baseDelta;e.anglePrev=e.angle-t*n,e.angularVelocity=(e.angle-e.anglePrev)/n,e.angularSpeed=Math.abs(e.angularVelocity)},i.getAngularVelocity=function(e){return(e.angle-e.anglePrev)*i._baseDelta/e.deltaTime},i.getAngularSpeed=function(e){return Math.abs(i.getAngularVelocity(e))},i.setAngularSpeed=function(e,t){i.setAngularVelocity(e,s.sign(i.getAngularVelocity(e))*t)},i.translate=function(e,t,n){i.setPosition(e,r.add(e.position,t),n)},i.rotate=function(e,t,n,o){if(n){var r=Math.cos(t),a=Math.sin(t),s=e.position.x-n.x,l=e.position.y-n.y;i.setPosition(e,{x:n.x+(s*r-l*a),y:n.y+(s*a+l*r)},o),i.setAngle(e,e.angle+t,o)}else i.setAngle(e,e.angle+t,o)},i.scale=function(e,t,n,r){var a=0,s=0;r=r||e.position;for(var u=0;u0&&(a+=d.area,s+=d.inertia),d.position.x=r.x+(d.position.x-r.x)*t,d.position.y=r.y+(d.position.y-r.y)*n,l.update(d.bounds,d.vertices,e.velocity)}e.parts.length>1&&(e.area=a,e.isStatic||(i.setMass(e,e.density*a),i.setInertia(e,s))),e.circleRadius&&(t===n?e.circleRadius*=t:e.circleRadius=null)},i.update=function(e,t){var n=(t=(void 0!==t?t:1e3/60)*e.timeScale)*t,a=i._timeCorrection?t/(e.deltaTime||t):1,u=1-e.frictionAir*(t/s._baseDelta),d=(e.position.x-e.positionPrev.x)*a,p=(e.position.y-e.positionPrev.y)*a;e.velocity.x=d*u+e.force.x/e.mass*n,e.velocity.y=p*u+e.force.y/e.mass*n,e.positionPrev.x=e.position.x,e.positionPrev.y=e.position.y,e.position.x+=e.velocity.x,e.position.y+=e.velocity.y,e.deltaTime=t,e.angularVelocity=(e.angle-e.anglePrev)*u*a+e.torque/e.inertia*n,e.anglePrev=e.angle,e.angle+=e.angularVelocity;for(var f=0;f0&&(v.position.x+=e.velocity.x,v.position.y+=e.velocity.y),0!==e.angularVelocity&&(o.rotate(v.vertices,e.angularVelocity,e.position),c.rotate(v.axes,e.angularVelocity),f>0&&r.rotateAbout(v.position,e.angularVelocity,e.position,v.position)),l.update(v.bounds,v.vertices,e.velocity)}},i.updateVelocities=function(e){var t=i._baseDelta/e.deltaTime,n=e.velocity;n.x=(e.position.x-e.positionPrev.x)*t,n.y=(e.position.y-e.positionPrev.y)*t,e.speed=Math.sqrt(n.x*n.x+n.y*n.y),e.angularVelocity=(e.angle-e.anglePrev)*t,e.angularSpeed=Math.abs(e.angularVelocity)},i.applyForce=function(e,t,n){var i=t.x-e.position.x,o=t.y-e.position.y;e.force.x+=n.x,e.force.y+=n.y,e.torque+=i*n.y-o*n.x},i._totalProperties=function(e){for(var t={mass:0,area:0,inertia:0,centre:{x:0,y:0}},n=1===e.parts.length?0:1;n0){n||(n={}),i=t.split(" ");for(var c=0;c0&&l.motion=l.sleepThreshold/n&&i.set(l,!0)):l.sleepCounter>0&&(l.sleepCounter-=1)}else i.set(l,!1)}},i.afterCollisions=function(e){for(var t=i._motionSleepThreshold,n=0;nt&&i.set(l,!1)}}}},i.set=function(e,t){var n=e.isSleeping;t?(e.isSleeping=!0,e.sleepCounter=e.sleepThreshold,e.positionImpulse.x=0,e.positionImpulse.y=0,e.positionPrev.x=e.position.x,e.positionPrev.y=e.position.y,e.anglePrev=e.angle,e.speed=0,e.angularSpeed=0,e.motion=0,n||r.trigger(e,"sleepStart")):(e.isSleeping=!1,e.sleepCounter=0,n&&r.trigger(e,"sleepEnd"))}},function(e,t,n){var i={};e.exports=i;var o,r,a,s=n(3),l=n(9);o=[],r={overlap:0,axis:null},a={overlap:0,axis:null},i.create=function(e,t){return{pair:null,collided:!1,bodyA:e,bodyB:t,parentA:e.parent,parentB:t.parent,depth:0,normal:{x:0,y:0},tangent:{x:0,y:0},penetration:{x:0,y:0},supports:[]}},i.collides=function(e,t,n){if(i._overlapAxes(r,e.vertices,t.vertices,e.axes),r.overlap<=0)return null;if(i._overlapAxes(a,t.vertices,e.vertices,t.axes),a.overlap<=0)return null;var o,c,u=n&&n.table[l.id(e,t)];u?o=u.collision:((o=i.create(e,t)).collided=!0,o.bodyA=e.idP?P=s:sB?B=s:so?o=a:al.frictionStatic?s.frictionStatic:l.frictionStatic,e.restitution=s.restitution>l.restitution?s.restitution:l.restitution,e.slop=s.slop>l.slop?s.slop:l.slop,t.pair=e,a.length=0;for(var u=0;u0?1:.7),t.damping=t.damping||0,t.angularStiffness=t.angularStiffness||0,t.angleA=t.bodyA?t.bodyA.angle:t.angleA,t.angleB=t.bodyB?t.bodyB.angle:t.angleB,t.plugin={};var a={visible:!0,lineWidth:2,strokeStyle:"#ffffff",type:"line",anchors:!0};return 0===t.length&&t.stiffness>.1?(a.type="pin",a.anchors=!1):t.stiffness<.9&&(a.type="spring"),t.render=c.extend(a,t.render),t},i.preSolveAll=function(e){for(var t=0;t=1||0===e.length?e.stiffness*t:e.stiffness*t*t,h=e.damping*t,b=r.mult(u,g*x),S=(n?n.inverseMass:0)+(o?o.inverseMass:0),w=S+((n?n.inverseInertia:0)+(o?o.inverseInertia:0));if(h>0){var A=r.create();v=r.div(u,d),m=r.sub(o&&r.sub(o.position,o.positionPrev)||A,n&&r.sub(n.position,n.positionPrev)||A),y=r.dot(v,m)}n&&!n.isStatic&&(f=n.inverseMass/S,n.constraintImpulse.x-=b.x*f,n.constraintImpulse.y-=b.y*f,n.position.x-=b.x*f,n.position.y-=b.y*f,h>0&&(n.positionPrev.x-=h*v.x*y*f,n.positionPrev.y-=h*v.y*y*f),p=r.cross(a,b)/w*i._torqueDampen*n.inverseInertia*(1-e.angularStiffness),n.constraintImpulse.angle-=p,n.angle-=p),o&&!o.isStatic&&(f=o.inverseMass/S,o.constraintImpulse.x+=b.x*f,o.constraintImpulse.y+=b.y*f,o.position.x+=b.x*f,o.position.y+=b.y*f,h>0&&(o.positionPrev.x+=h*v.x*y*f,o.positionPrev.y+=h*v.y*y*f),p=r.cross(s,b)/w*i._torqueDampen*o.inverseInertia*(1-e.angularStiffness),o.constraintImpulse.angle+=p,o.angle+=p)}}},i.postSolveAll=function(e){for(var t=0;t0&&(d.position.x+=c.x,d.position.y+=c.y),0!==c.angle&&(o.rotate(d.vertices,c.angle,n.position),l.rotate(d.axes,c.angle),u>0&&r.rotateAbout(d.position,c.angle,n.position,d.position)),s.update(d.bounds,d.vertices,n.velocity)}c.angle*=i._warming,c.x*=i._warming,c.y*=i._warming}}},i.pointAWorld=function(e){return{x:(e.bodyA?e.bodyA.position.x:0)+(e.pointA?e.pointA.x:0),y:(e.bodyA?e.bodyA.position.y:0)+(e.pointA?e.pointA.y:0)}},i.pointBWorld=function(e){return{x:(e.bodyB?e.bodyB.position.x:0)+(e.pointB?e.pointB.x:0),y:(e.bodyB?e.bodyB.position.y:0)+(e.pointB?e.pointB.y:0)}},i.currentLength=function(e){var t=(e.bodyA?e.bodyA.position.x:0)+(e.pointA?e.pointA.x:0),n=(e.bodyA?e.bodyA.position.y:0)+(e.pointA?e.pointA.y:0),i=t-((e.bodyB?e.bodyB.position.x:0)+(e.pointB?e.pointB.x:0)),o=n-((e.bodyB?e.bodyB.position.y:0)+(e.pointB?e.pointB.y:0));return Math.sqrt(i*i+o*o)}},function(e,t,n){var i={};e.exports=i;var o=n(2),r=n(0);i.fromVertices=function(e){for(var t={},n=0;n=1&&r.warn("Bodies.trapezoid: slope parameter must be < 1.");var c,u=n*(s*=.5),d=u+(1-2*s)*n,p=d+u;c=s<.5?"L 0 0 L "+u+" "+-i+" L "+d+" "+-i+" L "+p+" 0":"L 0 0 L "+d+" "+-i+" L "+p+" 0";var f={label:"Trapezoid Body",position:{x:e,y:t},vertices:o.fromPath(c)};if(l.chamfer){var v=l.chamfer;f.vertices=o.chamfer(f.vertices,v.radius,v.quality,v.qualityMin,v.qualityMax),delete l.chamfer}return a.create(r.extend({},f,l))},i.circle=function(e,t,n,o,a){o=o||{};var s={label:"Circle Body",circleRadius:n};a=a||25;var l=Math.ceil(Math.max(10,Math.min(a,n)));return l%2==1&&(l+=1),i.polygon(e,t,l,n,r.extend({},s,o))},i.polygon=function(e,t,n,s,l){if(l=l||{},n<3)return i.circle(e,t,s,l);for(var c=2*Math.PI/n,u="",d=.5*c,p=0;p0&&o.area(M)1?(v=a.create(r.extend({parts:y.slice(0)},i)),a.setPosition(v,{x:e,y:t}),v):y[0]}},function(e,t,n){var i={};e.exports=i;var o=n(0),r=n(8);i.create=function(e){return o.extend({bodies:[],pairs:null},e)},i.setBodies=function(e,t){e.bodies=t.slice(0)},i.clear=function(e){e.bodies=[]},i.collisions=function(e){var t,n,o=[],a=e.pairs,s=e.bodies,l=s.length,c=i.canCollide,u=r.collides;for(s.sort(i._compareBoundsX),t=0;tf)break;if(!(v<_.min.y||y>_.max.y)&&(!m||!h.isStatic&&!h.isSleeping)&&c(d.collisionFilter,h.collisionFilter)){var b=h.parts.length;if(x&&1===b)(B=u(d,h,a))&&o.push(B);else for(var S=b>1?1:0,w=g>1?1:0;w_.max.x||p.max.x<_.min.x||p.max.y<_.min.y||p.min.y>_.max.y||(B=u(A,M,a))&&o.push(B)}}}}return o},i.canCollide=function(e,t){return e.group===t.group&&0!==e.group?e.group>0:0!=(e.mask&t.category)&&0!=(t.mask&e.category)},i._compareBoundsX=function(e,t){return e.bounds.min.x-t.bounds.min.x}},function(e,t,n){var i={};e.exports=i;var o=n(0);i.create=function(e){var t={};return e||o.log("Mouse.create: element was undefined, defaulting to document.body","warn"),t.element=e||document.body,t.absolute={x:0,y:0},t.position={x:0,y:0},t.mousedownPosition={x:0,y:0},t.mouseupPosition={x:0,y:0},t.offset={x:0,y:0},t.scale={x:1,y:1},t.wheelDelta=0,t.button=-1,t.pixelRatio=parseInt(t.element.getAttribute("data-pixel-ratio"),10)||1,t.sourceEvents={mousemove:null,mousedown:null,mouseup:null,mousewheel:null},t.mousemove=function(e){var n=i._getRelativeMousePosition(e,t.element,t.pixelRatio);e.changedTouches&&(t.button=0,e.preventDefault()),t.absolute.x=n.x,t.absolute.y=n.y,t.position.x=t.absolute.x*t.scale.x+t.offset.x,t.position.y=t.absolute.y*t.scale.y+t.offset.y,t.sourceEvents.mousemove=e},t.mousedown=function(e){var n=i._getRelativeMousePosition(e,t.element,t.pixelRatio);e.changedTouches?(t.button=0,e.preventDefault()):t.button=e.button,t.absolute.x=n.x,t.absolute.y=n.y,t.position.x=t.absolute.x*t.scale.x+t.offset.x,t.position.y=t.absolute.y*t.scale.y+t.offset.y,t.mousedownPosition.x=t.position.x,t.mousedownPosition.y=t.position.y,t.sourceEvents.mousedown=e},t.mouseup=function(e){var n=i._getRelativeMousePosition(e,t.element,t.pixelRatio);e.changedTouches&&e.preventDefault(),t.button=-1,t.absolute.x=n.x,t.absolute.y=n.y,t.position.x=t.absolute.x*t.scale.x+t.offset.x,t.position.y=t.absolute.y*t.scale.y+t.offset.y,t.mouseupPosition.x=t.position.x,t.mouseupPosition.y=t.position.y,t.sourceEvents.mouseup=e},t.mousewheel=function(e){t.wheelDelta=Math.max(-1,Math.min(1,e.wheelDelta||-e.detail)),e.preventDefault(),t.sourceEvents.mousewheel=e},i.setElement(t,t.element),t},i.setElement=function(e,t){e.element=t,t.addEventListener("mousemove",e.mousemove,{passive:!0}),t.addEventListener("mousedown",e.mousedown,{passive:!0}),t.addEventListener("mouseup",e.mouseup,{passive:!0}),t.addEventListener("wheel",e.mousewheel,{passive:!1}),t.addEventListener("touchmove",e.mousemove,{passive:!1}),t.addEventListener("touchstart",e.mousedown,{passive:!1}),t.addEventListener("touchend",e.mouseup,{passive:!1})},i.clearSourceEvents=function(e){e.sourceEvents.mousemove=null,e.sourceEvents.mousedown=null,e.sourceEvents.mouseup=null,e.sourceEvents.mousewheel=null,e.wheelDelta=0},i.setOffset=function(e,t){e.offset.x=t.x,e.offset.y=t.y,e.position.x=e.absolute.x*e.scale.x+e.offset.x,e.position.y=e.absolute.y*e.scale.y+e.offset.y},i.setScale=function(e,t){e.scale.x=t.x,e.scale.y=t.y,e.position.x=e.absolute.x*e.scale.x+e.offset.x,e.position.y=e.absolute.y*e.scale.y+e.offset.y},i._getRelativeMousePosition=function(e,t,n){var i,o,r=t.getBoundingClientRect(),a=document.documentElement||document.body.parentNode||document.body,s=void 0!==window.pageXOffset?window.pageXOffset:a.scrollLeft,l=void 0!==window.pageYOffset?window.pageYOffset:a.scrollTop,c=e.changedTouches;return c?(i=c[0].pageX-r.left-s,o=c[0].pageY-r.top-l):(i=e.pageX-r.left-s,o=e.pageY-r.top-l),{x:i/(t.clientWidth/(t.width||t.clientWidth)*n),y:o/(t.clientHeight/(t.height||t.clientHeight)*n)}}},function(e,t,n){var i={};e.exports=i;var o=n(0);i._registry={},i.register=function(e){if(i.isPlugin(e)||o.warn("Plugin.register:",i.toString(e),"does not implement all required fields."),e.name in i._registry){var t=i._registry[e.name],n=i.versionParse(e.version).number,r=i.versionParse(t.version).number;n>r?(o.warn("Plugin.register:",i.toString(t),"was upgraded to",i.toString(e)),i._registry[e.name]=e):n-1},i.isFor=function(e,t){var n=e.for&&i.dependencyParse(e.for);return!e.for||t.name===n.name&&i.versionSatisfies(t.version,n.range)},i.use=function(e,t){if(e.uses=(e.uses||[]).concat(t||[]),0!==e.uses.length){for(var n=i.dependencies(e),r=o.topologicalSort(n),a=[],s=0;s0&&o.info(a.join(" "))}else o.warn("Plugin.use:",i.toString(e),"does not specify any dependencies to install.")},i.dependencies=function(e,t){var n=i.dependencyParse(e),r=n.name;if(!(r in(t=t||{}))){e=i.resolve(e)||e,t[r]=o.map(e.uses||[],(function(t){i.isPlugin(t)&&i.register(t);var r=i.dependencyParse(t),a=i.resolve(t);return a&&!i.versionSatisfies(a.version,r.range)?(o.warn("Plugin.dependencies:",i.toString(a),"does not satisfy",i.toString(r),"used by",i.toString(n)+"."),a._warned=!0,e._warned=!0):a||(o.warn("Plugin.dependencies:",i.toString(t),"used by",i.toString(n),"could not be resolved."),e._warned=!0),r.name}));for(var a=0;a=|>)?\s*((\d+)\.(\d+)\.(\d+))(-[0-9A-Za-z-+]+)?$/;t.test(e)||o.warn("Plugin.versionParse:",e,"is not a valid version or range.");var n=t.exec(e),i=Number(n[4]),r=Number(n[5]),a=Number(n[6]);return{isRange:Boolean(n[1]||n[2]),version:n[3],range:e,operator:n[1]||n[2]||"",major:i,minor:r,patch:a,parts:[i,r,a],prerelease:n[7],number:1e8*i+1e4*r+a}},i.versionSatisfies=function(e,t){t=t||"*";var n=i.versionParse(t),o=i.versionParse(e);if(n.isRange){if("*"===n.operator||"*"===e)return!0;if(">"===n.operator)return o.number>n.number;if(">="===n.operator)return o.number>=n.number;if("~"===n.operator)return o.major===n.major&&o.minor===n.minor&&o.patch>=n.patch;if("^"===n.operator)return n.major>0?o.major===n.major&&o.number>=n.number:n.minor>0?o.minor===n.minor&&o.patch>=n.patch:o.patch===n.patch}return e===t||"*"===e}},function(e,t){var n={};e.exports=n,n.create=function(e){return{vertex:e,normalImpulse:0,tangentImpulse:0}}},function(e,t,n){var i={};e.exports=i;var o=n(7),r=n(18),a=n(13),s=n(19),l=n(5),c=n(6),u=n(10),d=n(0),p=n(4);i._deltaMax=1e3/60,i.create=function(e){e=e||{};var t=d.extend({positionIterations:6,velocityIterations:4,constraintIterations:2,enableSleeping:!1,events:[],plugin:{},gravity:{x:0,y:1,scale:.001},timing:{timestamp:0,timeScale:1,lastDelta:0,lastElapsed:0,lastUpdatesPerFrame:0}},e);return t.world=e.world||c.create({label:"World"}),t.pairs=e.pairs||s.create(),t.detector=e.detector||a.create(),t.grid={buckets:[]},t.world.gravity=t.gravity,t.broadphase=t.grid,t.metrics={},t},i.update=function(e,t){var n,p=d.now(),f=e.world,v=e.detector,y=e.pairs,m=e.timing,g=m.timestamp;t>i._deltaMax&&d.warnOnce("Matter.Engine.update: delta argument is recommended to be less than or equal to",i._deltaMax.toFixed(3),"ms."),t=void 0!==t?t:d._baseDelta,t*=m.timeScale,m.timestamp+=t,m.lastDelta=t;var x={timestamp:m.timestamp,delta:t};l.trigger(e,"beforeUpdate",x);var h=c.allBodies(f),b=c.allConstraints(f);for(f.isModified&&(a.setBodies(v,h),c.setModified(f,!1,!1,!0)),e.enableSleeping&&o.update(h,t),i._bodiesApplyGravity(h,e.gravity),t>0&&i._bodiesUpdate(h,t),l.trigger(e,"beforeSolve",x),u.preSolveAll(h),n=0;n0&&l.trigger(e,"collisionStart",{pairs:y.collisionStart,timestamp:m.timestamp,delta:t});var w=d.clamp(20/e.positionIterations,0,1);for(r.preSolvePosition(y.list),n=0;n0&&l.trigger(e,"collisionActive",{pairs:y.collisionActive,timestamp:m.timestamp,delta:t}),y.collisionEnd.length>0&&l.trigger(e,"collisionEnd",{pairs:y.collisionEnd,timestamp:m.timestamp,delta:t}),i._bodiesClearForces(h),l.trigger(e,"afterUpdate",x),e.timing.lastElapsed=d.now()-p,e},i.merge=function(e,t){if(d.extend(e,t),t.world){e.world=t.world,i.clear(e);for(var n=c.allBodies(e.world),r=0;rN?(o=j>0?j:-j,(n=y.friction*(j>0?1:-1)*c)<-o?n=-o:n>o&&(n=o)):(n=j,o=f);var G=R*w-D*S,z=V*w-E*S,X=_/(C+g.inverseInertia*G*G+x.inverseInertia*z*z),Q=(1+y.restitution)*q*X;if(n*=X,q0&&(I.normalImpulse=0),Q=I.normalImpulse-Y}if(j<-d||j>d)I.tangentImpulse=0;else{var Z=I.tangentImpulse;I.tangentImpulse+=n,I.tangentImpulse<-o&&(I.tangentImpulse=-o),I.tangentImpulse>o&&(I.tangentImpulse=o),n=I.tangentImpulse-Z}var $=S*Q+A*n,J=w*Q+P*n;g.isStatic||g.isSleeping||(g.positionPrev.x+=$*g.inverseMass,g.positionPrev.y+=J*g.inverseMass,g.anglePrev+=(R*J-D*$)*g.inverseInertia),x.isStatic||x.isSleeping||(x.positionPrev.x-=$*x.inverseMass,x.positionPrev.y-=J*x.inverseMass,x.anglePrev-=(V*J-E*$)*x.inverseInertia)}}}}},function(e,t,n){var i={};e.exports=i;var o=n(9),r=n(0);i.create=function(e){return r.extend({table:{},list:[],collisionStart:[],collisionActive:[],collisionEnd:[]},e)},i.update=function(e,t,n){var i,r,a,s,l=e.list,c=l.length,u=e.table,d=t.length,p=e.collisionStart,f=e.collisionEnd,v=e.collisionActive;for(p.length=0,f.length=0,v.length=0,s=0;sy&&(y=x),s.translate(g,{x:.5*h,y:.5*x}),d=g.bounds.max.x+r,o.addBody(u,g),c=g,f+=1}else d+=r}p+=y+a,d=e}return u},i.chain=function(e,t,n,i,s,l){for(var c=e.bodies,u=1;u0)for(c=0;c0&&(p=f[c-1+(l-1)*t],o.addConstraint(e,r.create(a.extend({bodyA:p,bodyB:d},s)))),i&&cp||a<(c=p-c)||a>n-1-c))return 1===d&&s.translate(u,{x:(a+(n%2==1?1:-1))*f,y:0}),l(e+(u?a*f:0)+a*r,i,a,c,u,d)}))},i.newtonsCradle=function(e,t,n,i,a){for(var s=o.create({label:"Newtons Cradle"}),c=0;cu.bounds.max.x||f.bounds.max.yu.bounds.max.y))){var v=i._getRegion(e,f);if(!f.region||v.id!==f.region.id||o){f.region&&!o||(f.region=v);var y=i._regionUnion(v,f.region);for(a=y.startCol;a<=y.endCol;a++)for(s=y.startRow;s<=y.endRow;s++){l=d[c=i._getBucketId(a,s)];var m=a>=v.startCol&&a<=v.endCol&&s>=v.startRow&&s<=v.endRow,g=a>=f.region.startCol&&a<=f.region.endCol&&s>=f.region.startRow&&s<=f.region.endRow;!m&&g&&g&&l&&i._bucketRemoveBody(e,l,f),(f.region===v||m&&!g||o)&&(l||(l=i._createBucket(d,c)),i._bucketAddBody(e,l,f))}f.region=v,p=!0}}}p&&(e.pairsList=i._createActivePairsList(e))},a(i,"update","Grid.update ➤ replaced by Matter.Detector"),i.clear=function(e){e.buckets={},e.pairs={},e.pairsList=[]},a(i,"clear","Grid.clear ➤ replaced by Matter.Detector"),i._regionUnion=function(e,t){var n=Math.min(e.startCol,t.startCol),o=Math.max(e.endCol,t.endCol),r=Math.min(e.startRow,t.startRow),a=Math.max(e.endRow,t.endRow);return i._createRegion(n,o,r,a)},i._getRegion=function(e,t){var n=t.bounds,o=Math.floor(n.min.x/e.bucketWidth),r=Math.floor(n.max.x/e.bucketWidth),a=Math.floor(n.min.y/e.bucketHeight),s=Math.floor(n.max.y/e.bucketHeight);return i._createRegion(o,r,a,s)},i._createRegion=function(e,t,n,i){return{id:e+","+t+","+n+","+i,startCol:e,endCol:t,startRow:n,endRow:i}},i._getBucketId=function(e,t){return"C"+e+"R"+t},i._createBucket=function(e,t){return e[t]=[]},i._bucketAddBody=function(e,t,n){var i,r=e.pairs,a=o.id,s=t.length;for(i=0;i0?s.push(t):delete i[o[n]];return s}},function(e,t,n){var i={};e.exports=i;var o=n(3),r=n(7),a=n(14),s=n(5),l=n(13),c=n(10),u=n(6),d=n(0),p=n(1);i.create=function(e,t){var n=(e?e.mouse:null)||(t?t.mouse:null);n||(e&&e.render&&e.render.canvas?n=a.create(e.render.canvas):t&&t.element?n=a.create(t.element):(n=a.create(),d.warn("MouseConstraint.create: options.mouse was undefined, options.element was undefined, may not function as expected")));var o={type:"mouseConstraint",mouse:n,element:null,body:null,constraint:c.create({label:"Mouse Constraint",pointA:n.position,pointB:{x:0,y:0},length:.01,stiffness:.1,angularStiffness:1,render:{strokeStyle:"#90EE90",lineWidth:3}}),collisionFilter:{category:1,mask:4294967295,group:0}},r=d.extend(o,t);return s.on(e,"beforeUpdate",(function(){var t=u.allBodies(e.world);i.update(r,t),i._triggerEvents(r)})),r},i.update=function(e,t){var n=e.mouse,i=e.constraint,a=e.body;if(0===n.button){if(i.bodyB)r.set(i.bodyB,!1),i.pointA=n.position;else for(var c=0;c1?1:0;uo.max.x&&(o.max.x=c.x),l.yo.max.y&&(o.max.y=c.y))}var d=o.max.x-o.min.x+2*n.x,p=o.max.y-o.min.y+2*n.y,f=e.canvas.height,v=e.canvas.width/f,y=d/p,m=1,g=1;y>v?g=y/v:m=v/y,e.options.hasBounds=!0,e.bounds.min.x=o.min.x,e.bounds.max.x=o.min.x+d*m,e.bounds.min.y=o.min.y,e.bounds.max.y=o.min.y+p*g,i&&(e.bounds.min.x+=.5*d-d*m*.5,e.bounds.max.x+=.5*d-d*m*.5,e.bounds.min.y+=.5*p-p*g*.5,e.bounds.max.y+=.5*p-p*g*.5),e.bounds.min.x-=n.x,e.bounds.max.x-=n.x,e.bounds.min.y-=n.y,e.bounds.max.y-=n.y,e.mouse&&(u.setScale(e.mouse,{x:(e.bounds.max.x-e.bounds.min.x)/e.canvas.width,y:(e.bounds.max.y-e.bounds.min.y)/e.canvas.height}),u.setOffset(e.mouse,e.bounds.min))},i.startViewTransform=function(e){var t=e.bounds.max.x-e.bounds.min.x,n=e.bounds.max.y-e.bounds.min.y,i=t/e.options.width,o=n/e.options.height;e.context.setTransform(e.options.pixelRatio/i,0,0,e.options.pixelRatio/o,0,0),e.context.translate(-e.bounds.min.x,-e.bounds.min.y)},i.endViewTransform=function(e){e.context.setTransform(e.options.pixelRatio,0,0,e.options.pixelRatio,0,0)},i.world=function(e,t){var n,o=r.now(),d=e.engine,p=d.world,f=e.canvas,v=e.context,m=e.options,g=e.timing,x=a.allBodies(p),h=a.allConstraints(p),b=m.wireframes?m.wireframeBackground:m.background,S=[],w=[],A={timestamp:d.timing.timestamp};if(l.trigger(e,"beforeRender",A),e.currentBackground!==b&&y(e,b),v.globalCompositeOperation="source-in",v.fillStyle="transparent",v.fillRect(0,0,f.width,f.height),v.globalCompositeOperation="source-over",m.hasBounds){for(n=0;n1?1:0;a1?1:0;s1?1:0;r1?1:0;s1?1:0;r1?1:0;r1?1:0;o0)){var u=i.activeContacts[0].vertex.x,d=i.activeContacts[0].vertex.y;2===i.activeContacts.length&&(u=(i.activeContacts[0].vertex.x+i.activeContacts[1].vertex.x)/2,d=(i.activeContacts[0].vertex.y+i.activeContacts[1].vertex.y)/2),o.bodyB===o.supports[0].body||!0===o.bodyA.isStatic?s.moveTo(u-8*o.normal.x,d-8*o.normal.y):s.moveTo(u+8*o.normal.x,d+8*o.normal.y),s.lineTo(u,d)}l.wireframes?s.strokeStyle="rgba(255,165,0,0.7)":s.strokeStyle="orange",s.lineWidth=1,s.stroke()},i.separations=function(e,t,n){var i,o,r,a,s,l=n,c=e.options;for(l.beginPath(),s=0;st.maxFrameDelta)&&(d=t.frameDelta||c),t.frameDeltaSmoothing){t.frameDeltaHistory.push(d),t.frameDeltaHistory=t.frameDeltaHistory.slice(-t.frameDeltaHistorySize);var p=t.frameDeltaHistory.slice(0).sort(),f=t.frameDeltaHistory.slice(p.length*i._smoothingLowerBound,p.length*i._smoothingUpperBound);d=e(f)||d}t.frameDeltaSnapping&&(d=1e3/Math.round(1e3/d)),t.frameDelta=d,t.timeLastTick=s,t.timeBuffer+=t.frameDelta,t.timeBuffer=a.clamp(t.timeBuffer,0,t.frameDelta+c*i._timeBufferMargin),t.lastUpdatesDeferred=0;var v=t.maxUpdates,y={timestamp:n.timing.timestamp};for(o.trigger(t,"beforeTick",y),o.trigger(t,"tick",y);c>0&&t.timeBuffer>=c*i._timeBufferMargin;){var m=a.now();o.trigger(t,"beforeUpdate",y),r.update(n,c),o.trigger(t,"afterUpdate",y),t.timeBuffer-=c,u+=1;var g=a.now()-l,x=a.now()-m;if(u>=v||g+x>t.maxFrameTime){t.lastUpdatesDeferred=Math.round(Math.max(0,t.timeBuffer/c-i._timeBufferMargin));break}}n.timing.lastUpdatesPerFrame=u,o.trigger(t,"afterTick",y),t.frameDeltaHistory.length>=100&&(t.lastUpdatesDeferred&&Math.round(t.frameDelta/c)>v?a.warnOnce("Matter.Runner: runner reached runner.maxUpdates, see docs."):t.lastUpdatesDeferred&&a.warnOnce("Matter.Runner: runner reached runner.maxFrameTime, see docs."),void 0!==t.isFixed&&a.warnOnce("Matter.Runner: runner.isFixed is now redundant, see docs."),(t.deltaMin||t.deltaMax)&&a.warnOnce("Matter.Runner: runner.deltaMin and runner.deltaMax were removed, see docs."),0!==t.fps&&a.warnOnce("Matter.Runner: runner.fps was replaced by runner.delta, see docs."))},i.stop=function(e){i._cancelNextFrame(e)},i._onNextFrame=function(e,t){return"undefined"!=typeof window?e.frameRequestId=window.requestAnimationFrame(t):a.warnOnce("Matter.Runner: missing required global window.requestAnimationFrame."),e.frameRequestId},i._cancelNextFrame=function(e){"undefined"!=typeof window?window.cancelAnimationFrame(e.frameRequestId):a.warnOnce("Matter.Runner: missing required global window.cancelAnimationFrame.")};var e=function(e){for(var t=0,n=e.length,i=0;i1;if(!p||e!=p.x||t!=p.y){p&&i?(f=p.x,v=p.y):(f=0,v=0);var o={x:f+e,y:v+t};!i&&p||(p=o),y.push(o),g=f+e,x=v+t}},b=function(e){var t=e.pathSegTypeAsLetter.toUpperCase();if("Z"!==t){switch(t){case"M":case"L":case"T":case"C":case"S":case"Q":g=e.x,x=e.y;break;case"H":g=e.x;break;case"V":x=e.y}h(g,x,e.pathSegType)}};for(i._svgPathToAbsolute(e),a=e.getTotalLength(),c=[],n=0;n