diff --git a/.gitignore b/.gitignore index baa4e68..b5b01b1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,12 +1,11 @@ .idea node_modules npm-debug.log -doc +docs matter-doc-theme build/matter-dev.js build/matter-dev.min.js demo/js/lib/matter-dev.js -demo/js/Examples.js demo/js/Examples.min.js examples/build test/browser/diffs diff --git a/CHANGELOG.md b/CHANGELOG.md index 3e3f202..63a3891 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,57 @@ +## 0.15.0 (2020-12-24) + +* add window global, stub require and handle bad values in test tools ([497ac80](https://github.com/liabru/matter-js/commit/497ac80)) +* added Body.setCentre, closes #684, closes #461, closes #679 ([2ec247b](https://github.com/liabru/matter-js/commit/2ec247b)), closes [#684](https://github.com/liabru/matter-js/issues/684) [#461](https://github.com/liabru/matter-js/issues/461) [#679](https://github.com/liabru/matter-js/issues/679) +* added browser tests ([ceb7cd5](https://github.com/liabru/matter-js/commit/ceb7cd5)) +* Added build comparison tools and tests ([b7c938a](https://github.com/liabru/matter-js/commit/b7c938a)) +* added check for window in Common.now ([9ef9d02](https://github.com/liabru/matter-js/commit/9ef9d02)) +* added comparison output file option to test tools ([45aae25](https://github.com/liabru/matter-js/commit/45aae25)) +* Added config and test files to lint ([21e4ea6](https://github.com/liabru/matter-js/commit/21e4ea6)) +* added Constraint.pointAWorld and Constraint.pointBWorld ([3c32969](https://github.com/liabru/matter-js/commit/3c32969)) +* added examples to dev server bundle and commit built examples ([fe80478](https://github.com/liabru/matter-js/commit/fe80478)) +* added module export to examples ([f9ea799](https://github.com/liabru/matter-js/commit/f9ea799)) +* added overlap metric to test tools ([3fd674d](https://github.com/liabru/matter-js/commit/3fd674d)) +* added release scripts ([341c247](https://github.com/liabru/matter-js/commit/341c247)) +* added tag push to release task ([060283b](https://github.com/liabru/matter-js/commit/060283b)) +* added timing to engine snapshot ([e0cdbb8](https://github.com/liabru/matter-js/commit/e0cdbb8)) +* Added watch content base to dev server ([f471d4e](https://github.com/liabru/matter-js/commit/f471d4e)) +* added webpack build script ([046013e](https://github.com/liabru/matter-js/commit/046013e)) +* changed alpha build configuration ([182c84a](https://github.com/liabru/matter-js/commit/182c84a)) +* changed demo to auto populate examples with sourceLink and init ([5b0d34b](https://github.com/liabru/matter-js/commit/5b0d34b)) +* changed demo to serve without sub-directory ([823bbc0](https://github.com/liabru/matter-js/commit/823bbc0)) +* changed docs build config ([864452d](https://github.com/liabru/matter-js/commit/864452d)) +* changed example tests to use jest ([104d319](https://github.com/liabru/matter-js/commit/104d319)) +* fix decomp import in Bodies.fromVertices ([94e9614](https://github.com/liabru/matter-js/commit/94e9614)) +* fix decomp require ([0af1645](https://github.com/liabru/matter-js/commit/0af1645)) +* fix issues with render pixel ratio, closes #686, closes #687 ([d577477](https://github.com/liabru/matter-js/commit/d577477)), closes [#686](https://github.com/liabru/matter-js/issues/686) [#687](https://github.com/liabru/matter-js/issues/687) +* fix lint ([5a0079d](https://github.com/liabru/matter-js/commit/5a0079d)) +* fix lint issues ([9ca21c1](https://github.com/liabru/matter-js/commit/9ca21c1)) +* fix path to build in test worker ([fcdb4fa](https://github.com/liabru/matter-js/commit/fcdb4fa)) +* fix preversion script ([c368c14](https://github.com/liabru/matter-js/commit/c368c14)) +* fix terrain example module export ([4a967ec](https://github.com/liabru/matter-js/commit/4a967ec)) +* Fix typo in docs ([c486635](https://github.com/liabru/matter-js/commit/c486635)) +* fixed plugins in compare ([82bb415](https://github.com/liabru/matter-js/commit/82bb415)) +* implemented threaded comparison testing ([285d70d](https://github.com/liabru/matter-js/commit/285d70d)) +* Optimized Body's hidden class ([b3220cf](https://github.com/liabru/matter-js/commit/b3220cf)) +* Optimized Events.trigger method when no event is emitted ([b17cb48](https://github.com/liabru/matter-js/commit/b17cb48)) +* remove gulp ([6a28090](https://github.com/liabru/matter-js/commit/6a28090)) +* remove old demo libs ([13c7eb5](https://github.com/liabru/matter-js/commit/13c7eb5)) +* removed unused gulp release tasks ([e5a7311](https://github.com/liabru/matter-js/commit/e5a7311)) +* removed yuidocjs dev dependency ([ee848d2](https://github.com/liabru/matter-js/commit/ee848d2)) +* Set loose build version on dev server ([1fcf292](https://github.com/liabru/matter-js/commit/1fcf292)) +* update build script ([90abab6](https://github.com/liabru/matter-js/commit/90abab6)) +* update default render theme ([d258411](https://github.com/liabru/matter-js/commit/d258411)) +* update demo and example render styles ([6dd5ec5](https://github.com/liabru/matter-js/commit/6dd5ec5)) +* update dependencies ([e1e058c](https://github.com/liabru/matter-js/commit/e1e058c)) ([5f5b8a1](https://github.com/liabru/matter-js/commit/5f5b8a1)) +* update examples build config and scripts ([69afb11](https://github.com/liabru/matter-js/commit/69afb11)) +* update package lock ([ac3da07](https://github.com/liabru/matter-js/commit/ac3da07)) +* updated build scripts ([6b698ea](https://github.com/liabru/matter-js/commit/6b698ea)) +* updated ci ([288b9cd](https://github.com/liabru/matter-js/commit/288b9cd)) +* updated docs ([50cf171](https://github.com/liabru/matter-js/commit/50cf171)) +* updated readme ([ea5c012](https://github.com/liabru/matter-js/commit/ea5c012)) ([61b1963](https://github.com/liabru/matter-js/commit/61b1963)) + + + ## 0.14.2 (2018-06-11) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 242a4bb..386aa5a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -6,7 +6,7 @@ By providing any kind of contribution to this project, **you must agree and be l ## Contributions -Contributions by pull request or issues are welcome. Please ensure they follow the same style and architecture as the rest of the code. Use `npm run lint` before submitting. Please **do not include** any changes to the files in the `build` directory. +Contributions by pull request or issues are welcome. Please ensure they follow the same style and architecture as the rest of the code. Use `npm run lint` and see [Testing](#Testing) below before submitting. Please **do not include** any changes to the files in the `build` directory. Before contributing please read the license agreement described at the beginning of this document. @@ -22,6 +22,16 @@ which will install the required build dependencies, then run which will run the development server and opens `http://localhost:8000/` in your browser. Any changes you make to the source will automatically rebuild and reload the page. +## Testing + +All contributions should pass when running the commands + +- `npm run lint` +- `npm run test` +- `npm run test-browser` + +The output of `npm run test` also includes a [comparison report](https://github.com/liabru/matter-js/pull/794), which highlights changes in results, performance and accuracy against the last release build. + ## Commands The following development commands can be run at the terminal @@ -33,8 +43,8 @@ creates a release build - **npm run lint** runs the linter - **npm run test** -runs the tests -- **npm run compare** -compares the output of examples for current source against release build +runs the tests and compares results +- **npm run test-browser** +runs the browser tests - **npm run doc** builds the documentation diff --git a/Gulpfile.js b/Gulpfile.js deleted file mode 100644 index cd7bccb..0000000 --- a/Gulpfile.js +++ /dev/null @@ -1,90 +0,0 @@ -/* eslint-env es6 */ -"use strict"; - -const gulp = require('gulp'); -const bump = require('gulp-bump'); -const changelog = require('gulp-conventional-changelog'); -const tag = require('gulp-tag-version'); -const sequence = require('run-sequence'); -const gutil = require('gulp-util'); -const pkg = require('./package.json'); -const exec = require('child_process').exec; - -const shellExec = (command, callback) => { - const args = process.argv.slice(3).join(' '), - proc = exec(command + ' ' + args, (err, stdout, stderr) => { - callback(err, stdout, stderr, proc); - }); - - proc.stdout.on('data', data => process.stdout.write(data)); - proc.stderr.on('data', data => process.stderr.write(data)); -}; - -const shell = command => (callback => { shellExec(command, callback); }); - -const hint = command => (callback => { - gutil.log(gutil.colors.red('Error'), 'use', gutil.colors.yellow(command), 'instead.'); - callback(); -}); - -gulp.task('default', hint('npm run build')); -gulp.task('dev', hint('npm run dev')); -gulp.task('build', hint('npm run build')); -gulp.task('test', hint('npm run test')); -gulp.task('lint', hint('npm run lint')); - -gulp.task('doc', callback => { - shellExec(`yuidoc --config yuidoc.json --project-version ${pkg.version}`, callback); -}); - -gulp.task('bump', () => { - return gulp.src(['package.json', 'bower.json']) - .pipe(bump({ type: process.argv[4] || 'minor' })) - .pipe(gulp.dest('.')); -}); - -gulp.task('tag', () => { - return gulp.src('package.json') - .pipe(tag({ prefix: '' })); -}); - -gulp.task('changelog', () => { - return gulp.src('CHANGELOG.md') - .pipe(changelog()) - .pipe(gulp.dest('.')); -}); - -gulp.task('release', callback => { - shellExec('git status --porcelain', (err, stdout) => { - if (stdout && stdout.trim()) { - throw new gutil.PluginError({ - plugin: 'release', - message: 'cannot build release as there are uncomitted changes' - }); - } else { - sequence( - 'release:lint', 'bump', 'release:build', 'release:test', - 'doc', 'changelog', callback - ); - } - }); -}); - -gulp.task('release:lint', shell('npm run lint')); -gulp.task('release:build', shell('npm run build')); -gulp.task('release:test', shell('TEST_BUILD=true npm run test')); -gulp.task('release:push:git', shell('git push origin && git push origin --tags')); -gulp.task('release:push:npm', shell('npm publish')); - -gulp.task('release:push', callback => { - shellExec('git status --porcelain', (err, stdout) => { - if (stdout && stdout.trim()) { - throw new gutil.PluginError({ - plugin: 'release', - message: 'cannot push release as it has not yet been committed' - }); - } else { - sequence('tag', 'release:push:git', 'release:push:npm', callback); - } - }); -}); diff --git a/README.md b/README.md index 9c8fc2f..b5745b5 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ -Matter.js +Matter.js > *Matter.js* is a JavaScript 2D rigid body physics engine for the web -[brm.io/matter-js](http://brm.io/matter-js/) +[brm.io/matter-js](https://brm.io/matter-js/) -[Demos](#demos) - [Gallery](#gallery) - [Features](#features) - [Plugins](#plugins) - [Install](#install) - [Usage](#usage) - [Examples](#examples) - [Docs](#documentation) - [Wiki](https://github.com/liabru/matter-js/wiki) - [References](#references) - [License](#license) +[Demos](#demos) ・ [Gallery](#gallery) ・ [Features](#features) ・ [Plugins](#plugins) ・ [Install](#install) ・ [Usage](#usage) ・ [Examples](#examples) ・ [Docs](#documentation) ・ [Wiki](https://github.com/liabru/matter-js/wiki) ・ [References](#references) ・ [License](#license) [![Build Status](https://travis-ci.org/liabru/matter-js.png?branch=master)](https://travis-ci.org/liabru/matter-js) @@ -14,51 +14,55 @@ + + +
@@ -69,16 +73,18 @@ See how others are using matter.js physics -- [Les métamorphoses de Mr. Kalia](http://lab212.org/Les-metamorphoses-de-Mr-Kalia) by Lab212 for Google -- [4ify](http://pauliescanlon.io/4ify-channel-4-rebrand-2/) by Supernatural for Channel 4 -- [Adobe Analytics Live Stream](http://adobefirehose.mediarain.com/) by Rain for Adobe -- [Blood Sweat & Tools Interactive](http://bloodsweatandtools.discovery.ca/gamebench/) by Jam3 for Discovery -- [Oracle OpenWorld Experiment](http://theappslab.com/2016/10/10/how-i-attended-oracle-openworld-2016/) by Ed Jones for Oracle -- [Pablo The Flamingo](http://pablotheflamingo.com/) by Nathan Gordon -- [Goblins and Grottos](http://store.steampowered.com/app/389190) by Psychic Software -- [masQueLaCara](https://www.instagram.com/p/BCFqCs6JNsq/) by Zach Lieberman for Art Blocks Houston -- [#GIFMYLIVE](http://bonhommeparis.com/en/projects/arte-gifmylive) by Bonhomme for Arte -- [Hype](http://tumult.com/hype/pro/) by Tumult +- [Patrick Heng](https://patrickheng.com/) by Patrick Heng +- [USELESS](https://useless.london/) by Nice and Serious +- [Secret 7](https://secret-7.com/) by Goodness +- [New Company](https://www.new.company/) by New Company +- [Game of The Year](https://gameoftheyear.withgoogle.com/) by Google +- [Pablo The Flamingo](https://pablotheflamingo.com/) by Nathan Gordon +- [Les métamorphoses de Mr. Kalia](https://lab212.org/oeuvres/2:art/18/Les-metamorphoses-de-Mr-Kalia) by Lab212 +- [Phaser](https://phaser.io/) by Photon Storm +- [Sorry I Have No Filter](https://sorryihavenofilter.com/pages/about/) by Jessica Walsh +- [Fuse](https://fuse.blog/) by Fuse +- [Glyphfinder](https://www.glyphfinder.com/) by überdosis +- [Isolation](https://isolation.is/postcards/my-week) by sabato studio - [more...](https://github.com/liabru/matter-js/wiki/Gallery) ### Features @@ -131,7 +137,7 @@ See the list of [tutorials](https://github.com/liabru/matter-js/wiki/Tutorials). ### Examples See the [examples](https://github.com/liabru/matter-js/tree/master/examples) directory which contains the source for all [demos](#demos). -There are even more examples on [codepen](http://codepen.io/collection/Fuagy/). +There are even more examples on [codepen](https://codepen.io/collection/Fuagy/). ### Plugins @@ -144,11 +150,11 @@ The engine can be extended through plugins, see these resources: ### Documentation -See the [API Documentation](http://brm.io/matter-js/docs/) and the [wiki](https://github.com/liabru/matter-js/wiki) +See the [API Documentation](https://brm.io/matter-js/docs/) and the [wiki](https://github.com/liabru/matter-js/wiki) ### Building and Contributing -To build you must first install [node.js](http://nodejs.org/), then run +To build you must first install [node.js](https://nodejs.org/), then run npm install @@ -168,7 +174,7 @@ See the wiki page on [References](https://github.com/liabru/matter-js/wiki/Refer ### License -Matter.js is licensed under [The MIT License (MIT)](http://opensource.org/licenses/MIT) +Matter.js is licensed under [The MIT License (MIT)](https://opensource.org/licenses/MIT) Copyright (c) 2014 Liam Brummitt This license is also supplied with the release and source code. diff --git a/RELEASE.md b/RELEASE.md new file mode 100644 index 0000000..a334688 --- /dev/null +++ b/RELEASE.md @@ -0,0 +1,42 @@ +## ▲.● matter.js `0.15.0` + +Release notes for `0.15.0`. See the release [readme](https://github.com/liabru/matter-js/blob/0.15.0/README.md) for further information. + +### Highlights ✺ + +- __Optimised performance up to ~30% boost vs. `0.14.2`__ ([#528](https://github.com/liabru/matter-js/pull/528)) ([#522](https://github.com/liabru/matter-js/pull/522)) ([#553](https://github.com/liabru/matter-js/pull/553)) +- Added `Body.setCentre` ([2ec247b](https://github.com/liabru/matter-js/commit/2ec247b)) +- Added `Constraint.pointAWorld` and `Constraint.pointBWorld` ([3c32969](https://github.com/liabru/matter-js/commit/3c32969)) +- Changed default colour scheme ([d258411](https://github.com/liabru/matter-js/commit/d258411)) ([6dd5ec5](https://github.com/liabru/matter-js/commit/6dd5ec5)) +- Fixed issues with decomp require ([0af1645](https://github.com/liabru/matter-js/commit/0af1645)) +- Fixed issues with render pixel ratio ([d577477](https://github.com/liabru/matter-js/commit/d577477)) + +### Changes ✲ + +See the release [compare page](https://github.com/liabru/matter-js/compare/0.14.2...0.15.0) and the [changelog](https://github.com/liabru/matter-js/blob/0.15.0/CHANGELOG.md) for a detailed list of all changes. + +### Comparison ⎄ + +Differences in behaviour, quality and performance against the previous release `0.14.2`. For more information see [comparison method](https://github.com/liabru/matter-js/pull/794). + +```ocaml +Output comparison of 41 examples against matter-js@0.14.2 build on last run + +Similarity 100% Performance +33.6% Overlap +0.00% + +airFriction · · avalanche · · ballPool · · bridge · · broadphase · · car · · +catapult · · chains · · circleStack · · cloth · · collisionFiltering · · +compositeManipulation · · compound · · compoundStack · · concave · · constraints · · +doublePendulum · · events · · friction · · gravity · · gyro · · +manipulation · · mixed · · newtonsCradle · · pyramid · · ragdoll · · +raycasting · · restitution · · rounded · · sensors · · sleeping · · +slingshot · · softBody · · sprites · · stack · · staticFriction · · +stress · · stress2 · · timescale · · views · · wreckingBall · · + +where · no change ● extrinsics changed ◆ intrinsics changed + +``` + +### Contributors ♥︎ + +Many thanks to the [contributors](https://github.com/liabru/matter-js/compare/0.14.2...0.15.0) of this release, [past contributors](https://github.com/liabru/matter-js/graphs/contributors) as well those involved in the [community](https://github.com/liabru/matter-js/issues) for your input and support. diff --git a/bower.json b/bower.json deleted file mode 100644 index 1782d51..0000000 --- a/bower.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "Matter", - "version": "0.14.2", - "homepage": "https://github.com/liabru/matter-js", - "authors": [ - "Liam Brummitt (http://brm.io/)" - ], - "description": "a 2D rigid body physics engine for the web", - "main": "build/matter.js", - "keywords": [ - "javascript", - "canvas", - "html5", - "physics", - "physics engine", - "game engine", - "rigid body physics" - ], - "license": "MIT", - "ignore": [ - "**/.*", - "node_modules", - "bower_components", - "test", - "tests" - ] -} diff --git a/build/matter.js b/build/matter.js index b36c3f5..2ffab81 100644 --- a/build/matter.js +++ b/build/matter.js @@ -1,10 +1,8 @@ -/** -* matter-js 0.14.2 by @liabru 2018-06-11 -* http://brm.io/matter-js/ -* License MIT -*/ - -/** +/*! + * matter-js 0.15.0 by @liabru 2020-12-26 + * http://brm.io/matter-js/ + * License MIT + * * The MIT License (MIT) * * Copyright (c) Liam Brummitt and contributors. @@ -27,8 +25,2282 @@ * 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((function webpackLoadOptionalExternalModule() { try { return require("poly-decomp"); } catch(e) {} }())); + else if(typeof define === 'function' && define.amd) + define("Matter", ["poly-decomp"], factory); + else if(typeof exports === 'object') + exports["Matter"] = factory((function webpackLoadOptionalExternalModule() { try { return require("poly-decomp"); } catch(e) {} }())); + else + root["Matter"] = factory(root["decomp"]); +})(this, function(__WEBPACK_EXTERNAL_MODULE__27__) { +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 = 24); +/******/ }) +/************************************************************************/ +/******/ ([ +/* 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._nextId = 0; + Common._seed = 0; + Common._nowStartTime = +(new Date()); + + /** + * 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 will be high-resolution including decimal places if available. + * @method now + * @return {number} the current timestamp + */ + 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(); + } + } + + 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 + * @property Common.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))); + } + }; + + /** + * 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 + )); + }; +})(); + + +/***/ }), +/* 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) { + var i; + if (scalar) { + for (i = 0; i < vertices.length; i++) { + vertices[i].x += vector.x * scalar; + vertices[i].y += vector.y * scalar; + } + } else { + for (i = 0; i < vertices.length; i++) { + vertices[i].x += vector.x; + vertices[i].y += vector.y; + } + } + + 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); + + for (var i = 0; i < vertices.length; i++) { + var vertice = vertices[i], + dx = vertice.x - point.x, + dy = vertice.y - point.y; + + vertice.x = point.x + (dx * cos - dy * sin); + vertice.y = point.y + (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) { + for (var i = 0; i < vertices.length; i++) { + var vertice = vertices[i], + nextVertice = vertices[(i + 1) % vertices.length]; + if ((point.x - vertice.x) * (nextVertice.y - vertice.y) + (point.y - vertice.y) * (vertice.x - nextVertice.x) > 0) { + return false; + } + } + + 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.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]); + } + } + } + } + }; + +})(); + + +/***/ }), +/* 5 */ +/***/ (function(module, exports, __webpack_require__) { + +/** +* The `Matter.Composite` module contains methods for creating and manipulating composite bodies. +* A composite body is a collection of `Matter.Body`, `Matter.Constraint` and other `Matter.Composite`, therefore composites form a tree structure. +* It is important to use the functions in this module to modify composites, rather than directly modifying their properties. +* Note that the `Matter.World` object is also a type of `Matter.Composite` and as such all composite methods here can also operate on a `Matter.World`. +* +* 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__(4); +var Common = __webpack_require__(0); +var Bounds = __webpack_require__(1); +var Body = __webpack_require__(6); + +(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: {} + }, 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). + * @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 (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 add function. Adds one or many body(s), constraint(s) or a composite(s) to the given composite. + * Triggers `beforeAdd` and `afterAdd` events on the `composite`. + * @method add + * @param {composite} composite + * @param {} object + * @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 + * @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); + Composite.setModified(compositeA, true, true, false); + } + + 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); + Composite.setModified(composite, true, true, false); + } + + 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) { + var bodies = [].concat(composite.bodies); + + for (var i = 0; i < composite.composites.length; i++) + bodies = bodies.concat(Composite.allBodies(composite.composites[i])); + + 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) { + var constraints = [].concat(composite.constraints); + + for (var i = 0; i < composite.composites.length; i++) + constraints = constraints.concat(Composite.allConstraints(composite.composites[i])); + + 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) { + var composites = [].concat(composite.composites); + + for (var i = 0; i < composite.composites.length; i++) + composites = composites.concat(Composite.allComposites(composite.composites[i])); + + 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(); + } + + Composite.setModified(composite, true, true, false); + + 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); + } + + Composite.setModified(composite, true, true, false); + + 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); + } + + Composite.setModified(composite, true, true, false); + + 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); + } + + Composite.setModified(composite, true, true, false); + + 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. + * Most `Matter.Composite` methods will automatically set this flag to `true` to inform the engine of changes to be handled. + * If you need to change it manually, you should use the `Composite.setModified` method. + * + * @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 {} + */ + +})(); + + +/***/ }), +/* 6 */ +/***/ (function(module, exports, __webpack_require__) { -(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.Matter = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i 0 && body.motion < Sleeping._motionSleepThreshold * timeFactor) { + body.sleepCounter += 1; - Body.setPosition(body, { - x: point.x + (dx * cos - dy * sin), - y: point.y + (dx * sin + dy * cos) - }); - - Body.rotate(body, rotation); - } - - Composite.setModified(composite, true, true, false); - - 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); - } - - Composite.setModified(composite, true, true, false); - - 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. - * Most `Matter.Composite` methods will automatically set this flag to `true` to inform the engine of changes to be handled. - * If you need to change it manually, you should use the `Composite.setModified` method. - * - * @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 {} - */ - -})(); - -},{"../core/Common":14,"../core/Events":16,"../geometry/Bounds":26,"./Body":1}],3:[function(_dereq_,module,exports){ -/** -* The `Matter.World` module contains methods for creating and manipulating the world composite. -* A `Matter.World` is a `Matter.Composite` body, which is a collection of `Matter.Body`, `Matter.Constraint` and other `Matter.Composite`. -* A `Matter.World` has a few additional properties including `gravity` and `bounds`. -* It is important to use the functions in the `Matter.Composite` module to modify the world composite, rather than directly modifying its properties. -* There are also a few methods here that alias those in `Matter.Composite` for easier readability. -* -* See the included usage [examples](https://github.com/liabru/matter-js/tree/master/examples). -* -* @class World -* @extends Composite -*/ - -var World = {}; - -module.exports = World; - -var Composite = _dereq_('./Composite'); -var Constraint = _dereq_('../constraint/Constraint'); -var Common = _dereq_('../core/Common'); - -(function() { - - /** - * Creates a new world composite. The options parameter is an object that specifies any properties you wish to override the defaults. - * See the properties section below for detailed information on what you can pass via the `options` object. - * @method create - * @constructor - * @param {} options - * @return {world} A new world - */ - World.create = function(options) { - var composite = Composite.create(); - - var defaults = { - label: 'World', - gravity: { - x: 0, - y: 1, - scale: 0.001 - }, - bounds: { - min: { x: -Infinity, y: -Infinity }, - max: { x: Infinity, y: Infinity } - } - }; - - return Common.extend(composite, defaults, options); - }; - - /* - * - * Properties Documentation - * - */ - - /** - * The gravity to apply on the world. - * - * @property gravity - * @type object - */ - - /** - * The gravity x component. - * - * @property gravity.x - * @type object - * @default 0 - */ - - /** - * The gravity y component. - * - * @property gravity.y - * @type object - * @default 1 - */ - - /** - * The gravity scale factor. - * - * @property gravity.scale - * @type object - * @default 0.001 - */ - - /** - * A `Bounds` object that defines the world bounds for collision detection. - * - * @property bounds - * @type bounds - * @default { min: { x: -Infinity, y: -Infinity }, max: { x: Infinity, y: Infinity } } - */ - - // World is a Composite body - // see src/module/Outro.js for these aliases: - - /** - * An alias for Composite.add - * @method add - * @param {world} world - * @param {} object - * @return {composite} The original world with the objects added - */ - - /** - * An alias for Composite.remove - * @method remove - * @param {world} world - * @param {} object - * @param {boolean} [deep=false] - * @return {composite} The original world with the objects removed - */ - - /** - * An alias for Composite.clear - * @method clear - * @param {world} world - * @param {boolean} keepStatic - */ - - /** - * An alias for Composite.addComposite - * @method addComposite - * @param {world} world - * @param {composite} composite - * @return {world} The original world with the objects from composite added - */ - - /** - * An alias for Composite.addBody - * @method addBody - * @param {world} world - * @param {body} body - * @return {world} The original world with the body added - */ - - /** - * An alias for Composite.addConstraint - * @method addConstraint - * @param {world} world - * @param {constraint} constraint - * @return {world} The original world with the constraint added - */ - -})(); - -},{"../constraint/Constraint":12,"../core/Common":14,"./Composite":2}],4:[function(_dereq_,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 { - id: Contact.id(vertex), - vertex: vertex, - normalImpulse: 0, - tangentImpulse: 0 - }; - }; - - /** - * Generates a contact id. - * @method id - * @param {vertex} vertex - * @return {string} Unique contactID - */ - Contact.id = function(vertex) { - return vertex.body.id + '_' + vertex.index; - }; - -})(); - -},{}],5:[function(_dereq_,module,exports){ -/** -* The `Matter.Detector` module contains methods for detecting collisions given a set of pairs. -* -* @class Detector -*/ - -// TODO: speculative contacts - -var Detector = {}; - -module.exports = Detector; - -var SAT = _dereq_('./SAT'); -var Pair = _dereq_('./Pair'); -var Bounds = _dereq_('../geometry/Bounds'); - -(function() { - - /** - * Finds all collisions given a list of pairs. - * @method collisions - * @param {pair[]} broadphasePairs - * @param {engine} engine - * @return {array} collisions - */ - Detector.collisions = function(broadphasePairs, engine) { - var collisions = [], - pairsTable = engine.pairs.table; - - - for (var i = 0; i < broadphasePairs.length; i++) { - var bodyA = broadphasePairs[i][0], - bodyB = broadphasePairs[i][1]; - - if ((bodyA.isStatic || bodyA.isSleeping) && (bodyB.isStatic || bodyB.isSleeping)) - continue; - - if (!Detector.canCollide(bodyA.collisionFilter, bodyB.collisionFilter)) - continue; - - - // mid phase - if (Bounds.overlaps(bodyA.bounds, bodyB.bounds)) { - for (var j = bodyA.parts.length > 1 ? 1 : 0; j < bodyA.parts.length; j++) { - var partA = bodyA.parts[j]; - - for (var k = bodyB.parts.length > 1 ? 1 : 0; k < bodyB.parts.length; k++) { - var partB = bodyB.parts[k]; - - if ((partA === bodyA && partB === bodyB) || Bounds.overlaps(partA.bounds, partB.bounds)) { - // find a previous collision we could reuse - var pairId = Pair.id(partA, partB), - pair = pairsTable[pairId], - previousCollision; - - if (pair && pair.isActive) { - previousCollision = pair.collision; - } else { - previousCollision = null; - } - - // narrow phase - var collision = SAT.collides(partA, partB, previousCollision); - - - if (collision.collided) { - 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; - }; - -})(); - -},{"../geometry/Bounds":26,"./Pair":7,"./SAT":11}],6:[function(_dereq_,module,exports){ -/** -* The `Matter.Grid` module contains methods for creating and manipulating collision broadphase grid structures. -* -* @class Grid -*/ - -var Grid = {}; - -module.exports = Grid; - -var Pair = _dereq_('./Pair'); -var Detector = _dereq_('./Detector'); -var Common = _dereq_('../core/Common'); - -(function() { - - /** - * Creates a new grid. - * @method create - * @param {} options - * @return {grid} A new grid - */ - Grid.create = function(options) { - var defaults = { - controller: Grid, - detector: Detector.collisions, - 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. - * @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; - - // don't update out of world bodies - if (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); - }; - - /** - * Clears the grid. - * @method clear - * @param {grid} grid - */ - Grid.clear = function(grid) { - grid.buckets = {}; - grid.pairs = {}; - grid.pairsList = []; - }; - - /** - * Finds the union of two regions. - * @method _regionUnion - * @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 - * @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 - * @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 - * @private - * @param {} column - * @param {} row - * @return {string} bucket id - */ - Grid._getBucketId = function(column, row) { - return 'C' + column + 'R' + row; - }; - - /** - * Creates a bucket. - * @method _createBucket - * @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 - * @private - * @param {} grid - * @param {} bucket - * @param {} body - */ - Grid._bucketAddBody = function(grid, bucket, body) { - // add new pairs - for (var i = 0; i < bucket.length; 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 pairId = Pair.id(body, bodyB), - pair = grid.pairs[pairId]; - - if (pair) { - pair[2] += 1; - } else { - grid.pairs[pairId] = [body, bodyB, 1]; - } - } - - // add to bodies (after pairs, otherwise pairs with self) - bucket.push(body); - }; - - /** - * Removes a body from a bucket. - * @method _bucketRemoveBody - * @private - * @param {} grid - * @param {} bucket - * @param {} body - */ - Grid._bucketRemoveBody = function(grid, bucket, body) { - // remove from bucket - bucket.splice(Common.indexOf(bucket, body), 1); - - // update pair counts - for (var i = 0; i < bucket.length; i++) { - // keep track of the number of buckets the pair exists in - // important for _createActivePairsList to work - var bodyB = bucket[i], - pairId = Pair.id(body, bodyB), - pair = grid.pairs[pairId]; - - if (pair) - pair[2] -= 1; - } - }; - - /** - * Generates a list of the active pairs in the grid. - * @method _createActivePairsList - * @private - * @param {} grid - * @return [] pairs - */ - Grid._createActivePairsList = function(grid) { - var pairKeys, - pair, - pairs = []; - - // grid.pairs is used as a hashmap - pairKeys = Common.keys(grid.pairs); - - // iterate over grid.pairs - for (var k = 0; k < pairKeys.length; k++) { - pair = grid.pairs[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 grid.pairs[pairKeys[k]]; - } - } - - return pairs; - }; - -})(); - -},{"../core/Common":14,"./Detector":5,"./Pair":7}],7:[function(_dereq_,module,exports){ -/** -* The `Matter.Pair` module contains methods for creating and manipulating collision pairs. -* -* @class Pair -*/ - -var Pair = {}; - -module.exports = Pair; - -var Contact = _dereq_('./Contact'); - -(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, - parentA = collision.parentA, - parentB = collision.parentB; - - var pair = { - id: Pair.id(bodyA, bodyB), - bodyA: bodyA, - bodyB: bodyB, - contacts: {}, - activeContacts: [], - separation: 0, - isActive: true, - isSensor: bodyA.isSensor || bodyB.isSensor, - timeCreated: timestamp, - timeUpdated: timestamp, - inverseMass: parentA.inverseMass + parentB.inverseMass, - friction: Math.min(parentA.friction, parentB.friction), - frictionStatic: Math.max(parentA.frictionStatic, parentB.frictionStatic), - restitution: Math.max(parentA.restitution, parentB.restitution), - slop: Math.max(parentA.slop, parentB.slop) - }; - - 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; - - pair.collision = collision; - pair.inverseMass = parentA.inverseMass + parentB.inverseMass; - pair.friction = Math.min(parentA.friction, parentB.friction); - pair.frictionStatic = Math.max(parentA.frictionStatic, parentB.frictionStatic); - pair.restitution = Math.max(parentA.restitution, parentB.restitution); - pair.slop = Math.max(parentA.slop, parentB.slop); - activeContacts.length = 0; - - if (collision.collided) { - for (var i = 0; i < supports.length; i++) { - var support = supports[i], - contactId = Contact.id(support), - contact = contacts[contactId]; - - if (contact) { - activeContacts.push(contact); - } else { - activeContacts.push(contacts[contactId] = Contact.create(support)); - } - } - - pair.separation = collision.depth; - Pair.setActive(pair, true, timestamp); - } else { - if (pair.isActive === true) - Pair.setActive(pair, false, timestamp); - } - }; - - /** - * 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; - } - }; - -})(); - -},{"./Contact":4}],8:[function(_dereq_,module,exports){ -/** -* The `Matter.Pairs` module contains methods for creating and manipulating collision pair sets. -* -* @class Pairs -*/ - -var Pairs = {}; - -module.exports = Pairs; - -var Pair = _dereq_('./Pair'); -var Common = _dereq_('../core/Common'); - -(function() { - - Pairs._pairMaxIdleLife = 1000; - - /** - * 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, - pairsTable = pairs.table, - collisionStart = pairs.collisionStart, - collisionEnd = pairs.collisionEnd, - collisionActive = pairs.collisionActive, - activePairIds = [], - collision, - pairId, - pair, - i; - - // clear collision state arrays, but maintain old reference - collisionStart.length = 0; - collisionEnd.length = 0; - collisionActive.length = 0; - - for (i = 0; i < collisions.length; i++) { - collision = collisions[i]; - - if (collision.collided) { - pairId = Pair.id(collision.bodyA, collision.bodyB); - activePairIds.push(pairId); - - pair = pairsTable[pairId]; - - 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); - } else { - // pair did not exist, create a new pair - pair = Pair.create(collision, timestamp); - pairsTable[pairId] = pair; - - // push the new pair - collisionStart.push(pair); - pairsList.push(pair); - } - } - } - - // deactivate previously active pairs that are now inactive - for (i = 0; i < pairsList.length; i++) { - pair = pairsList[i]; - if (pair.isActive && Common.indexOf(activePairIds, pair.id) === -1) { - Pair.setActive(pair, false, timestamp); - collisionEnd.push(pair); + if (body.sleepCounter >= body.sleepThreshold) + Sleeping.set(body, true); + } else if (body.sleepCounter > 0) { + body.sleepCounter -= 1; } } }; - - /** - * Finds and removes pairs that have been inactive for a set amount of time. - * @method removeOld - * @param {object} pairs - * @param {number} timestamp - */ - Pairs.removeOld = function(pairs, timestamp) { - var pairsList = pairs.list, - pairsTable = pairs.table, - indexesToRemove = [], - pair, - collision, - pairIndex, - i; - - for (i = 0; i < pairsList.length; i++) { - pair = pairsList[i]; - collision = pair.collision; - - // never remove sleeping pairs - if (collision.bodyA.isSleeping || collision.bodyB.isSleeping) { - pair.timeUpdated = timestamp; - continue; - } - - // if pair is inactive for too long, mark it to be removed - if (timestamp - pair.timeUpdated > Pairs._pairMaxIdleLife) { - indexesToRemove.push(i); - } - } - - // remove marked pairs - for (i = 0; i < indexesToRemove.length; i++) { - pairIndex = indexesToRemove[i] - i; - pair = pairsList[pairIndex]; - delete pairsTable[pair.id]; - pairsList.splice(pairIndex, 1); - } - }; /** - * 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; - }; - -})(); - -},{"../core/Common":14,"./Pair":7}],9:[function(_dereq_,module,exports){ -/** -* 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 = _dereq_('../geometry/Vector'); -var SAT = _dereq_('./SAT'); -var Bounds = _dereq_('../geometry/Bounds'); -var Bodies = _dereq_('../factory/Bodies'); -var Vertices = _dereq_('../geometry/Vertices'); - -(function() { - - /** - * Returns a list of collisions between `body` and `bodies`. - * @method collides - * @param {body} body - * @param {body[]} bodies - * @return {object[]} Collisions - */ - Query.collides = function(body, bodies) { - var collisions = []; - - for (var i = 0; i < bodies.length; i++) { - var bodyA = bodies[i]; - - if (Bounds.overlaps(bodyA.bounds, body.bounds)) { - for (var j = bodyA.parts.length === 1 ? 0 : 1; j < bodyA.parts.length; j++) { - var part = bodyA.parts[j]; - - if (Bounds.overlaps(part.bounds, body.bounds)) { - var collision = SAT.collides(part, body); - - if (collision.collided) { - 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 {object[]} 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; - }; - -})(); - -},{"../factory/Bodies":23,"../geometry/Bounds":26,"../geometry/Vector":28,"../geometry/Vertices":29,"./SAT":11}],10:[function(_dereq_,module,exports){ -/** -* The `Matter.Resolver` module contains methods for resolving collision pairs. -* -* @class Resolver -*/ - -var Resolver = {}; - -module.exports = Resolver; - -var Vertices = _dereq_('../geometry/Vertices'); -var Vector = _dereq_('../geometry/Vector'); -var Common = _dereq_('../core/Common'); -var Bounds = _dereq_('../geometry/Bounds'); - -(function() { - - Resolver._restingThresh = 4; - Resolver._restingThreshTangent = 6; - Resolver._positionDampen = 0.9; - Resolver._positionWarming = 0.8; - Resolver._frictionNormalMultiplier = 5; - - /** - * Prepare pairs for position solving. - * @method preSolvePosition - * @param {pair[]} pairs - */ - Resolver.preSolvePosition = function(pairs) { - var i, - pair, - activeCount; - - // find total contacts on each body - for (i = 0; i < pairs.length; 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 + * Given a set of colliding pairs, wakes the sleeping bodies involved. + * @method afterCollisions * @param {pair[]} pairs * @param {number} timeScale */ - Resolver.solvePosition = function(pairs, timeScale) { - var i, - pair, - collision, - bodyA, - bodyB, - normal, - bodyBtoA, - contactShare, - positionImpulse, - contactCount = {}, - tempA = Vector._temp[0], - tempB = Vector._temp[1], - tempC = Vector._temp[2], - tempD = Vector._temp[3]; + Sleeping.afterCollisions = function(pairs, timeScale) { + var timeFactor = timeScale * timeScale * timeScale; - // find impulses required to resolve penetration - for (i = 0; i < pairs.length; 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 - bodyBtoA = Vector.sub(Vector.add(bodyB.positionImpulse, bodyB.position, tempA), - Vector.add(bodyA.positionImpulse, - Vector.sub(bodyB.position, collision.penetration, tempB), tempC), tempD); - - pair.separation = Vector.dot(normal, bodyBtoA); - } - - for (i = 0; i < pairs.length; 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) * timeScale; - - if (bodyA.isStatic || bodyB.isStatic) - positionImpulse *= 2; - - if (!(bodyA.isStatic || bodyA.isSleeping)) { - contactShare = Resolver._positionDampen / bodyA.totalContacts; - bodyA.positionImpulse.x += normal.x * positionImpulse * contactShare; - bodyA.positionImpulse.y += normal.y * positionImpulse * contactShare; - } - - if (!(bodyB.isStatic || bodyB.isSleeping)) { - contactShare = Resolver._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) { - for (var i = 0; i < bodies.length; i++) { - var body = bodies[i]; - - // reset contact count - body.totalContacts = 0; - - if (body.positionImpulse.x !== 0 || body.positionImpulse.y !== 0) { - // update body geometry - for (var j = 0; j < body.parts.length; j++) { - var part = body.parts[j]; - Vertices.translate(part.vertices, body.positionImpulse); - Bounds.update(part.bounds, part.vertices, body.velocity); - part.position.x += body.positionImpulse.x; - part.position.y += body.positionImpulse.y; - } - - // move the body without changing velocity - body.positionPrev.x += body.positionImpulse.x; - body.positionPrev.y += body.positionImpulse.y; - - if (Vector.dot(body.positionImpulse, body.velocity) < 0) { - // reset cached impulse if the body has velocity along it - body.positionImpulse.x = 0; - body.positionImpulse.y = 0; - } else { - // warm the next iteration - body.positionImpulse.x *= Resolver._positionWarming; - body.positionImpulse.y *= Resolver._positionWarming; - } - } - } - }; - - /** - * Prepare pairs for velocity solving. - * @method preSolveVelocity - * @param {pair[]} pairs - */ - Resolver.preSolveVelocity = function(pairs) { - var i, - j, - pair, - contacts, - collision, - bodyA, - bodyB, - normal, - tangent, - contact, - contactVertex, - normalImpulse, - tangentImpulse, - offset, - impulse = Vector._temp[0], - tempA = Vector._temp[1]; - - for (i = 0; i < pairs.length; i++) { - pair = pairs[i]; - - if (!pair.isActive || pair.isSensor) - continue; - - contacts = pair.activeContacts; - collision = pair.collision; - bodyA = collision.parentA; - bodyB = collision.parentB; - normal = collision.normal; - tangent = collision.tangent; - - // resolve each contact - for (j = 0; j < contacts.length; j++) { - contact = contacts[j]; - contactVertex = contact.vertex; - normalImpulse = contact.normalImpulse; - tangentImpulse = contact.tangentImpulse; - - if (normalImpulse !== 0 || tangentImpulse !== 0) { - // total impulse from contact - impulse.x = (normal.x * normalImpulse) + (tangent.x * tangentImpulse); - impulse.y = (normal.y * normalImpulse) + (tangent.y * tangentImpulse); - - // apply impulse from contact - if (!(bodyA.isStatic || bodyA.isSleeping)) { - offset = Vector.sub(contactVertex, bodyA.position, tempA); - bodyA.positionPrev.x += impulse.x * bodyA.inverseMass; - bodyA.positionPrev.y += impulse.y * bodyA.inverseMass; - bodyA.anglePrev += Vector.cross(offset, impulse) * bodyA.inverseInertia; - } - - if (!(bodyB.isStatic || bodyB.isSleeping)) { - offset = Vector.sub(contactVertex, bodyB.position, tempA); - bodyB.positionPrev.x -= impulse.x * bodyB.inverseMass; - bodyB.positionPrev.y -= impulse.y * bodyB.inverseMass; - bodyB.anglePrev -= Vector.cross(offset, impulse) * bodyB.inverseInertia; - } - } - } - } - }; - - /** - * Find a solution for pair velocities. - * @method solveVelocity - * @param {pair[]} pairs - * @param {number} timeScale - */ - Resolver.solveVelocity = function(pairs, timeScale) { - var timeScaleSquared = timeScale * timeScale, - impulse = Vector._temp[0], - tempA = Vector._temp[1], - tempB = Vector._temp[2], - tempC = Vector._temp[3], - tempD = Vector._temp[4], - tempE = Vector._temp[5]; - + // wake up bodies involved in collisions for (var i = 0; i < pairs.length; i++) { var pair = pairs[i]; - if (!pair.isActive || pair.isSensor) + // don't wake inactive pairs + if (!pair.isActive) continue; - + var collision = pair.collision, - bodyA = collision.parentA, - bodyB = collision.parentB, - normal = collision.normal, - tangent = collision.tangent, - contacts = pair.activeContacts, - contactShare = 1 / contacts.length; + 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; - // update body velocities - bodyA.velocity.x = bodyA.position.x - bodyA.positionPrev.x; - bodyA.velocity.y = bodyA.position.y - bodyA.positionPrev.y; - bodyB.velocity.x = bodyB.position.x - bodyB.positionPrev.x; - bodyB.velocity.y = bodyB.position.y - bodyB.positionPrev.y; - bodyA.angularVelocity = bodyA.angle - bodyA.anglePrev; - bodyB.angularVelocity = bodyB.angle - bodyB.anglePrev; - - // resolve each contact - for (var j = 0; j < contacts.length; j++) { - var contact = contacts[j], - contactVertex = contact.vertex, - offsetA = Vector.sub(contactVertex, bodyA.position, tempA), - offsetB = Vector.sub(contactVertex, bodyB.position, tempB), - velocityPointA = Vector.add(bodyA.velocity, Vector.mult(Vector.perp(offsetA), bodyA.angularVelocity), tempC), - velocityPointB = Vector.add(bodyB.velocity, Vector.mult(Vector.perp(offsetB), bodyB.angularVelocity), tempD), - relativeVelocity = Vector.sub(velocityPointA, velocityPointB, tempE), - normalVelocity = Vector.dot(normal, relativeVelocity); - - var tangentVelocity = Vector.dot(tangent, relativeVelocity), - tangentSpeed = Math.abs(tangentVelocity), - tangentVelocityDirection = Common.sign(tangentVelocity); - - // raw impulses - var normalImpulse = (1 + pair.restitution) * normalVelocity, - normalForce = Common.clamp(pair.separation + normalVelocity, 0, 1) * Resolver._frictionNormalMultiplier; - - // coulomb friction - var tangentImpulse = tangentVelocity, - maxFriction = Infinity; - - if (tangentSpeed > pair.friction * pair.frictionStatic * normalForce * timeScaleSquared) { - maxFriction = tangentSpeed; - tangentImpulse = Common.clamp( - pair.friction * tangentVelocityDirection * timeScaleSquared, - -maxFriction, maxFriction - ); + if (!sleepingBody.isStatic && movingBody.motion > Sleeping._motionWakeThreshold * timeFactor) { + 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; - // modify impulses accounting for mass, inertia and offset - var oAcN = Vector.cross(offsetA, normal), - oBcN = Vector.cross(offsetB, normal), - share = contactShare / (bodyA.inverseMass + bodyB.inverseMass + bodyA.inverseInertia * oAcN * oAcN + bodyB.inverseInertia * oBcN * oBcN); + if (isSleeping) { + body.isSleeping = true; + body.sleepCounter = body.sleepThreshold; - normalImpulse *= share; - tangentImpulse *= share; + body.positionImpulse.x = 0; + body.positionImpulse.y = 0; - // handle high velocity and resting collisions separately - if (normalVelocity < 0 && normalVelocity * normalVelocity > Resolver._restingThresh * timeScaleSquared) { - // 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 = Math.min(contact.normalImpulse + normalImpulse, 0); - normalImpulse = contact.normalImpulse - contactNormalImpulse; - } + body.positionPrev.x = body.position.x; + body.positionPrev.y = body.position.y; - // handle high velocity and resting collisions separately - if (tangentVelocity * tangentVelocity > Resolver._restingThreshTangent * timeScaleSquared) { - // 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 = Common.clamp(contact.tangentImpulse + tangentImpulse, -maxFriction, maxFriction); - tangentImpulse = contact.tangentImpulse - contactTangentImpulse; - } + body.anglePrev = body.angle; + body.speed = 0; + body.angularSpeed = 0; + body.motion = 0; - // total impulse from contact - impulse.x = (normal.x * normalImpulse) + (tangent.x * tangentImpulse); - impulse.y = (normal.y * normalImpulse) + (tangent.y * tangentImpulse); - - // apply impulse from contact - if (!(bodyA.isStatic || bodyA.isSleeping)) { - bodyA.positionPrev.x += impulse.x * bodyA.inverseMass; - bodyA.positionPrev.y += impulse.y * bodyA.inverseMass; - bodyA.anglePrev += Vector.cross(offsetA, impulse) * bodyA.inverseInertia; - } + if (!wasSleeping) { + Events.trigger(body, 'sleepStart'); + } + } else { + body.isSleeping = false; + body.sleepCounter = 0; - if (!(bodyB.isStatic || bodyB.isSleeping)) { - bodyB.positionPrev.x -= impulse.x * bodyB.inverseMass; - bodyB.positionPrev.y -= impulse.y * bodyB.inverseMass; - bodyB.anglePrev -= Vector.cross(offsetB, impulse) * bodyB.inverseInertia; - } + if (wasSleeping) { + Events.trigger(body, 'sleepEnd'); } } }; })(); -},{"../core/Common":14,"../geometry/Bounds":26,"../geometry/Vector":28,"../geometry/Vertices":29}],11:[function(_dereq_,module,exports){ -/** -* The `Matter.SAT` module contains methods for detecting collisions using the Separating Axis Theorem. -* -* @class SAT -*/ -// TODO: true circles and curves +/***/ }), +/* 8 */ +/***/ (function(module, exports, __webpack_require__) { -var SAT = {}; - -module.exports = SAT; - -var Vertices = _dereq_('../geometry/Vertices'); -var Vector = _dereq_('../geometry/Vector'); - -(function() { - - /** - * Detect collision between two bodies using the Separating Axis Theorem. - * @method collides - * @param {body} bodyA - * @param {body} bodyB - * @param {collision} previousCollision - * @return {collision} collision - */ - SAT.collides = function(bodyA, bodyB, previousCollision) { - var overlapAB, - overlapBA, - minOverlap, - collision, - canReusePrevCol = false; - - if (previousCollision) { - // estimate total motion - var parentA = bodyA.parent, - parentB = bodyB.parent, - motion = parentA.speed * parentA.speed + parentA.angularSpeed * parentA.angularSpeed - + parentB.speed * parentB.speed + parentB.angularSpeed * parentB.angularSpeed; - - // we may be able to (partially) reuse collision result - // but only safe if collision was resting - canReusePrevCol = previousCollision && previousCollision.collided && motion < 0.2; - - // reuse collision object - collision = previousCollision; - } else { - collision = { collided: false, bodyA: bodyA, bodyB: bodyB }; - } - - if (previousCollision && canReusePrevCol) { - // if we can reuse the collision result - // we only need to test the previously found axis - var axisBodyA = collision.axisBody, - axisBodyB = axisBodyA === bodyA ? bodyB : bodyA, - axes = [axisBodyA.axes[previousCollision.axisNumber]]; - - minOverlap = SAT._overlapAxes(axisBodyA.vertices, axisBodyB.vertices, axes); - collision.reused = true; - - if (minOverlap.overlap <= 0) { - collision.collided = false; - return collision; - } - } else { - // if we can't reuse a result, perform a full SAT test - - overlapAB = SAT._overlapAxes(bodyA.vertices, bodyB.vertices, bodyA.axes); - - if (overlapAB.overlap <= 0) { - collision.collided = false; - return collision; - } - - overlapBA = SAT._overlapAxes(bodyB.vertices, bodyA.vertices, bodyB.axes); - - if (overlapBA.overlap <= 0) { - collision.collided = false; - return collision; - } - - if (overlapAB.overlap < overlapBA.overlap) { - minOverlap = overlapAB; - collision.axisBody = bodyA; - } else { - minOverlap = overlapBA; - collision.axisBody = bodyB; - } - - // important for reuse later - collision.axisNumber = minOverlap.axisNumber; - } - - collision.bodyA = bodyA.id < bodyB.id ? bodyA : bodyB; - collision.bodyB = bodyA.id < bodyB.id ? bodyB : bodyA; - collision.collided = true; - collision.depth = minOverlap.overlap; - collision.parentA = collision.bodyA.parent; - collision.parentB = collision.bodyB.parent; - - bodyA = collision.bodyA; - bodyB = collision.bodyB; - - // ensure normal is facing away from bodyA - if (Vector.dot(minOverlap.axis, Vector.sub(bodyB.position, bodyA.position)) < 0) { - collision.normal = { - x: minOverlap.axis.x, - y: minOverlap.axis.y - }; - } else { - collision.normal = { - x: -minOverlap.axis.x, - y: -minOverlap.axis.y - }; - } - - collision.tangent = Vector.perp(collision.normal); - - collision.penetration = collision.penetration || {}; - collision.penetration.x = collision.normal.x * collision.depth; - collision.penetration.y = collision.normal.y * collision.depth; - - // find support points, there is always either exactly one or two - var verticesB = SAT._findSupports(bodyA, bodyB, collision.normal), - supports = []; - - // find the supports from bodyB that are inside bodyA - if (Vertices.contains(bodyA.vertices, verticesB[0])) - supports.push(verticesB[0]); - - if (Vertices.contains(bodyA.vertices, verticesB[1])) - supports.push(verticesB[1]); - - // find the supports from bodyA that are inside bodyB - if (supports.length < 2) { - var verticesA = SAT._findSupports(bodyB, bodyA, Vector.neg(collision.normal)); - - if (Vertices.contains(bodyB.vertices, verticesA[0])) - supports.push(verticesA[0]); - - if (supports.length < 2 && Vertices.contains(bodyB.vertices, verticesA[1])) - supports.push(verticesA[1]); - } - - // account for the edge case of overlapping but no vertex containment - if (supports.length < 1) - supports = [verticesB[0]]; - - collision.supports = supports; - - return collision; - }; - - /** - * Find the overlap between two sets of vertices. - * @method _overlapAxes - * @private - * @param {} verticesA - * @param {} verticesB - * @param {} axes - * @return result - */ - SAT._overlapAxes = function(verticesA, verticesB, axes) { - var projectionA = Vector._temp[0], - projectionB = Vector._temp[1], - result = { overlap: Number.MAX_VALUE }, - overlap, - axis; - - for (var i = 0; i < axes.length; i++) { - axis = axes[i]; - - SAT._projectToAxis(projectionA, verticesA, axis); - SAT._projectToAxis(projectionB, verticesB, axis); - - overlap = Math.min(projectionA.max - projectionB.min, projectionB.max - projectionA.min); - - if (overlap <= 0) { - result.overlap = overlap; - return result; - } - - if (overlap < result.overlap) { - result.overlap = overlap; - result.axis = axis; - result.axisNumber = i; - } - } - - return result; - }; - - /** - * Projects vertices on an axis and returns an interval. - * @method _projectToAxis - * @private - * @param {} projection - * @param {} vertices - * @param {} axis - */ - SAT._projectToAxis = function(projection, vertices, axis) { - var min = Vector.dot(vertices[0], axis), - max = min; - - for (var i = 1; i < vertices.length; i += 1) { - var dot = Vector.dot(vertices[i], axis); - - 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 {} bodyA - * @param {} bodyB - * @param {} normal - * @return [vector] - */ - SAT._findSupports = function(bodyA, bodyB, normal) { - var nearestDistance = Number.MAX_VALUE, - vertexToBody = Vector._temp[0], - vertices = bodyB.vertices, - bodyAPosition = bodyA.position, - distance, - vertex, - vertexA, - vertexB; - - // find closest vertex on bodyB - for (var i = 0; i < vertices.length; i++) { - vertex = vertices[i]; - vertexToBody.x = vertex.x - bodyAPosition.x; - vertexToBody.y = vertex.y - bodyAPosition.y; - distance = -Vector.dot(normal, vertexToBody); - - if (distance < nearestDistance) { - nearestDistance = distance; - vertexA = vertex; - } - } - - // find next closest vertex using the two connected to it - var prevIndex = vertexA.index - 1 >= 0 ? vertexA.index - 1 : vertices.length - 1; - vertex = vertices[prevIndex]; - vertexToBody.x = vertex.x - bodyAPosition.x; - vertexToBody.y = vertex.y - bodyAPosition.y; - nearestDistance = -Vector.dot(normal, vertexToBody); - vertexB = vertex; - - var nextIndex = (vertexA.index + 1) % vertices.length; - vertex = vertices[nextIndex]; - vertexToBody.x = vertex.x - bodyAPosition.x; - vertexToBody.y = vertex.y - bodyAPosition.y; - distance = -Vector.dot(normal, vertexToBody); - if (distance < nearestDistance) { - vertexB = vertex; - } - - return [vertexA, vertexB]; - }; - -})(); - -},{"../geometry/Vector":28,"../geometry/Vertices":29}],12:[function(_dereq_,module,exports){ /** * 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). @@ -3560,12 +3691,12 @@ var Constraint = {}; module.exports = Constraint; -var Vertices = _dereq_('../geometry/Vertices'); -var Vector = _dereq_('../geometry/Vector'); -var Sleeping = _dereq_('../core/Sleeping'); -var Bounds = _dereq_('../geometry/Bounds'); -var Axes = _dereq_('../geometry/Axes'); -var Common = _dereq_('../core/Common'); +var Vertices = __webpack_require__(3); +var Vector = __webpack_require__(2); +var Sleeping = __webpack_require__(7); +var Bounds = __webpack_require__(1); +var Axes = __webpack_require__(15); +var Common = __webpack_require__(0); (function() { @@ -3848,6 +3979,32 @@ var Common = _dereq_('../core/Common'); } }; + /** + * 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.x, + y: (constraint.bodyA ? constraint.bodyA.position.y : 0) + constraint.pointA.y + }; + }; + + /** + * 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.x, + y: (constraint.bodyB ? constraint.bodyB.position.y : 0) + constraint.pointB.y + }; + }; + /* * * Properties Documentation @@ -4000,4360 +4157,144 @@ var Common = _dereq_('../core/Common'); })(); -},{"../core/Common":14,"../core/Sleeping":22,"../geometry/Axes":25,"../geometry/Bounds":26,"../geometry/Vector":28,"../geometry/Vertices":29}],13:[function(_dereq_,module,exports){ + +/***/ }), +/* 9 */ +/***/ (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. +* The `Matter.Pair` module contains methods for creating and manipulating collision pairs. * -* See the included usage [examples](https://github.com/liabru/matter-js/tree/master/examples). -* -* @class MouseConstraint +* @class Pair */ -var MouseConstraint = {}; +var Pair = {}; -module.exports = MouseConstraint; +module.exports = Pair; -var Vertices = _dereq_('../geometry/Vertices'); -var Sleeping = _dereq_('../core/Sleeping'); -var Mouse = _dereq_('../core/Mouse'); -var Events = _dereq_('../core/Events'); -var Detector = _dereq_('../collision/Detector'); -var Constraint = _dereq_('./Constraint'); -var Composite = _dereq_('../body/Composite'); -var Common = _dereq_('../core/Common'); -var Bounds = _dereq_('../geometry/Bounds'); +var Contact = __webpack_require__(18); (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. + * Creates a pair. * @method create - * @param {engine} engine - * @param {} options - * @return {MouseConstraint} A new MouseConstraint + * @param {collision} collision + * @param {number} timestamp + * @return {pair} A new pair */ - MouseConstraint.create = function(engine, options) { - var mouse = (engine ? engine.mouse : null) || (options ? options.mouse : null); + Pair.create = function(collision, timestamp) { + var bodyA = collision.bodyA, + bodyB = collision.bodyB, + parentA = collision.parentA, + parentB = collision.parentB; - 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 pair = { + id: Pair.id(bodyA, bodyB), + bodyA: bodyA, + bodyB: bodyB, + contacts: {}, + activeContacts: [], + separation: 0, + isActive: true, + confirmedActive: true, + isSensor: bodyA.isSensor || bodyB.isSensor, + timeCreated: timestamp, + timeUpdated: timestamp, + inverseMass: parentA.inverseMass + parentB.inverseMass, + friction: Math.min(parentA.friction, parentB.friction), + frictionStatic: Math.max(parentA.frictionStatic, parentB.frictionStatic), + restitution: Math.max(parentA.restitution, parentB.restitution), + slop: Math.max(parentA.slop, parentB.slop) }; - var mouseConstraint = Common.extend(defaults, options); + Pair.update(pair, collision, timestamp); - Events.on(engine, 'beforeUpdate', function() { - var allBodies = Composite.allBodies(engine.world); - MouseConstraint.update(mouseConstraint, allBodies); - MouseConstraint._triggerEvents(mouseConstraint); - }); - - return mouseConstraint; + return pair; }; /** - * Updates the given mouse constraint. - * @private + * Updates a pair given a collision. * @method update - * @param {MouseConstraint} mouseConstraint - * @param {body[]} bodies + * @param {pair} pair + * @param {collision} collision + * @param {number} timestamp */ - 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 - */ - -})(); - -},{"../body/Composite":2,"../collision/Detector":5,"../core/Common":14,"../core/Events":16,"../core/Mouse":19,"../core/Sleeping":22,"../geometry/Bounds":26,"../geometry/Vertices":29,"./Constraint":12}],14:[function(_dereq_,module,exports){ -(function (global){ -/** -* The `Matter.Common` module contains utility functions that are common to all modules. -* -* @class Common -*/ - -var Common = {}; - -module.exports = Common; - -(function() { - - Common._nextId = 0; - Common._seed = 0; - Common._nowStartTime = +(new Date()); - - /** - * 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]; - } - } - } - } + Pair.update = function(pair, collision, timestamp) { + var contacts = pair.contacts, + supports = collision.supports, + activeContacts = pair.activeContacts, + parentA = collision.parentA, + parentB = collision.parentB; - 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 = []; + pair.collision = collision; + pair.inverseMass = parentA.inverseMass + parentB.inverseMass; + pair.friction = Math.min(parentA.friction, parentB.friction); + pair.frictionStatic = Math.max(parentA.frictionStatic, parentB.frictionStatic); + pair.restitution = Math.max(parentA.restitution, parentB.restitution); + pair.slop = Math.max(parentA.slop, parentB.slop); + activeContacts.length = 0; - 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 will be high-resolution including decimal places if available. - * @method now - * @return {number} the current timestamp - */ - Common.now = function() { - if (window.performance) { - if (window.performance.now) { - return window.performance.now(); - } else if (window.performance.webkitNow) { - return window.performance.webkitNow(); - } - } - - 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 - * @property Common.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))); - } - }; - - /** - * 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 - )); - }; - - /** - * Used to require external libraries outside of the bundle. - * It first looks for the `globalName` on the environment's global namespace. - * If the global is not found, it will fall back to using the standard `require` using the `moduleName`. - * @private - * @method _requireGlobal - * @param {string} globalName The global module name - * @param {string} moduleName The fallback CommonJS module name - * @return {} The loaded module - */ - Common._requireGlobal = function(globalName, moduleName) { - var obj = (typeof window !== 'undefined' ? window[globalName] : typeof global !== 'undefined' ? global[globalName] : null); - return obj || _dereq_(moduleName); - }; -})(); - -}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{}],15:[function(_dereq_,module,exports){ -/** -* The `Matter.Engine` module contains methods for creating and manipulating engines. -* An engine is a controller that manages updating the simulation of the world. -* See `Matter.Runner` for an optional game loop utility. -* -* See the included usage [examples](https://github.com/liabru/matter-js/tree/master/examples). -* -* @class Engine -*/ - -var Engine = {}; - -module.exports = Engine; - -var World = _dereq_('../body/World'); -var Sleeping = _dereq_('./Sleeping'); -var Resolver = _dereq_('../collision/Resolver'); -var Render = _dereq_('../render/Render'); -var Pairs = _dereq_('../collision/Pairs'); -var Metrics = _dereq_('./Metrics'); -var Grid = _dereq_('../collision/Grid'); -var Events = _dereq_('./Events'); -var Composite = _dereq_('../body/Composite'); -var Constraint = _dereq_('../constraint/Constraint'); -var Common = _dereq_('./Common'); -var Body = _dereq_('../body/Body'); - -(function() { - - /** - * Creates a new engine. The options parameter is an object that specifies any properties you wish to override the defaults. - * All properties have default values, and many are pre-calculated automatically based on other properties. - * See the properties section below for detailed information on what you can pass via the `options` object. - * @method create - * @param {object} [options] - * @return {engine} engine - */ - Engine.create = function(element, options) { - // options may be passed as the first (and only) argument - options = Common.isElement(element) ? options : element; - element = Common.isElement(element) ? element : null; - options = options || {}; - - if (element || options.render) { - Common.warn('Engine.create: engine.render is deprecated (see docs)'); - } - - var defaults = { - positionIterations: 6, - velocityIterations: 4, - constraintIterations: 2, - enableSleeping: false, - events: [], - plugin: {}, - timing: { - timestamp: 0, - timeScale: 1 - }, - broadphase: { - controller: Grid - } - }; - - var engine = Common.extend(defaults, options); - - // @deprecated - if (element || engine.render) { - var renderDefaults = { - element: element, - controller: Render - }; - - engine.render = Common.extend(renderDefaults, engine.render); - } - - // @deprecated - if (engine.render && engine.render.controller) { - engine.render = engine.render.controller.create(engine.render); - } - - // @deprecated - if (engine.render) { - engine.render.engine = engine; - } - - engine.world = options.world || World.create(engine.world); - engine.pairs = Pairs.create(); - engine.broadphase = engine.broadphase.controller.create(engine.broadphase); - engine.metrics = engine.metrics || { extended: false }; - - - return engine; - }; - - /** - * Moves the simulation forward in time by `delta` ms. - * The `correction` argument is an optional `Number` that specifies the time correction factor to apply to the update. - * This can help improve the accuracy of the simulation in cases where `delta` is changing between updates. - * The value of `correction` is defined as `delta / lastDelta`, i.e. the percentage change of `delta` over the last step. - * Therefore the value is always `1` (no correction) when `delta` constant (or when no correction is desired, which is the default). - * See the paper on Time Corrected Verlet for more information. - * - * Triggers `beforeUpdate` and `afterUpdate` events. - * Triggers `collisionStart`, `collisionActive` and `collisionEnd` events. - * @method update - * @param {engine} engine - * @param {number} [delta=16.666] - * @param {number} [correction=1] - */ - Engine.update = function(engine, delta, correction) { - delta = delta || 1000 / 60; - correction = correction || 1; - - var world = engine.world, - timing = engine.timing, - broadphase = engine.broadphase, - broadphasePairs = [], - i; - - // increment timestamp - timing.timestamp += delta * timing.timeScale; - - // create an event object - var event = { - timestamp: timing.timestamp - }; - - Events.trigger(engine, 'beforeUpdate', event); - - // get lists of all bodies and constraints, no matter what composites they are in - var allBodies = Composite.allBodies(world), - allConstraints = Composite.allConstraints(world); - - - // if sleeping enabled, call the sleeping controller - if (engine.enableSleeping) - Sleeping.update(allBodies, timing.timeScale); - - // applies gravity to all bodies - Engine._bodiesApplyGravity(allBodies, world.gravity); - - // update all body position and rotation by integration - Engine._bodiesUpdate(allBodies, delta, timing.timeScale, correction, world.bounds); - - // update all constraints (first pass) - Constraint.preSolveAll(allBodies); - for (i = 0; i < engine.constraintIterations; i++) { - Constraint.solveAll(allConstraints, timing.timeScale); - } - Constraint.postSolveAll(allBodies); - - // broadphase pass: find potential collision pairs - if (broadphase.controller) { - // if world is dirty, we must flush the whole grid - if (world.isModified) - broadphase.controller.clear(broadphase); - - // update the grid buckets based on current bodies - broadphase.controller.update(broadphase, allBodies, engine, world.isModified); - broadphasePairs = broadphase.pairsList; - } else { - // if no broadphase set, we just pass all bodies - broadphasePairs = allBodies; - } - - // clear all composite modified flags - if (world.isModified) { - Composite.setModified(world, false, false, true); - } - - // narrowphase pass: find actual collisions, then create or update collision pairs - var collisions = broadphase.detector(broadphasePairs, engine); - - // update collision pairs - var pairs = engine.pairs, - timestamp = timing.timestamp; - Pairs.update(pairs, collisions, timestamp); - Pairs.removeOld(pairs, timestamp); - - // wake up bodies involved in collisions - if (engine.enableSleeping) - Sleeping.afterCollisions(pairs.list, timing.timeScale); - - // trigger collision events - if (pairs.collisionStart.length > 0) - Events.trigger(engine, 'collisionStart', { pairs: pairs.collisionStart }); - - // iteratively resolve position between collisions - Resolver.preSolvePosition(pairs.list); - for (i = 0; i < engine.positionIterations; i++) { - Resolver.solvePosition(pairs.list, timing.timeScale); - } - Resolver.postSolvePosition(allBodies); - - // update all constraints (second pass) - Constraint.preSolveAll(allBodies); - for (i = 0; i < engine.constraintIterations; i++) { - Constraint.solveAll(allConstraints, timing.timeScale); - } - Constraint.postSolveAll(allBodies); - - // iteratively resolve velocity between collisions - Resolver.preSolveVelocity(pairs.list); - for (i = 0; i < engine.velocityIterations; i++) { - Resolver.solveVelocity(pairs.list, timing.timeScale); - } - - // trigger collision events - if (pairs.collisionActive.length > 0) - Events.trigger(engine, 'collisionActive', { pairs: pairs.collisionActive }); - - if (pairs.collisionEnd.length > 0) - Events.trigger(engine, 'collisionEnd', { pairs: pairs.collisionEnd }); - - - // clear force buffers - Engine._bodiesClearForces(allBodies); - - Events.trigger(engine, 'afterUpdate', event); - - return engine; - }; - - /** - * Merges two engines by keeping the configuration of `engineA` but replacing the world with the one from `engineB`. - * @method merge - * @param {engine} engineA - * @param {engine} engineB - */ - Engine.merge = function(engineA, engineB) { - Common.extend(engineA, engineB); - - if (engineB.world) { - engineA.world = engineB.world; - - Engine.clear(engineA); - - var bodies = Composite.allBodies(engineA.world); - - for (var i = 0; i < bodies.length; i++) { - var body = bodies[i]; - Sleeping.set(body, false); - body.id = Common.nextId(); - } - } - }; - - /** - * Clears the engine including the world, pairs and broadphase. - * @method clear - * @param {engine} engine - */ - Engine.clear = function(engine) { - var world = engine.world; - - Pairs.clear(engine.pairs); - - var broadphase = engine.broadphase; - if (broadphase.controller) { - var bodies = Composite.allBodies(world); - broadphase.controller.clear(broadphase); - broadphase.controller.update(broadphase, bodies, engine, true); - } - }; - - /** - * Zeroes the `body.force` and `body.torque` force buffers. - * @method _bodiesClearForces - * @private - * @param {body[]} bodies - */ - Engine._bodiesClearForces = function(bodies) { - for (var i = 0; i < bodies.length; i++) { - var body = bodies[i]; - - // reset force buffers - body.force.x = 0; - body.force.y = 0; - body.torque = 0; - } - }; - - /** - * Applys a mass dependant force to all given bodies. - * @method _bodiesApplyGravity - * @private - * @param {body[]} bodies - * @param {vector} gravity - */ - Engine._bodiesApplyGravity = function(bodies, gravity) { - var gravityScale = typeof gravity.scale !== 'undefined' ? gravity.scale : 0.001; - - if ((gravity.x === 0 && gravity.y === 0) || gravityScale === 0) { - return; - } - - for (var i = 0; i < bodies.length; i++) { - var body = bodies[i]; - - if (body.isStatic || body.isSleeping) - continue; - - // apply gravity - body.force.y += body.mass * gravity.y * gravityScale; - body.force.x += body.mass * gravity.x * gravityScale; - } - }; - - /** - * Applys `Body.update` to all given `bodies`. - * @method _bodiesUpdate - * @private - * @param {body[]} bodies - * @param {number} deltaTime - * The amount of time elapsed between updates - * @param {number} timeScale - * @param {number} correction - * The Verlet correction factor (deltaTime / lastDeltaTime) - * @param {bounds} worldBounds - */ - Engine._bodiesUpdate = function(bodies, deltaTime, timeScale, correction, worldBounds) { - for (var i = 0; i < bodies.length; i++) { - var body = bodies[i]; - - if (body.isStatic || body.isSleeping) - continue; - - Body.update(body, deltaTime, timeScale, correction); - } - }; - - /** - * An alias for `Runner.run`, see `Matter.Runner` for more information. - * @method run - * @param {engine} engine - */ - - /** - * Fired just before an update - * - * @event beforeUpdate - * @param {} event An event object - * @param {number} event.timestamp The engine.timing.timestamp of the event - * @param {} event.source The source object of the event - * @param {} event.name The name of the event - */ - - /** - * Fired after engine update and all collision events - * - * @event afterUpdate - * @param {} event An event object - * @param {number} event.timestamp The engine.timing.timestamp of the event - * @param {} event.source The source object of the event - * @param {} event.name The name of the event - */ - - /** - * Fired after engine update, provides a list of all pairs that have started to collide in the current tick (if any) - * - * @event collisionStart - * @param {} event An event object - * @param {} event.pairs List of affected pairs - * @param {number} event.timestamp The engine.timing.timestamp of the event - * @param {} event.source The source object of the event - * @param {} event.name The name of the event - */ - - /** - * Fired after engine update, provides a list of all pairs that are colliding in the current tick (if any) - * - * @event collisionActive - * @param {} event An event object - * @param {} event.pairs List of affected pairs - * @param {number} event.timestamp The engine.timing.timestamp of the event - * @param {} event.source The source object of the event - * @param {} event.name The name of the event - */ - - /** - * Fired after engine update, provides a list of all pairs that have ended collision in the current tick (if any) - * - * @event collisionEnd - * @param {} event An event object - * @param {} event.pairs List of affected pairs - * @param {number} event.timestamp The engine.timing.timestamp of the event - * @param {} event.source The source object of the event - * @param {} event.name The name of the event - */ - - /* - * - * Properties Documentation - * - */ - - /** - * An integer `Number` that specifies the number of position iterations to perform each update. - * The higher the value, the higher quality the simulation will be at the expense of performance. - * - * @property positionIterations - * @type number - * @default 6 - */ - - /** - * An integer `Number` that specifies the number of velocity iterations to perform each update. - * The higher the value, the higher quality the simulation will be at the expense of performance. - * - * @property velocityIterations - * @type number - * @default 4 - */ - - /** - * An integer `Number` that specifies the number of constraint iterations to perform each update. - * The higher the value, the higher quality the simulation will be at the expense of performance. - * The default value of `2` is usually very adequate. - * - * @property constraintIterations - * @type number - * @default 2 - */ - - /** - * A flag that specifies whether the engine should allow sleeping via the `Matter.Sleeping` module. - * Sleeping can improve stability and performance, but often at the expense of accuracy. - * - * @property enableSleeping - * @type boolean - * @default false - */ - - /** - * An `Object` containing properties regarding the timing systems of the engine. - * - * @property timing - * @type object - */ - - /** - * A `Number` that specifies the global scaling factor of time for all bodies. - * A value of `0` freezes the simulation. - * A value of `0.1` gives a slow-motion effect. - * A value of `1.2` gives a speed-up effect. - * - * @property timing.timeScale - * @type number - * @default 1 - */ - - /** - * A `Number` that specifies the current simulation-time in milliseconds starting from `0`. - * It is incremented on every `Engine.update` by the given `delta` argument. - * - * @property timing.timestamp - * @type number - * @default 0 - */ - - /** - * An instance of a `Render` controller. The default value is a `Matter.Render` instance created by `Engine.create`. - * One may also develop a custom renderer module based on `Matter.Render` and pass an instance of it to `Engine.create` via `options.render`. - * - * A minimal custom renderer object must define at least three functions: `create`, `clear` and `world` (see `Matter.Render`). - * It is also possible to instead pass the _module_ reference via `options.render.controller` and `Engine.create` will instantiate one for you. - * - * @property render - * @type render - * @deprecated see Demo.js for an example of creating a renderer - * @default a Matter.Render instance - */ - - /** - * An instance of a broadphase controller. The default value is a `Matter.Grid` instance created by `Engine.create`. - * - * @property broadphase - * @type grid - * @default a Matter.Grid instance - */ - - /** - * A `World` composite object that will contain all simulated bodies and constraints. - * - * @property world - * @type world - * @default a Matter.World instance - */ - - /** - * An object reserved for storing plugin-specific properties. - * - * @property plugin - * @type {} - */ - -})(); - -},{"../body/Body":1,"../body/Composite":2,"../body/World":3,"../collision/Grid":6,"../collision/Pairs":8,"../collision/Resolver":10,"../constraint/Constraint":12,"../render/Render":31,"./Common":14,"./Events":16,"./Metrics":18,"./Sleeping":22}],16:[function(_dereq_,module,exports){ -/** -* 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 = _dereq_('./Common'); - -(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; - - if (object.events) { - if (!event) - event = {}; - - names = eventNames.split(' '); - - for (var i = 0; i < names.length; i++) { - name = names[i]; - callbacks = object.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]); - } - } - } - } - }; - -})(); - -},{"./Common":14}],17:[function(_dereq_,module,exports){ -/** -* 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 = _dereq_('./Plugin'); -var Common = _dereq_('./Common'); - -(function() { - - /** - * The library name. - * @property name - * @readOnly - * @type {String} - */ - Matter.name = 'matter-js'; - - /** - * The library version. - * @property version - * @readOnly - * @type {String} - */ - Matter.version = '0.14.2'; - - /** - * 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); - }; - -})(); - -},{"./Common":14,"./Plugin":20}],18:[function(_dereq_,module,exports){ - -},{"../body/Composite":2,"./Common":14}],19:[function(_dereq_,module,exports){ -/** -* The `Matter.Mouse` module contains methods for creating and manipulating mouse inputs. -* -* @class Mouse -*/ - -var Mouse = {}; - -module.exports = Mouse; - -var Common = _dereq_('../core/Common'); - -(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 = mouse.element.getAttribute('data-pixel-ratio') || 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.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); - element.addEventListener('mousedown', mouse.mousedown); - element.addEventListener('mouseup', mouse.mouseup); - - element.addEventListener('mousewheel', mouse.mousewheel); - element.addEventListener('DOMMouseScroll', mouse.mousewheel); - - element.addEventListener('touchmove', mouse.mousemove); - element.addEventListener('touchstart', mouse.mousedown); - element.addEventListener('touchend', mouse.mouseup); - }; - - /** - * 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) - }; - }; - -})(); - -},{"../core/Common":14}],20:[function(_dereq_,module,exports){ -/** -* The `Matter.Plugin` module contains functions for registering and installing plugins on modules. -* -* @class Plugin -*/ - -var Plugin = {}; - -module.exports = Plugin; - -var Common = _dereq_('./Common'); - -(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` - * - 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 = /^\*|[\^~]?\d+\.\d+\.\d+(-[0-9A-Za-z-]+)?$/; - - if (!pattern.test(range)) { - Common.warn('Plugin.versionParse:', range, 'is not a valid version or range.'); - } - - var identifiers = range.split('-'); - range = identifiers[0]; - - var isRange = isNaN(Number(range[0])), - version = isRange ? range.substr(1) : range, - parts = Common.map(version.split('.'), function(part) { - return Number(part); - }); - - return { - isRange: isRange, - version: version, - range: range, - operator: isRange ? range[0] : '', - parts: parts, - prerelease: identifiers[1], - number: parts[0] * 1e8 + parts[1] * 1e4 + parts[2] - }; - }; - - /** - * 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 rangeParsed = Plugin.versionParse(range), - rangeParts = rangeParsed.parts, - versionParsed = Plugin.versionParse(version), - versionParts = versionParsed.parts; - - if (rangeParsed.isRange) { - if (rangeParsed.operator === '*' || version === '*') { - return true; - } - - if (rangeParsed.operator === '~') { - return versionParts[0] === rangeParts[0] && versionParts[1] === rangeParts[1] && versionParts[2] >= rangeParts[2]; - } - - if (rangeParsed.operator === '^') { - if (rangeParts[0] > 0) { - return versionParts[0] === rangeParts[0] && versionParsed.number >= rangeParsed.number; - } - - if (rangeParts[1] > 0) { - return versionParts[1] === rangeParts[1] && versionParts[2] >= rangeParts[2]; - } - - return versionParts[2] === rangeParts[2]; - } - } - - return version === range || version === '*'; - }; - -})(); - -},{"./Common":14}],21:[function(_dereq_,module,exports){ -/** -* The `Matter.Runner` module is an optional utility which provides a game loop, -* that handles continuously updating a `Matter.Engine` for you within a browser. -* It is intended for development and debugging purposes, but may also be suitable for simple games. -* If you are using your own game loop instead, then you do not need the `Matter.Runner` module. -* Instead just call `Engine.update(engine, delta)` in your own loop. -* -* See the included usage [examples](https://github.com/liabru/matter-js/tree/master/examples). -* -* @class Runner -*/ - -var Runner = {}; - -module.exports = Runner; - -var Events = _dereq_('./Events'); -var Engine = _dereq_('./Engine'); -var Common = _dereq_('./Common'); - -(function() { - - var _requestAnimationFrame, - _cancelAnimationFrame; - - if (typeof window !== 'undefined') { - _requestAnimationFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame - || window.mozRequestAnimationFrame || window.msRequestAnimationFrame; - - _cancelAnimationFrame = window.cancelAnimationFrame || window.mozCancelAnimationFrame - || window.webkitCancelAnimationFrame || window.msCancelAnimationFrame; - } - - if (!_requestAnimationFrame) { - var _frameTimeout; - - _requestAnimationFrame = function(callback){ - _frameTimeout = setTimeout(function() { - callback(Common.now()); - }, 1000 / 60); - }; - - _cancelAnimationFrame = function() { - clearTimeout(_frameTimeout); - }; - } - - /** - * Creates a new Runner. The options parameter is an object that specifies any properties you wish to override the defaults. - * @method create - * @param {} options - */ - Runner.create = function(options) { - var defaults = { - fps: 60, - correction: 1, - deltaSampleSize: 60, - counterTimestamp: 0, - frameCounter: 0, - deltaHistory: [], - timePrev: null, - timeScalePrev: 1, - frameRequestId: null, - isFixed: false, - enabled: true - }; - - var runner = Common.extend(defaults, options); - - runner.delta = runner.delta || 1000 / runner.fps; - runner.deltaMin = runner.deltaMin || 1000 / runner.fps; - runner.deltaMax = runner.deltaMax || 1000 / (runner.fps * 0.5); - runner.fps = 1000 / runner.delta; - - return runner; - }; - - /** - * Continuously ticks a `Matter.Engine` by calling `Runner.tick` on the `requestAnimationFrame` event. - * @method run - * @param {engine} engine - */ - Runner.run = function(runner, engine) { - // create runner if engine is first argument - if (typeof runner.positionIterations !== 'undefined') { - engine = runner; - runner = Runner.create(); - } - - (function render(time){ - runner.frameRequestId = _requestAnimationFrame(render); - - if (time && runner.enabled) { - Runner.tick(runner, engine, time); - } - })(); - - return runner; - }; - - /** - * A game loop utility that updates the engine and renderer by one step (a 'tick'). - * Features delta smoothing, time correction and fixed or dynamic timing. - * Triggers `beforeTick`, `tick` and `afterTick` events on the engine. - * Consider just `Engine.update(engine, delta)` if you're using your own loop. - * @method tick - * @param {runner} runner - * @param {engine} engine - * @param {number} time - */ - Runner.tick = function(runner, engine, time) { - var timing = engine.timing, - correction = 1, - delta; - - // create an event object - var event = { - timestamp: timing.timestamp - }; - - Events.trigger(runner, 'beforeTick', event); - Events.trigger(engine, 'beforeTick', event); // @deprecated - - if (runner.isFixed) { - // fixed timestep - delta = runner.delta; - } else { - // dynamic timestep based on wall clock between calls - delta = (time - runner.timePrev) || runner.delta; - runner.timePrev = time; - - // optimistically filter delta over a few frames, to improve stability - runner.deltaHistory.push(delta); - runner.deltaHistory = runner.deltaHistory.slice(-runner.deltaSampleSize); - delta = Math.min.apply(null, runner.deltaHistory); - - // limit delta - delta = delta < runner.deltaMin ? runner.deltaMin : delta; - delta = delta > runner.deltaMax ? runner.deltaMax : delta; - - // correction for delta - correction = delta / runner.delta; - - // update engine timing object - runner.delta = delta; - } - - // time correction for time scaling - if (runner.timeScalePrev !== 0) - correction *= timing.timeScale / runner.timeScalePrev; - - if (timing.timeScale === 0) - correction = 0; - - runner.timeScalePrev = timing.timeScale; - runner.correction = correction; - - // fps counter - runner.frameCounter += 1; - if (time - runner.counterTimestamp >= 1000) { - runner.fps = runner.frameCounter * ((time - runner.counterTimestamp) / 1000); - runner.counterTimestamp = time; - runner.frameCounter = 0; - } - - Events.trigger(runner, 'tick', event); - Events.trigger(engine, 'tick', event); // @deprecated - - // if world has been modified, clear the render scene graph - if (engine.world.isModified - && engine.render - && engine.render.controller - && engine.render.controller.clear) { - engine.render.controller.clear(engine.render); // @deprecated - } - - // update - Events.trigger(runner, 'beforeUpdate', event); - Engine.update(engine, delta, correction); - Events.trigger(runner, 'afterUpdate', event); - - // render - // @deprecated - if (engine.render && engine.render.controller) { - Events.trigger(runner, 'beforeRender', event); - Events.trigger(engine, 'beforeRender', event); // @deprecated - - engine.render.controller.world(engine.render); - - Events.trigger(runner, 'afterRender', event); - Events.trigger(engine, 'afterRender', event); // @deprecated - } - - Events.trigger(runner, 'afterTick', event); - Events.trigger(engine, 'afterTick', event); // @deprecated - }; - - /** - * Ends execution of `Runner.run` on the given `runner`, by canceling the animation frame request event loop. - * If you wish to only temporarily pause the engine, see `engine.enabled` instead. - * @method stop - * @param {runner} runner - */ - Runner.stop = function(runner) { - _cancelAnimationFrame(runner.frameRequestId); - }; - - /** - * Alias for `Runner.run`. - * @method start - * @param {runner} runner - * @param {engine} engine - */ - Runner.start = function(runner, engine) { - Runner.run(runner, engine); - }; - - /* - * - * Events Documentation - * - */ - - /** - * Fired at the start of a tick, before any updates to the engine or timing - * - * @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 after engine timing updated, but just before update - * - * @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 at the end of a tick, after engine update and after rendering - * - * @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 update - * - * @event beforeUpdate - * @param {} event An event object - * @param {number} event.timestamp The engine.timing.timestamp of the event - * @param {} event.source The source object of the event - * @param {} event.name The name of the event - */ - - /** - * Fired after update - * - * @event afterUpdate - * @param {} event An event object - * @param {number} event.timestamp The engine.timing.timestamp of the event - * @param {} event.source The source object of the event - * @param {} event.name The name of the event - */ - - /** - * Fired 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 - * @deprecated - */ - - /** - * 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 - * @deprecated - */ - - /* - * - * Properties Documentation - * - */ - - /** - * A flag that specifies whether the runner is running or not. - * - * @property enabled - * @type boolean - * @default true - */ - - /** - * A `Boolean` that specifies if the runner should use a fixed timestep (otherwise it is variable). - * If timing is fixed, then the apparent simulation speed will change depending on the frame rate (but behaviour will be deterministic). - * If the timing is variable, then the apparent simulation speed will be constant (approximately, but at the cost of determininism). - * - * @property isFixed - * @type boolean - * @default false - */ - - /** - * A `Number` that specifies the time step between updates in milliseconds. - * If `engine.timing.isFixed` is set to `true`, then `delta` is fixed. - * If it is `false`, then `delta` can dynamically change to maintain the correct apparent simulation speed. - * - * @property delta - * @type number - * @default 1000 / 60 - */ - -})(); - -},{"./Common":14,"./Engine":15,"./Events":16}],22:[function(_dereq_,module,exports){ -/** -* The `Matter.Sleeping` module contains methods to manage the sleeping state of bodies. -* -* @class Sleeping -*/ - -var Sleeping = {}; - -module.exports = Sleeping; - -var Events = _dereq_('./Events'); - -(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} timeScale - */ - Sleeping.update = function(bodies, timeScale) { - var timeFactor = timeScale * timeScale * timeScale; - - // update bodies sleeping status - for (var i = 0; i < bodies.length; i++) { - var body = bodies[i], - motion = body.speed * body.speed + body.angularSpeed * body.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 < Sleeping._motionSleepThreshold * timeFactor) { - body.sleepCounter += 1; - - if (body.sleepCounter >= body.sleepThreshold) - 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 - * @param {number} timeScale - */ - Sleeping.afterCollisions = function(pairs, timeScale) { - var timeFactor = timeScale * timeScale * timeScale; - - // 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 > Sleeping._motionWakeThreshold * timeFactor) { - 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'); - } - } - }; - -})(); - -},{"./Events":16}],23:[function(_dereq_,module,exports){ -/** -* 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 = _dereq_('../geometry/Vertices'); -var Common = _dereq_('../core/Common'); -var Body = _dereq_('../body/Body'); -var Bounds = _dereq_('../geometry/Bounds'); -var Vector = _dereq_('../geometry/Vector'); -var decomp; - -(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 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 - * @param {object} [options] - * @return {body} A new trapezoid body - */ - Bodies.trapezoid = function(x, y, width, height, slope, options) { - options = options || {}; - - 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)); - }; - - /** - * Creates a body using the supplied vertices (or an array containing multiple sets of vertices). - * If the vertices are convex, they will pass through as supplied. - * Otherwise if the vertices are concave, they will be decomposed if [poly-decomp.js](https://github.com/schteppe/poly-decomp.js) is available. - * Note that this process is not guaranteed to support complex sets of vertices (e.g. those with holes may fail). - * By default the decomposition will discard collinear edges (to improve performance). - * It can also optionally discard any parts that have an area less than `minimumArea`. - * If the vertices can not be decomposed, the result will fall back to using the convex hull. - * The options parameter is an object that 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 [[vector]] vertexSets - * @param {object} [options] - * @param {bool} [flagInternal=false] - * @param {number} [removeCollinear=0.01] - * @param {number} [minimumArea=10] - * @return {body} - */ - Bodies.fromVertices = function(x, y, vertexSets, options, flagInternal, removeCollinear, minimumArea) { - if (!decomp) { - decomp = Common._requireGlobal('decomp', 'poly-decomp'); - } - - var body, - parts, - isConvex, - vertices, - i, - j, - k, - v, - z; - - options = options || {}; - parts = []; - - flagInternal = typeof flagInternal !== 'undefined' ? flagInternal : false; - removeCollinear = typeof removeCollinear !== 'undefined' ? removeCollinear : 0.01; - minimumArea = typeof minimumArea !== 'undefined' ? minimumArea : 10; - - if (!decomp) { - Common.warn('Bodies.fromVertices: poly-decomp.js required. Could not decompose vertices. Fallback to convex hull.'); - } - - // 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); - - if (isConvex || !decomp) { - if (isConvex) { - vertices = Vertices.clockwiseSort(vertices); + if (collision.collided) { + for (var i = 0; i < supports.length; i++) { + var support = supports[i], + contactId = Contact.id(support), + contact = contacts[contactId]; + + if (contact) { + activeContacts.push(contact); } 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); - - // 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 - }); + activeContacts.push(contacts[contactId] = Contact.create(support)); } } - } - // 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)); - Body.setPosition(body, { x: x, y: y }); - - return body; + pair.separation = collision.depth; + Pair.setActive(pair, true, timestamp); } else { - return parts[0]; + if (pair.isActive === true) + Pair.setActive(pair, false, timestamp); } }; - -})(); - -},{"../body/Body":1,"../core/Common":14,"../geometry/Bounds":26,"../geometry/Vector":28,"../geometry/Vertices":29}],24:[function(_dereq_,module,exports){ -/** -* 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 = _dereq_('../body/Composite'); -var Constraint = _dereq_('../constraint/Constraint'); -var Common = _dereq_('../core/Common'); -var Body = _dereq_('../body/Body'); -var Bodies = _dereq_('./Bodies'); - -(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} xx - * @param {number} yy - * @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(xx, yy, columns, rows, columnGap, rowGap, callback) { - var stack = Composite.create({ label: 'Stack' }), - x = xx, - y = yy, - lastBody, - i = 0; - - for (var row = 0; row < rows; row++) { - var maxHeight = 0; - - for (var column = 0; column < columns; column++) { - var body = callback(x, y, 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 }); - - x = body.bounds.max.x + columnGap; - - Composite.addBody(stack, body); - - lastBody = body; - i += 1; - } else { - x += columnGap; - } - } - - y += maxHeight + rowGap; - x = xx; - } - - 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 + * Set a pair as active or inactive. + * @method setActive + * @param {pair} pair + * @param {bool} isActive + * @param {number} timestamp */ - 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} xx - * @param {number} yy - * @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(xx, yy, columns, rows, columnGap, rowGap, callback) { - return Composites.stack(xx, yy, columns, rows, columnGap, rowGap, function(x, y, 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(xx + xOffset + column * columnGap, y, column, row, lastBody, i); - }); - }; - - /** - * Creates a composite with a Newton's Cradle setup of bodies and constraints. - * @method newtonsCradle - * @param {number} xx - * @param {number} yy - * @param {number} number - * @param {number} size - * @param {number} length - * @return {composite} A new composite newtonsCradle body - */ - Composites.newtonsCradle = function(xx, yy, number, size, length) { - var newtonsCradle = Composite.create({ label: 'Newtons Cradle' }); - - for (var i = 0; i < number; i++) { - var separation = 1.9, - circle = Bodies.circle(xx + i * (size * separation), yy + length, size, - { inertia: Infinity, restitution: 1, friction: 0, frictionAir: 0.0001, slop: 1 }), - constraint = Constraint.create({ pointA: { x: xx + i * (size * separation), y: yy }, bodyB: circle }); - - Composite.addBody(newtonsCradle, circle); - Composite.addConstraint(newtonsCradle, constraint); - } - - return newtonsCradle; - }; - - /** - * Creates a composite with simple car setup of bodies and constraints. - * @method car - * @param {number} xx - * @param {number} yy - * @param {number} width - * @param {number} height - * @param {number} wheelSize - * @return {composite} A new composite car body - */ - Composites.car = function(xx, yy, 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(xx, yy, width, height, { - collisionFilter: { - group: group - }, - chamfer: { - radius: height * 0.5 - }, - density: 0.0002 - }); - - var wheelA = Bodies.circle(xx + wheelAOffset, yy + wheelYOffset, wheelSize, { - collisionFilter: { - group: group - }, - friction: 0.8 - }); - - var wheelB = Bodies.circle(xx + wheelBOffset, yy + 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; - }; - - /** - * Creates a simple soft body like object. - * @method softBody - * @param {number} xx - * @param {number} yy - * @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(xx, yy, 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(xx, yy, columns, rows, columnGap, rowGap, function(x, y) { - return Bodies.circle(x, y, particleRadius, particleOptions); - }); - - Composites.mesh(softBody, columns, rows, crossBrace, constraintOptions); - - softBody.label = 'Soft Body'; - - return softBody; - }; - -})(); - -},{"../body/Body":1,"../body/Composite":2,"../constraint/Constraint":12,"../core/Common":14,"./Bodies":23}],25:[function(_dereq_,module,exports){ -/** -* The `Matter.Axes` module contains methods for creating and manipulating sets of axes. -* -* @class Axes -*/ - -var Axes = {}; - -module.exports = Axes; - -var Vector = _dereq_('../geometry/Vector'); -var Common = _dereq_('../core/Common'); - -(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; - } - }; - -})(); - -},{"../core/Common":14,"../geometry/Vector":28}],26:[function(_dereq_,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; - }; - -})(); - -},{}],27:[function(_dereq_,module,exports){ -/** -* 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 = _dereq_('../geometry/Bounds'); -var Common = _dereq_('../core/Common'); - -(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; - } - } - }; - -})(); -},{"../core/Common":14,"../geometry/Bounds":26}],28:[function(_dereq_,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() - ]; - -})(); -},{}],29:[function(_dereq_,module,exports){ -/** -* 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 = _dereq_('../geometry/Vector'); -var Common = _dereq_('../core/Common'); - -(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) { - var i; - if (scalar) { - for (i = 0; i < vertices.length; i++) { - vertices[i].x += vector.x * scalar; - vertices[i].y += vector.y * scalar; - } + Pair.setActive = function(pair, isActive, timestamp) { + if (isActive) { + pair.isActive = true; + pair.timeUpdated = timestamp; } else { - for (i = 0; i < vertices.length; i++) { - vertices[i].x += vector.x; - vertices[i].y += vector.y; - } + pair.isActive = false; + pair.activeContacts.length = 0; } - - return vertices; }; /** - * Rotates the set of vertices in-place. - * @method rotate - * @param {vertices} vertices - * @param {number} angle - * @param {vector} point + * Get the id for the given pair. + * @method id + * @param {body} bodyA + * @param {body} bodyB + * @return {string} Unique pairId */ - Vertices.rotate = function(vertices, angle, point) { - if (angle === 0) - return; - - var cos = Math.cos(angle), - sin = Math.sin(angle); - - for (var i = 0; i < vertices.length; i++) { - var vertice = vertices[i], - dx = vertice.x - point.x, - dy = vertice.y - point.y; - - vertice.x = point.x + (dx * cos - dy * sin); - vertice.y = point.y + (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) { - for (var i = 0; i < vertices.length; i++) { - var vertice = vertices[i], - nextVertice = vertices[(i + 1) % vertices.length]; - if ((point.x - vertice.x) * (nextVertice.y - vertice.y) + (point.y - vertice.y) * (vertice.x - nextVertice.x) > 0) { - return false; - } - } - - 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]; + Pair.id = function(bodyA, bodyB) { + if (bodyA.id < bodyB.id) { + return 'A' + bodyA.id + 'B' + bodyB.id; } else { - radius = radius || [8]; + return 'A' + bodyB.id + 'B' + bodyA.id; } - - // 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); }; })(); -},{"../core/Common":14,"../geometry/Vector":28}],30:[function(_dereq_,module,exports){ -var Matter = module.exports = _dereq_('../core/Matter'); -Matter.Body = _dereq_('../body/Body'); -Matter.Composite = _dereq_('../body/Composite'); -Matter.World = _dereq_('../body/World'); +/***/ }), +/* 10 */ +/***/ (function(module, exports, __webpack_require__) { -Matter.Contact = _dereq_('../collision/Contact'); -Matter.Detector = _dereq_('../collision/Detector'); -Matter.Grid = _dereq_('../collision/Grid'); -Matter.Pairs = _dereq_('../collision/Pairs'); -Matter.Pair = _dereq_('../collision/Pair'); -Matter.Query = _dereq_('../collision/Query'); -Matter.Resolver = _dereq_('../collision/Resolver'); -Matter.SAT = _dereq_('../collision/SAT'); - -Matter.Constraint = _dereq_('../constraint/Constraint'); -Matter.MouseConstraint = _dereq_('../constraint/MouseConstraint'); - -Matter.Common = _dereq_('../core/Common'); -Matter.Engine = _dereq_('../core/Engine'); -Matter.Events = _dereq_('../core/Events'); -Matter.Mouse = _dereq_('../core/Mouse'); -Matter.Runner = _dereq_('../core/Runner'); -Matter.Sleeping = _dereq_('../core/Sleeping'); -Matter.Plugin = _dereq_('../core/Plugin'); - - -Matter.Bodies = _dereq_('../factory/Bodies'); -Matter.Composites = _dereq_('../factory/Composites'); - -Matter.Axes = _dereq_('../geometry/Axes'); -Matter.Bounds = _dereq_('../geometry/Bounds'); -Matter.Svg = _dereq_('../geometry/Svg'); -Matter.Vector = _dereq_('../geometry/Vector'); -Matter.Vertices = _dereq_('../geometry/Vertices'); - -Matter.Render = _dereq_('../render/Render'); -Matter.RenderPixi = _dereq_('../render/RenderPixi'); - -// aliases - -Matter.World.add = Matter.Composite.add; -Matter.World.remove = Matter.Composite.remove; -Matter.World.addComposite = Matter.Composite.addComposite; -Matter.World.addBody = Matter.Composite.addBody; -Matter.World.addConstraint = Matter.Composite.addConstraint; -Matter.World.clear = Matter.Composite.clear; -Matter.Engine.run = Matter.Runner.run; - -},{"../body/Body":1,"../body/Composite":2,"../body/World":3,"../collision/Contact":4,"../collision/Detector":5,"../collision/Grid":6,"../collision/Pair":7,"../collision/Pairs":8,"../collision/Query":9,"../collision/Resolver":10,"../collision/SAT":11,"../constraint/Constraint":12,"../constraint/MouseConstraint":13,"../core/Common":14,"../core/Engine":15,"../core/Events":16,"../core/Matter":17,"../core/Metrics":18,"../core/Mouse":19,"../core/Plugin":20,"../core/Runner":21,"../core/Sleeping":22,"../factory/Bodies":23,"../factory/Composites":24,"../geometry/Axes":25,"../geometry/Bounds":26,"../geometry/Svg":27,"../geometry/Vector":28,"../geometry/Vertices":29,"../render/Render":31,"../render/RenderPixi":32}],31:[function(_dereq_,module,exports){ /** * The `Matter.Render` module is a simple HTML5 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. @@ -8366,13 +4307,13 @@ var Render = {}; module.exports = Render; -var Common = _dereq_('../core/Common'); -var Composite = _dereq_('../body/Composite'); -var Bounds = _dereq_('../geometry/Bounds'); -var Events = _dereq_('../core/Events'); -var Grid = _dereq_('../collision/Grid'); -var Vector = _dereq_('../geometry/Vector'); -var Mouse = _dereq_('../core/Mouse'); +var Common = __webpack_require__(0); +var Composite = __webpack_require__(5); +var Bounds = __webpack_require__(1); +var Events = __webpack_require__(4); +var Grid = __webpack_require__(11); +var Vector = __webpack_require__(2); +var Mouse = __webpack_require__(14); (function() { @@ -8408,8 +4349,8 @@ var Mouse = _dereq_('../core/Mouse'); width: 800, height: 600, pixelRatio: 1, - background: '#18181d', - wireframeBackground: '#0f0f13', + background: '#14151f', + wireframeBackground: '#14151f', hasBounds: !!options.bounds, enabled: true, wireframes: true, @@ -8511,7 +4452,6 @@ var Mouse = _dereq_('../core/Mouse'); canvas.height = options.height * pixelRatio; canvas.style.width = options.width + 'px'; canvas.style.height = options.height + 'px'; - render.context.scale(pixelRatio, pixelRatio); }; /** @@ -8623,7 +4563,11 @@ var Mouse = _dereq_('../core/Mouse'); boundsScaleX = boundsWidth / render.options.width, boundsScaleY = boundsHeight / render.options.height; - render.context.scale(1 / boundsScaleX, 1 / boundsScaleY); + 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); }; @@ -8704,8 +4648,8 @@ var Mouse = _dereq_('../core/Mouse'); // 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 + 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); @@ -8713,6 +4657,10 @@ var Mouse = _dereq_('../core/Mouse'); } 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)) { @@ -8792,6 +4740,27 @@ var Mouse = _dereq_('../core/Mouse'); text += "fps: " + Math.round(metrics.timing.fps) + space; } + // @if DEBUG + if (metrics.extended) { + if (metrics.timing) { + text += "delta: " + metrics.timing.delta.toFixed(3) + space; + text += "correction: " + metrics.timing.correction.toFixed(3) + space; + } + + text += "bodies: " + bodies.length + space; + + if (engine.broadphase.controller === Grid) + text += "buckets: " + metrics.buckets + space; + + text += "\n"; + + text += "collisions: " + metrics.collisions + space; + text += "pairs: " + engine.pairs.list.length + space; + text += "broad: " + metrics.broadEff + space; + text += "mid: " + metrics.midEff + space; + text += "narrow: " + metrics.narrowEff + space; + } + // @endif render.debugString = text; render.debugTimestamp = engine.timing.timestamp; @@ -9255,7 +5224,7 @@ var Mouse = _dereq_('../core/Mouse'); // 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); + (part.vertices[0].y + part.vertices[part.vertices.length-1].y) / 2); } } } @@ -9555,9 +5524,9 @@ var Mouse = _dereq_('../core/Mouse'); var region = bucketId.split(/C|R/); c.rect(0.5 + parseInt(region[1], 10) * grid.bucketWidth, - 0.5 + parseInt(region[2], 10) * grid.bucketHeight, - grid.bucketWidth, - grid.bucketHeight); + 0.5 + parseInt(region[2], 10) * grid.bucketHeight, + grid.bucketWidth, + grid.bucketHeight); } c.lineWidth = 1; @@ -9604,7 +5573,7 @@ var Mouse = _dereq_('../core/Mouse'); 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)); + Math.floor(bounds.max.x - bounds.min.x + 6), Math.floor(bounds.max.y - bounds.min.y + 6)); context.closePath(); context.stroke(); @@ -9638,7 +5607,7 @@ var Mouse = _dereq_('../core/Mouse'); 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)); + Math.floor(bounds.max.x - bounds.min.x), Math.floor(bounds.max.y - bounds.min.y)); context.closePath(); context.stroke(); context.fill(); @@ -9840,7 +5809,4482 @@ var Mouse = _dereq_('../core/Mouse'); })(); -},{"../body/Composite":2,"../collision/Grid":6,"../core/Common":14,"../core/Events":16,"../core/Mouse":19,"../geometry/Bounds":26,"../geometry/Vector":28}],32:[function(_dereq_,module,exports){ + +/***/ }), +/* 11 */ +/***/ (function(module, exports, __webpack_require__) { + +/** +* The `Matter.Grid` module contains methods for creating and manipulating collision broadphase grid structures. +* +* @class Grid +*/ + +var Grid = {}; + +module.exports = Grid; + +var Pair = __webpack_require__(9); +var Detector = __webpack_require__(12); +var Common = __webpack_require__(0); + +(function() { + + /** + * Creates a new grid. + * @method create + * @param {} options + * @return {grid} A new grid + */ + Grid.create = function(options) { + var defaults = { + controller: Grid, + detector: Detector.collisions, + 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. + * @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; + + // @if DEBUG + var metrics = engine.metrics; + metrics.broadphaseTests = 0; + // @endif + + for (i = 0; i < bodies.length; i++) { + var body = bodies[i]; + + if (body.isSleeping && !forceUpdate) + continue; + + // don't update out of world bodies + if (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 DEBUG + metrics.broadphaseTests += 1; + // @endif + + 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); + }; + + /** + * Clears the grid. + * @method clear + * @param {grid} grid + */ + Grid.clear = function(grid) { + grid.buckets = {}; + grid.pairs = {}; + grid.pairsList = []; + }; + + /** + * Finds the union of two regions. + * @method _regionUnion + * @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 + * @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 + * @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 + * @private + * @param {} column + * @param {} row + * @return {string} bucket id + */ + Grid._getBucketId = function(column, row) { + return 'C' + column + 'R' + row; + }; + + /** + * Creates a bucket. + * @method _createBucket + * @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 + * @private + * @param {} grid + * @param {} bucket + * @param {} body + */ + Grid._bucketAddBody = function(grid, bucket, body) { + // add new pairs + for (var i = 0; i < bucket.length; 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 pairId = Pair.id(body, bodyB), + pair = grid.pairs[pairId]; + + if (pair) { + pair[2] += 1; + } else { + grid.pairs[pairId] = [body, bodyB, 1]; + } + } + + // add to bodies (after pairs, otherwise pairs with self) + bucket.push(body); + }; + + /** + * Removes a body from a bucket. + * @method _bucketRemoveBody + * @private + * @param {} grid + * @param {} bucket + * @param {} body + */ + Grid._bucketRemoveBody = function(grid, bucket, body) { + // remove from bucket + bucket.splice(Common.indexOf(bucket, body), 1); + + // update pair counts + for (var i = 0; i < bucket.length; i++) { + // keep track of the number of buckets the pair exists in + // important for _createActivePairsList to work + var bodyB = bucket[i], + pairId = Pair.id(body, bodyB), + pair = grid.pairs[pairId]; + + if (pair) + pair[2] -= 1; + } + }; + + /** + * Generates a list of the active pairs in the grid. + * @method _createActivePairsList + * @private + * @param {} grid + * @return [] pairs + */ + Grid._createActivePairsList = function(grid) { + var pairKeys, + pair, + pairs = []; + + // grid.pairs is used as a hashmap + pairKeys = Common.keys(grid.pairs); + + // iterate over grid.pairs + for (var k = 0; k < pairKeys.length; k++) { + pair = grid.pairs[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 grid.pairs[pairKeys[k]]; + } + } + + return pairs; + }; + +})(); + + +/***/ }), +/* 12 */ +/***/ (function(module, exports, __webpack_require__) { + +/** +* The `Matter.Detector` module contains methods for detecting collisions given a set of pairs. +* +* @class Detector +*/ + +// TODO: speculative contacts + +var Detector = {}; + +module.exports = Detector; + +var SAT = __webpack_require__(13); +var Pair = __webpack_require__(9); +var Bounds = __webpack_require__(1); + +(function() { + + /** + * Finds all collisions given a list of pairs. + * @method collisions + * @param {pair[]} broadphasePairs + * @param {engine} engine + * @return {array} collisions + */ + Detector.collisions = function(broadphasePairs, engine) { + var collisions = [], + pairsTable = engine.pairs.table; + + // @if DEBUG + var metrics = engine.metrics; + // @endif + + for (var i = 0; i < broadphasePairs.length; i++) { + var bodyA = broadphasePairs[i][0], + bodyB = broadphasePairs[i][1]; + + if ((bodyA.isStatic || bodyA.isSleeping) && (bodyB.isStatic || bodyB.isSleeping)) + continue; + + if (!Detector.canCollide(bodyA.collisionFilter, bodyB.collisionFilter)) + continue; + + // @if DEBUG + metrics.midphaseTests += 1; + // @endif + + // mid phase + if (Bounds.overlaps(bodyA.bounds, bodyB.bounds)) { + for (var j = bodyA.parts.length > 1 ? 1 : 0; j < bodyA.parts.length; j++) { + var partA = bodyA.parts[j]; + + for (var k = bodyB.parts.length > 1 ? 1 : 0; k < bodyB.parts.length; k++) { + var partB = bodyB.parts[k]; + + if ((partA === bodyA && partB === bodyB) || Bounds.overlaps(partA.bounds, partB.bounds)) { + // find a previous collision we could reuse + var pairId = Pair.id(partA, partB), + pair = pairsTable[pairId], + previousCollision; + + if (pair && pair.isActive) { + previousCollision = pair.collision; + } else { + previousCollision = null; + } + + // narrow phase + var collision = SAT.collides(partA, partB, previousCollision); + + // @if DEBUG + metrics.narrowphaseTests += 1; + if (collision.reused) + metrics.narrowReuseCount += 1; + // @endif + + if (collision.collided) { + collisions.push(collision); + // @if DEBUG + metrics.narrowDetections += 1; + // @endif + } + } + } + } + } + } + + 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; + }; + +})(); + + +/***/ }), +/* 13 */ +/***/ (function(module, exports, __webpack_require__) { + +/** +* The `Matter.SAT` module contains methods for detecting collisions using the Separating Axis Theorem. +* +* @class SAT +*/ + +// TODO: true circles and curves + +var SAT = {}; + +module.exports = SAT; + +var Vertices = __webpack_require__(3); +var Vector = __webpack_require__(2); + +(function() { + + /** + * Detect collision between two bodies using the Separating Axis Theorem. + * @method collides + * @param {body} bodyA + * @param {body} bodyB + * @param {collision} previousCollision + * @return {collision} collision + */ + SAT.collides = function(bodyA, bodyB, previousCollision) { + var overlapAB, + overlapBA, + minOverlap, + collision, + canReusePrevCol = false; + + if (previousCollision) { + // estimate total motion + var parentA = bodyA.parent, + parentB = bodyB.parent, + motion = parentA.speed * parentA.speed + parentA.angularSpeed * parentA.angularSpeed + + parentB.speed * parentB.speed + parentB.angularSpeed * parentB.angularSpeed; + + // we may be able to (partially) reuse collision result + // but only safe if collision was resting + canReusePrevCol = previousCollision && previousCollision.collided && motion < 0.2; + + // reuse collision object + collision = previousCollision; + } else { + collision = { collided: false, bodyA: bodyA, bodyB: bodyB }; + } + + if (previousCollision && canReusePrevCol) { + // if we can reuse the collision result + // we only need to test the previously found axis + var axisBodyA = collision.axisBody, + axisBodyB = axisBodyA === bodyA ? bodyB : bodyA, + axes = [axisBodyA.axes[previousCollision.axisNumber]]; + + minOverlap = SAT._overlapAxes(axisBodyA.vertices, axisBodyB.vertices, axes); + collision.reused = true; + + if (minOverlap.overlap <= 0) { + collision.collided = false; + return collision; + } + } else { + // if we can't reuse a result, perform a full SAT test + + overlapAB = SAT._overlapAxes(bodyA.vertices, bodyB.vertices, bodyA.axes); + + if (overlapAB.overlap <= 0) { + collision.collided = false; + return collision; + } + + overlapBA = SAT._overlapAxes(bodyB.vertices, bodyA.vertices, bodyB.axes); + + if (overlapBA.overlap <= 0) { + collision.collided = false; + return collision; + } + + if (overlapAB.overlap < overlapBA.overlap) { + minOverlap = overlapAB; + collision.axisBody = bodyA; + } else { + minOverlap = overlapBA; + collision.axisBody = bodyB; + } + + // important for reuse later + collision.axisNumber = minOverlap.axisNumber; + } + + collision.bodyA = bodyA.id < bodyB.id ? bodyA : bodyB; + collision.bodyB = bodyA.id < bodyB.id ? bodyB : bodyA; + collision.collided = true; + collision.depth = minOverlap.overlap; + collision.parentA = collision.bodyA.parent; + collision.parentB = collision.bodyB.parent; + + bodyA = collision.bodyA; + bodyB = collision.bodyB; + + // ensure normal is facing away from bodyA + if (Vector.dot(minOverlap.axis, Vector.sub(bodyB.position, bodyA.position)) < 0) { + collision.normal = { + x: minOverlap.axis.x, + y: minOverlap.axis.y + }; + } else { + collision.normal = { + x: -minOverlap.axis.x, + y: -minOverlap.axis.y + }; + } + + collision.tangent = Vector.perp(collision.normal); + + collision.penetration = collision.penetration || {}; + collision.penetration.x = collision.normal.x * collision.depth; + collision.penetration.y = collision.normal.y * collision.depth; + + // find support points, there is always either exactly one or two + var verticesB = SAT._findSupports(bodyA, bodyB, collision.normal), + supports = []; + + // find the supports from bodyB that are inside bodyA + if (Vertices.contains(bodyA.vertices, verticesB[0])) + supports.push(verticesB[0]); + + if (Vertices.contains(bodyA.vertices, verticesB[1])) + supports.push(verticesB[1]); + + // find the supports from bodyA that are inside bodyB + if (supports.length < 2) { + var verticesA = SAT._findSupports(bodyB, bodyA, Vector.neg(collision.normal)); + + if (Vertices.contains(bodyB.vertices, verticesA[0])) + supports.push(verticesA[0]); + + if (supports.length < 2 && Vertices.contains(bodyB.vertices, verticesA[1])) + supports.push(verticesA[1]); + } + + // account for the edge case of overlapping but no vertex containment + if (supports.length < 1) + supports = [verticesB[0]]; + + collision.supports = supports; + + return collision; + }; + + /** + * Find the overlap between two sets of vertices. + * @method _overlapAxes + * @private + * @param {} verticesA + * @param {} verticesB + * @param {} axes + * @return result + */ + SAT._overlapAxes = function(verticesA, verticesB, axes) { + var projectionA = Vector._temp[0], + projectionB = Vector._temp[1], + result = { overlap: Number.MAX_VALUE }, + overlap, + axis; + + for (var i = 0; i < axes.length; i++) { + axis = axes[i]; + + SAT._projectToAxis(projectionA, verticesA, axis); + SAT._projectToAxis(projectionB, verticesB, axis); + + overlap = Math.min(projectionA.max - projectionB.min, projectionB.max - projectionA.min); + + if (overlap <= 0) { + result.overlap = overlap; + return result; + } + + if (overlap < result.overlap) { + result.overlap = overlap; + result.axis = axis; + result.axisNumber = i; + } + } + + return result; + }; + + /** + * Projects vertices on an axis and returns an interval. + * @method _projectToAxis + * @private + * @param {} projection + * @param {} vertices + * @param {} axis + */ + SAT._projectToAxis = function(projection, vertices, axis) { + var min = Vector.dot(vertices[0], axis), + max = min; + + for (var i = 1; i < vertices.length; i += 1) { + var dot = Vector.dot(vertices[i], axis); + + 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 {} bodyA + * @param {} bodyB + * @param {} normal + * @return [vector] + */ + SAT._findSupports = function(bodyA, bodyB, normal) { + var nearestDistance = Number.MAX_VALUE, + vertexToBody = Vector._temp[0], + vertices = bodyB.vertices, + bodyAPosition = bodyA.position, + distance, + vertex, + vertexA, + vertexB; + + // find closest vertex on bodyB + for (var i = 0; i < vertices.length; i++) { + vertex = vertices[i]; + vertexToBody.x = vertex.x - bodyAPosition.x; + vertexToBody.y = vertex.y - bodyAPosition.y; + distance = -Vector.dot(normal, vertexToBody); + + if (distance < nearestDistance) { + nearestDistance = distance; + vertexA = vertex; + } + } + + // find next closest vertex using the two connected to it + var prevIndex = vertexA.index - 1 >= 0 ? vertexA.index - 1 : vertices.length - 1; + vertex = vertices[prevIndex]; + vertexToBody.x = vertex.x - bodyAPosition.x; + vertexToBody.y = vertex.y - bodyAPosition.y; + nearestDistance = -Vector.dot(normal, vertexToBody); + vertexB = vertex; + + var nextIndex = (vertexA.index + 1) % vertices.length; + vertex = vertices[nextIndex]; + vertexToBody.x = vertex.x - bodyAPosition.x; + vertexToBody.y = vertex.y - bodyAPosition.y; + distance = -Vector.dot(normal, vertexToBody); + if (distance < nearestDistance) { + vertexB = vertex; + } + + return [vertexA, vertexB]; + }; + +})(); + + +/***/ }), +/* 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.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); + element.addEventListener('mousedown', mouse.mousedown); + element.addEventListener('mouseup', mouse.mouseup); + + element.addEventListener('mousewheel', mouse.mousewheel); + element.addEventListener('DOMMouseScroll', mouse.mousewheel); + + element.addEventListener('touchmove', mouse.mousemove); + element.addEventListener('touchstart', mouse.mousedown); + element.addEventListener('touchend', mouse.mouseup); + }; + + /** + * 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.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; + } + }; + +})(); + + +/***/ }), +/* 16 */ +/***/ (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__(6); +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 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 + * @param {object} [options] + * @return {body} A new trapezoid body + */ + Bodies.trapezoid = function(x, y, width, height, slope, options) { + options = options || {}; + + 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)); + }; + + /** + * Creates a body using the supplied vertices (or an array containing multiple sets of vertices). + * If the vertices are convex, they will pass through as supplied. + * Otherwise if the vertices are concave, they will be decomposed if [poly-decomp.js](https://github.com/schteppe/poly-decomp.js) is available. + * Note that this process is not guaranteed to support complex sets of vertices (e.g. those with holes may fail). + * By default the decomposition will discard collinear edges (to improve performance). + * It can also optionally discard any parts that have an area less than `minimumArea`. + * If the vertices can not be decomposed, the result will fall back to using the convex hull. + * The options parameter is an object that 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 [[vector]] vertexSets + * @param {object} [options] + * @param {bool} [flagInternal=false] + * @param {number} [removeCollinear=0.01] + * @param {number} [minimumArea=10] + * @return {body} + */ + Bodies.fromVertices = function(x, y, vertexSets, options, flagInternal, removeCollinear, minimumArea) { + var globals = typeof global !== 'undefined' ? global : window, + decomp, + body, + parts, + isConvex, + vertices, + i, + j, + k, + v, + z; + + try { + decomp = globals.decomp || __webpack_require__(27); + } catch (e) { + // decomp is undefined + } + + options = options || {}; + parts = []; + + flagInternal = typeof flagInternal !== 'undefined' ? flagInternal : false; + removeCollinear = typeof removeCollinear !== 'undefined' ? removeCollinear : 0.01; + minimumArea = typeof minimumArea !== 'undefined' ? minimumArea : 10; + + if (!decomp) { + Common.warn('Bodies.fromVertices: poly-decomp.js required. Could not decompose vertices. Fallback to convex hull.'); + } + + // 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); + + if (isConvex || !decomp) { + 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); + + // 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)); + Body.setPosition(body, { x: x, y: y }); + + return body; + } else { + return parts[0]; + } + }; + +})(); + + +/***/ }), +/* 17 */ +/***/ (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` + * - 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 = /^\*|[\^~]?\d+\.\d+\.\d+(-[0-9A-Za-z-]+)?$/; + + if (!pattern.test(range)) { + Common.warn('Plugin.versionParse:', range, 'is not a valid version or range.'); + } + + var identifiers = range.split('-'); + range = identifiers[0]; + + var isRange = isNaN(Number(range[0])), + version = isRange ? range.substr(1) : range, + parts = Common.map(version.split('.'), function(part) { + return Number(part); + }); + + return { + isRange: isRange, + version: version, + range: range, + operator: isRange ? range[0] : '', + parts: parts, + prerelease: identifiers[1], + number: parts[0] * 1e8 + parts[1] * 1e4 + parts[2] + }; + }; + + /** + * 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 rangeParsed = Plugin.versionParse(range), + rangeParts = rangeParsed.parts, + versionParsed = Plugin.versionParse(version), + versionParts = versionParsed.parts; + + if (rangeParsed.isRange) { + if (rangeParsed.operator === '*' || version === '*') { + return true; + } + + if (rangeParsed.operator === '~') { + return versionParts[0] === rangeParts[0] && versionParts[1] === rangeParts[1] && versionParts[2] >= rangeParts[2]; + } + + if (rangeParsed.operator === '^') { + if (rangeParts[0] > 0) { + return versionParts[0] === rangeParts[0] && versionParsed.number >= rangeParsed.number; + } + + if (rangeParts[1] > 0) { + return versionParts[1] === rangeParts[1] && versionParts[2] >= rangeParts[2]; + } + + return versionParts[2] === rangeParts[2]; + } + } + + return version === range || version === '*'; + }; + +})(); + + +/***/ }), +/* 18 */ +/***/ (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 { + id: Contact.id(vertex), + vertex: vertex, + normalImpulse: 0, + tangentImpulse: 0 + }; + }; + + /** + * Generates a contact id. + * @method id + * @param {vertex} vertex + * @return {string} Unique contactID + */ + Contact.id = function(vertex) { + return vertex.body.id + '_' + vertex.index; + }; + +})(); + + +/***/ }), +/* 19 */ +/***/ (function(module, exports, __webpack_require__) { + +/** +* The `Matter.World` module contains methods for creating and manipulating the world composite. +* A `Matter.World` is a `Matter.Composite` body, which is a collection of `Matter.Body`, `Matter.Constraint` and other `Matter.Composite`. +* A `Matter.World` has a few additional properties including `gravity` and `bounds`. +* It is important to use the functions in the `Matter.Composite` module to modify the world composite, rather than directly modifying its properties. +* There are also a few methods here that alias those in `Matter.Composite` for easier readability. +* +* See the included usage [examples](https://github.com/liabru/matter-js/tree/master/examples). +* +* @class World +* @extends Composite +*/ + +var World = {}; + +module.exports = World; + +var Composite = __webpack_require__(5); +var Constraint = __webpack_require__(8); +var Common = __webpack_require__(0); + +(function() { + + /** + * Creates a new world composite. The options parameter is an object that specifies any properties you wish to override the defaults. + * See the properties section below for detailed information on what you can pass via the `options` object. + * @method create + * @constructor + * @param {} options + * @return {world} A new world + */ + World.create = function(options) { + var composite = Composite.create(); + + var defaults = { + label: 'World', + gravity: { + x: 0, + y: 1, + scale: 0.001 + }, + bounds: { + min: { x: -Infinity, y: -Infinity }, + max: { x: Infinity, y: Infinity } + } + }; + + return Common.extend(composite, defaults, options); + }; + + /* + * + * Properties Documentation + * + */ + + /** + * The gravity to apply on the world. + * + * @property gravity + * @type object + */ + + /** + * The gravity x component. + * + * @property gravity.x + * @type object + * @default 0 + */ + + /** + * The gravity y component. + * + * @property gravity.y + * @type object + * @default 1 + */ + + /** + * The gravity scale factor. + * + * @property gravity.scale + * @type object + * @default 0.001 + */ + + /** + * A `Bounds` object that defines the world bounds for collision detection. + * + * @property bounds + * @type bounds + * @default { min: { x: -Infinity, y: -Infinity }, max: { x: Infinity, y: Infinity } } + */ + + // World is a Composite body + // see src/module/Outro.js for these aliases: + + /** + * An alias for Composite.add + * @method add + * @param {world} world + * @param {} object + * @return {composite} The original world with the objects added + */ + + /** + * An alias for Composite.remove + * @method remove + * @param {world} world + * @param {} object + * @param {boolean} [deep=false] + * @return {composite} The original world with the objects removed + */ + + /** + * An alias for Composite.clear + * @method clear + * @param {world} world + * @param {boolean} keepStatic + */ + + /** + * An alias for Composite.addComposite + * @method addComposite + * @param {world} world + * @param {composite} composite + * @return {world} The original world with the objects from composite added + */ + + /** + * An alias for Composite.addBody + * @method addBody + * @param {world} world + * @param {body} body + * @return {world} The original world with the body added + */ + + /** + * An alias for Composite.addConstraint + * @method addConstraint + * @param {world} world + * @param {constraint} constraint + * @return {world} The original world with the constraint added + */ + +})(); + + +/***/ }), +/* 20 */ +/***/ (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() { + + Pairs._pairMaxIdleLife = 1000; + + /** + * 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, + pairsTable = pairs.table, + collisionStart = pairs.collisionStart, + collisionEnd = pairs.collisionEnd, + collisionActive = pairs.collisionActive, + collision, + pairId, + pair, + i; + + // clear collision state arrays, but maintain old reference + collisionStart.length = 0; + collisionEnd.length = 0; + collisionActive.length = 0; + + for (i = 0; i < pairsList.length; i++) { + pairsList[i].confirmedActive = false; + } + + for (i = 0; i < collisions.length; i++) { + collision = collisions[i]; + + if (collision.collided) { + pairId = Pair.id(collision.bodyA, collision.bodyB); + + pair = pairsTable[pairId]; + + 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[pairId] = pair; + + // push the new pair + collisionStart.push(pair); + pairsList.push(pair); + } + } + } + + // deactivate previously active pairs that are now inactive + for (i = 0; i < pairsList.length; i++) { + pair = pairsList[i]; + if (pair.isActive && !pair.confirmedActive) { + Pair.setActive(pair, false, timestamp); + collisionEnd.push(pair); + } + } + }; + + /** + * Finds and removes pairs that have been inactive for a set amount of time. + * @method removeOld + * @param {object} pairs + * @param {number} timestamp + */ + Pairs.removeOld = function(pairs, timestamp) { + var pairsList = pairs.list, + pairsTable = pairs.table, + indexesToRemove = [], + pair, + collision, + pairIndex, + i; + + for (i = 0; i < pairsList.length; i++) { + pair = pairsList[i]; + collision = pair.collision; + + // never remove sleeping pairs + if (collision.bodyA.isSleeping || collision.bodyB.isSleeping) { + pair.timeUpdated = timestamp; + continue; + } + + // if pair is inactive for too long, mark it to be removed + if (timestamp - pair.timeUpdated > Pairs._pairMaxIdleLife) { + indexesToRemove.push(i); + } + } + + // remove marked pairs + for (i = 0; i < indexesToRemove.length; i++) { + pairIndex = indexesToRemove[i] - i; + pair = pairsList[pairIndex]; + delete pairsTable[pair.id]; + pairsList.splice(pairIndex, 1); + } + }; + + /** + * 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; + }; + +})(); + + +/***/ }), +/* 21 */ +/***/ (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 Vector = __webpack_require__(2); +var Common = __webpack_require__(0); +var Bounds = __webpack_require__(1); + +(function() { + + Resolver._restingThresh = 4; + Resolver._restingThreshTangent = 6; + Resolver._positionDampen = 0.9; + Resolver._positionWarming = 0.8; + Resolver._frictionNormalMultiplier = 5; + + /** + * Prepare pairs for position solving. + * @method preSolvePosition + * @param {pair[]} pairs + */ + Resolver.preSolvePosition = function(pairs) { + var i, + pair, + activeCount; + + // find total contacts on each body + for (i = 0; i < pairs.length; 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} timeScale + */ + Resolver.solvePosition = function(pairs, timeScale) { + var i, + pair, + collision, + bodyA, + bodyB, + normal, + bodyBtoA, + contactShare, + positionImpulse, + contactCount = {}, + tempA = Vector._temp[0], + tempB = Vector._temp[1], + tempC = Vector._temp[2], + tempD = Vector._temp[3]; + + // find impulses required to resolve penetration + for (i = 0; i < pairs.length; 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 + bodyBtoA = Vector.sub(Vector.add(bodyB.positionImpulse, bodyB.position, tempA), + Vector.add(bodyA.positionImpulse, + Vector.sub(bodyB.position, collision.penetration, tempB), tempC), tempD); + + pair.separation = Vector.dot(normal, bodyBtoA); + } + + for (i = 0; i < pairs.length; 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) * timeScale; + + if (bodyA.isStatic || bodyB.isStatic) + positionImpulse *= 2; + + if (!(bodyA.isStatic || bodyA.isSleeping)) { + contactShare = Resolver._positionDampen / bodyA.totalContacts; + bodyA.positionImpulse.x += normal.x * positionImpulse * contactShare; + bodyA.positionImpulse.y += normal.y * positionImpulse * contactShare; + } + + if (!(bodyB.isStatic || bodyB.isSleeping)) { + contactShare = Resolver._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) { + for (var i = 0; i < bodies.length; i++) { + var body = bodies[i]; + + // reset contact count + body.totalContacts = 0; + + if (body.positionImpulse.x !== 0 || body.positionImpulse.y !== 0) { + // update body geometry + for (var j = 0; j < body.parts.length; j++) { + var part = body.parts[j]; + Vertices.translate(part.vertices, body.positionImpulse); + Bounds.update(part.bounds, part.vertices, body.velocity); + part.position.x += body.positionImpulse.x; + part.position.y += body.positionImpulse.y; + } + + // move the body without changing velocity + body.positionPrev.x += body.positionImpulse.x; + body.positionPrev.y += body.positionImpulse.y; + + if (Vector.dot(body.positionImpulse, body.velocity) < 0) { + // reset cached impulse if the body has velocity along it + body.positionImpulse.x = 0; + body.positionImpulse.y = 0; + } else { + // warm the next iteration + body.positionImpulse.x *= Resolver._positionWarming; + body.positionImpulse.y *= Resolver._positionWarming; + } + } + } + }; + + /** + * Prepare pairs for velocity solving. + * @method preSolveVelocity + * @param {pair[]} pairs + */ + Resolver.preSolveVelocity = function(pairs) { + var i, + j, + pair, + contacts, + collision, + bodyA, + bodyB, + normal, + tangent, + contact, + contactVertex, + normalImpulse, + tangentImpulse, + offset, + impulse = Vector._temp[0], + tempA = Vector._temp[1]; + + for (i = 0; i < pairs.length; i++) { + pair = pairs[i]; + + if (!pair.isActive || pair.isSensor) + continue; + + contacts = pair.activeContacts; + collision = pair.collision; + bodyA = collision.parentA; + bodyB = collision.parentB; + normal = collision.normal; + tangent = collision.tangent; + + // resolve each contact + for (j = 0; j < contacts.length; j++) { + contact = contacts[j]; + contactVertex = contact.vertex; + normalImpulse = contact.normalImpulse; + tangentImpulse = contact.tangentImpulse; + + if (normalImpulse !== 0 || tangentImpulse !== 0) { + // total impulse from contact + impulse.x = (normal.x * normalImpulse) + (tangent.x * tangentImpulse); + impulse.y = (normal.y * normalImpulse) + (tangent.y * tangentImpulse); + + // apply impulse from contact + if (!(bodyA.isStatic || bodyA.isSleeping)) { + offset = Vector.sub(contactVertex, bodyA.position, tempA); + bodyA.positionPrev.x += impulse.x * bodyA.inverseMass; + bodyA.positionPrev.y += impulse.y * bodyA.inverseMass; + bodyA.anglePrev += Vector.cross(offset, impulse) * bodyA.inverseInertia; + } + + if (!(bodyB.isStatic || bodyB.isSleeping)) { + offset = Vector.sub(contactVertex, bodyB.position, tempA); + bodyB.positionPrev.x -= impulse.x * bodyB.inverseMass; + bodyB.positionPrev.y -= impulse.y * bodyB.inverseMass; + bodyB.anglePrev -= Vector.cross(offset, impulse) * bodyB.inverseInertia; + } + } + } + } + }; + + /** + * Find a solution for pair velocities. + * @method solveVelocity + * @param {pair[]} pairs + * @param {number} timeScale + */ + Resolver.solveVelocity = function(pairs, timeScale) { + var timeScaleSquared = timeScale * timeScale, + impulse = Vector._temp[0], + tempA = Vector._temp[1], + tempB = Vector._temp[2], + tempC = Vector._temp[3], + tempD = Vector._temp[4], + tempE = Vector._temp[5]; + + for (var i = 0; i < pairs.length; i++) { + var pair = pairs[i]; + + if (!pair.isActive || pair.isSensor) + continue; + + var collision = pair.collision, + bodyA = collision.parentA, + bodyB = collision.parentB, + normal = collision.normal, + tangent = collision.tangent, + contacts = pair.activeContacts, + contactShare = 1 / contacts.length; + + // update body velocities + bodyA.velocity.x = bodyA.position.x - bodyA.positionPrev.x; + bodyA.velocity.y = bodyA.position.y - bodyA.positionPrev.y; + bodyB.velocity.x = bodyB.position.x - bodyB.positionPrev.x; + bodyB.velocity.y = bodyB.position.y - bodyB.positionPrev.y; + bodyA.angularVelocity = bodyA.angle - bodyA.anglePrev; + bodyB.angularVelocity = bodyB.angle - bodyB.anglePrev; + + // resolve each contact + for (var j = 0; j < contacts.length; j++) { + var contact = contacts[j], + contactVertex = contact.vertex, + offsetA = Vector.sub(contactVertex, bodyA.position, tempA), + offsetB = Vector.sub(contactVertex, bodyB.position, tempB), + velocityPointA = Vector.add(bodyA.velocity, Vector.mult(Vector.perp(offsetA), bodyA.angularVelocity), tempC), + velocityPointB = Vector.add(bodyB.velocity, Vector.mult(Vector.perp(offsetB), bodyB.angularVelocity), tempD), + relativeVelocity = Vector.sub(velocityPointA, velocityPointB, tempE), + normalVelocity = Vector.dot(normal, relativeVelocity); + + var tangentVelocity = Vector.dot(tangent, relativeVelocity), + tangentSpeed = Math.abs(tangentVelocity), + tangentVelocityDirection = Common.sign(tangentVelocity); + + // raw impulses + var normalImpulse = (1 + pair.restitution) * normalVelocity, + normalForce = Common.clamp(pair.separation + normalVelocity, 0, 1) * Resolver._frictionNormalMultiplier; + + // coulomb friction + var tangentImpulse = tangentVelocity, + maxFriction = Infinity; + + if (tangentSpeed > pair.friction * pair.frictionStatic * normalForce * timeScaleSquared) { + maxFriction = tangentSpeed; + tangentImpulse = Common.clamp( + pair.friction * tangentVelocityDirection * timeScaleSquared, + -maxFriction, maxFriction + ); + } + + // modify impulses accounting for mass, inertia and offset + var oAcN = Vector.cross(offsetA, normal), + oBcN = Vector.cross(offsetB, normal), + share = contactShare / (bodyA.inverseMass + bodyB.inverseMass + bodyA.inverseInertia * oAcN * oAcN + bodyB.inverseInertia * oBcN * oBcN); + + normalImpulse *= share; + tangentImpulse *= share; + + // handle high velocity and resting collisions separately + if (normalVelocity < 0 && normalVelocity * normalVelocity > Resolver._restingThresh * timeScaleSquared) { + // 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 = Math.min(contact.normalImpulse + normalImpulse, 0); + normalImpulse = contact.normalImpulse - contactNormalImpulse; + } + + // handle high velocity and resting collisions separately + if (tangentVelocity * tangentVelocity > Resolver._restingThreshTangent * timeScaleSquared) { + // 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 = Common.clamp(contact.tangentImpulse + tangentImpulse, -maxFriction, maxFriction); + tangentImpulse = contact.tangentImpulse - contactTangentImpulse; + } + + // total impulse from contact + impulse.x = (normal.x * normalImpulse) + (tangent.x * tangentImpulse); + impulse.y = (normal.y * normalImpulse) + (tangent.y * tangentImpulse); + + // apply impulse from contact + if (!(bodyA.isStatic || bodyA.isSleeping)) { + bodyA.positionPrev.x += impulse.x * bodyA.inverseMass; + bodyA.positionPrev.y += impulse.y * bodyA.inverseMass; + bodyA.anglePrev += Vector.cross(offsetA, impulse) * bodyA.inverseInertia; + } + + if (!(bodyB.isStatic || bodyB.isSleeping)) { + bodyB.positionPrev.x -= impulse.x * bodyB.inverseMass; + bodyB.positionPrev.y -= impulse.y * bodyB.inverseMass; + bodyB.anglePrev -= Vector.cross(offsetB, impulse) * bodyB.inverseInertia; + } + } + } + }; + +})(); + + +/***/ }), +/* 22 */ +/***/ (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 World = __webpack_require__(19); +var Sleeping = __webpack_require__(7); +var Resolver = __webpack_require__(21); +var Render = __webpack_require__(10); +var Pairs = __webpack_require__(20); +var Metrics = __webpack_require__(23); +var Grid = __webpack_require__(11); +var Events = __webpack_require__(4); +var Composite = __webpack_require__(5); +var Constraint = __webpack_require__(8); +var Common = __webpack_require__(0); +var Body = __webpack_require__(6); + +(function() { + + /** + * Creates a new engine. The options parameter is an object that specifies any properties you wish to override the defaults. + * All properties have default values, and many are pre-calculated automatically based on other properties. + * See the properties section below for detailed information on what you can pass via the `options` object. + * @method create + * @param {object} [options] + * @return {engine} engine + */ + Engine.create = function(element, options) { + // options may be passed as the first (and only) argument + options = Common.isElement(element) ? options : element; + element = Common.isElement(element) ? element : null; + options = options || {}; + + if (element || options.render) { + Common.warn('Engine.create: engine.render is deprecated (see docs)'); + } + + var defaults = { + positionIterations: 6, + velocityIterations: 4, + constraintIterations: 2, + enableSleeping: false, + events: [], + plugin: {}, + timing: { + timestamp: 0, + timeScale: 1 + }, + broadphase: { + controller: Grid + } + }; + + var engine = Common.extend(defaults, options); + + // @deprecated + if (element || engine.render) { + var renderDefaults = { + element: element, + controller: Render + }; + + engine.render = Common.extend(renderDefaults, engine.render); + } + + // @deprecated + if (engine.render && engine.render.controller) { + engine.render = engine.render.controller.create(engine.render); + } + + // @deprecated + if (engine.render) { + engine.render.engine = engine; + } + + engine.world = options.world || World.create(engine.world); + engine.pairs = Pairs.create(); + engine.broadphase = engine.broadphase.controller.create(engine.broadphase); + engine.metrics = engine.metrics || { extended: false }; + + // @if DEBUG + engine.metrics = Metrics.create(engine.metrics); + // @endif + + return engine; + }; + + /** + * Moves the simulation forward in time by `delta` ms. + * The `correction` argument is an optional `Number` that specifies the time correction factor to apply to the update. + * This can help improve the accuracy of the simulation in cases where `delta` is changing between updates. + * The value of `correction` is defined as `delta / lastDelta`, i.e. the percentage change of `delta` over the last step. + * Therefore the value is always `1` (no correction) when `delta` constant (or when no correction is desired, which is the default). + * See the paper on Time Corrected Verlet for more information. + * + * Triggers `beforeUpdate` and `afterUpdate` events. + * Triggers `collisionStart`, `collisionActive` and `collisionEnd` events. + * @method update + * @param {engine} engine + * @param {number} [delta=16.666] + * @param {number} [correction=1] + */ + Engine.update = function(engine, delta, correction) { + delta = delta || 1000 / 60; + correction = correction || 1; + + var world = engine.world, + timing = engine.timing, + broadphase = engine.broadphase, + broadphasePairs = [], + i; + + // increment timestamp + timing.timestamp += delta * timing.timeScale; + + // create an event object + var event = { + timestamp: timing.timestamp + }; + + Events.trigger(engine, 'beforeUpdate', event); + + // get lists of all bodies and constraints, no matter what composites they are in + var allBodies = Composite.allBodies(world), + allConstraints = Composite.allConstraints(world); + + // @if DEBUG + // reset metrics logging + Metrics.reset(engine.metrics); + // @endif + + // if sleeping enabled, call the sleeping controller + if (engine.enableSleeping) + Sleeping.update(allBodies, timing.timeScale); + + // applies gravity to all bodies + Engine._bodiesApplyGravity(allBodies, world.gravity); + + // update all body position and rotation by integration + Engine._bodiesUpdate(allBodies, delta, timing.timeScale, correction, world.bounds); + + // update all constraints (first pass) + Constraint.preSolveAll(allBodies); + for (i = 0; i < engine.constraintIterations; i++) { + Constraint.solveAll(allConstraints, timing.timeScale); + } + Constraint.postSolveAll(allBodies); + + // broadphase pass: find potential collision pairs + if (broadphase.controller) { + // if world is dirty, we must flush the whole grid + if (world.isModified) + broadphase.controller.clear(broadphase); + + // update the grid buckets based on current bodies + broadphase.controller.update(broadphase, allBodies, engine, world.isModified); + broadphasePairs = broadphase.pairsList; + } else { + // if no broadphase set, we just pass all bodies + broadphasePairs = allBodies; + } + + // clear all composite modified flags + if (world.isModified) { + Composite.setModified(world, false, false, true); + } + + // narrowphase pass: find actual collisions, then create or update collision pairs + var collisions = broadphase.detector(broadphasePairs, engine); + + // update collision pairs + var pairs = engine.pairs, + timestamp = timing.timestamp; + Pairs.update(pairs, collisions, timestamp); + Pairs.removeOld(pairs, timestamp); + + // wake up bodies involved in collisions + if (engine.enableSleeping) + Sleeping.afterCollisions(pairs.list, timing.timeScale); + + // trigger collision events + if (pairs.collisionStart.length > 0) + Events.trigger(engine, 'collisionStart', { pairs: pairs.collisionStart }); + + // iteratively resolve position between collisions + Resolver.preSolvePosition(pairs.list); + for (i = 0; i < engine.positionIterations; i++) { + Resolver.solvePosition(pairs.list, timing.timeScale); + } + Resolver.postSolvePosition(allBodies); + + // update all constraints (second pass) + Constraint.preSolveAll(allBodies); + for (i = 0; i < engine.constraintIterations; i++) { + Constraint.solveAll(allConstraints, timing.timeScale); + } + Constraint.postSolveAll(allBodies); + + // iteratively resolve velocity between collisions + Resolver.preSolveVelocity(pairs.list); + for (i = 0; i < engine.velocityIterations; i++) { + Resolver.solveVelocity(pairs.list, timing.timeScale); + } + + // trigger collision events + if (pairs.collisionActive.length > 0) + Events.trigger(engine, 'collisionActive', { pairs: pairs.collisionActive }); + + if (pairs.collisionEnd.length > 0) + Events.trigger(engine, 'collisionEnd', { pairs: pairs.collisionEnd }); + + // @if DEBUG + // update metrics log + Metrics.update(engine.metrics, engine); + // @endif + + // clear force buffers + Engine._bodiesClearForces(allBodies); + + Events.trigger(engine, 'afterUpdate', event); + + return engine; + }; + + /** + * Merges two engines by keeping the configuration of `engineA` but replacing the world with the one from `engineB`. + * @method merge + * @param {engine} engineA + * @param {engine} engineB + */ + Engine.merge = function(engineA, engineB) { + Common.extend(engineA, engineB); + + if (engineB.world) { + engineA.world = engineB.world; + + Engine.clear(engineA); + + var bodies = Composite.allBodies(engineA.world); + + for (var i = 0; i < bodies.length; i++) { + var body = bodies[i]; + Sleeping.set(body, false); + body.id = Common.nextId(); + } + } + }; + + /** + * Clears the engine including the world, pairs and broadphase. + * @method clear + * @param {engine} engine + */ + Engine.clear = function(engine) { + var world = engine.world; + + Pairs.clear(engine.pairs); + + var broadphase = engine.broadphase; + if (broadphase.controller) { + var bodies = Composite.allBodies(world); + broadphase.controller.clear(broadphase); + broadphase.controller.update(broadphase, bodies, engine, true); + } + }; + + /** + * Zeroes the `body.force` and `body.torque` force buffers. + * @method _bodiesClearForces + * @private + * @param {body[]} bodies + */ + Engine._bodiesClearForces = function(bodies) { + for (var i = 0; i < bodies.length; i++) { + var body = bodies[i]; + + // reset force buffers + body.force.x = 0; + body.force.y = 0; + body.torque = 0; + } + }; + + /** + * Applys a mass dependant force to all given bodies. + * @method _bodiesApplyGravity + * @private + * @param {body[]} bodies + * @param {vector} gravity + */ + Engine._bodiesApplyGravity = function(bodies, gravity) { + var gravityScale = typeof gravity.scale !== 'undefined' ? gravity.scale : 0.001; + + if ((gravity.x === 0 && gravity.y === 0) || gravityScale === 0) { + return; + } + + for (var i = 0; i < bodies.length; i++) { + var body = bodies[i]; + + if (body.isStatic || body.isSleeping) + continue; + + // apply gravity + body.force.y += body.mass * gravity.y * gravityScale; + body.force.x += body.mass * gravity.x * gravityScale; + } + }; + + /** + * Applys `Body.update` to all given `bodies`. + * @method _bodiesUpdate + * @private + * @param {body[]} bodies + * @param {number} deltaTime + * The amount of time elapsed between updates + * @param {number} timeScale + * @param {number} correction + * The Verlet correction factor (deltaTime / lastDeltaTime) + * @param {bounds} worldBounds + */ + Engine._bodiesUpdate = function(bodies, deltaTime, timeScale, correction, worldBounds) { + for (var i = 0; i < bodies.length; i++) { + var body = bodies[i]; + + if (body.isStatic || body.isSleeping) + continue; + + Body.update(body, deltaTime, timeScale, correction); + } + }; + + /** + * An alias for `Runner.run`, see `Matter.Runner` for more information. + * @method run + * @param {engine} engine + */ + + /** + * Fired just before an update + * + * @event beforeUpdate + * @param {} event An event object + * @param {number} event.timestamp The engine.timing.timestamp of the event + * @param {} event.source The source object of the event + * @param {} event.name The name of the event + */ + + /** + * Fired after engine update and all collision events + * + * @event afterUpdate + * @param {} event An event object + * @param {number} event.timestamp The engine.timing.timestamp of the event + * @param {} event.source The source object of the event + * @param {} event.name The name of the event + */ + + /** + * Fired after engine update, provides a list of all pairs that have started to collide in the current tick (if any) + * + * @event collisionStart + * @param {} event An event object + * @param {} event.pairs List of affected pairs + * @param {number} event.timestamp The engine.timing.timestamp of the event + * @param {} event.source The source object of the event + * @param {} event.name The name of the event + */ + + /** + * Fired after engine update, provides a list of all pairs that are colliding in the current tick (if any) + * + * @event collisionActive + * @param {} event An event object + * @param {} event.pairs List of affected pairs + * @param {number} event.timestamp The engine.timing.timestamp of the event + * @param {} event.source The source object of the event + * @param {} event.name The name of the event + */ + + /** + * Fired after engine update, provides a list of all pairs that have ended collision in the current tick (if any) + * + * @event collisionEnd + * @param {} event An event object + * @param {} event.pairs List of affected pairs + * @param {number} event.timestamp The engine.timing.timestamp of the event + * @param {} event.source The source object of the event + * @param {} event.name The name of the event + */ + + /* + * + * Properties Documentation + * + */ + + /** + * An integer `Number` that specifies the number of position iterations to perform each update. + * The higher the value, the higher quality the simulation will be at the expense of performance. + * + * @property positionIterations + * @type number + * @default 6 + */ + + /** + * An integer `Number` that specifies the number of velocity iterations to perform each update. + * The higher the value, the higher quality the simulation will be at the expense of performance. + * + * @property velocityIterations + * @type number + * @default 4 + */ + + /** + * An integer `Number` that specifies the number of constraint iterations to perform each update. + * The higher the value, the higher quality the simulation will be at the expense of performance. + * The default value of `2` is usually very adequate. + * + * @property constraintIterations + * @type number + * @default 2 + */ + + /** + * A flag that specifies whether the engine should allow sleeping via the `Matter.Sleeping` module. + * Sleeping can improve stability and performance, but often at the expense of accuracy. + * + * @property enableSleeping + * @type boolean + * @default false + */ + + /** + * An `Object` containing properties regarding the timing systems of the engine. + * + * @property timing + * @type object + */ + + /** + * A `Number` that specifies the global scaling factor of time for all bodies. + * A value of `0` freezes the simulation. + * A value of `0.1` gives a slow-motion effect. + * A value of `1.2` gives a speed-up effect. + * + * @property timing.timeScale + * @type number + * @default 1 + */ + + /** + * A `Number` that specifies the current simulation-time in milliseconds starting from `0`. + * It is incremented on every `Engine.update` by the given `delta` argument. + * + * @property timing.timestamp + * @type number + * @default 0 + */ + + /** + * An instance of a `Render` controller. The default value is a `Matter.Render` instance created by `Engine.create`. + * One may also develop a custom renderer module based on `Matter.Render` and pass an instance of it to `Engine.create` via `options.render`. + * + * A minimal custom renderer object must define at least three functions: `create`, `clear` and `world` (see `Matter.Render`). + * It is also possible to instead pass the _module_ reference via `options.render.controller` and `Engine.create` will instantiate one for you. + * + * @property render + * @type render + * @deprecated see Demo.js for an example of creating a renderer + * @default a Matter.Render instance + */ + + /** + * An instance of a broadphase controller. The default value is a `Matter.Grid` instance created by `Engine.create`. + * + * @property broadphase + * @type grid + * @default a Matter.Grid instance + */ + + /** + * A `World` composite object that will contain all simulated bodies and constraints. + * + * @property world + * @type world + * @default a Matter.World instance + */ + + /** + * An object reserved for storing plugin-specific properties. + * + * @property plugin + * @type {} + */ + +})(); + + +/***/ }), +/* 23 */ +/***/ (function(module, exports, __webpack_require__) { + +// @if DEBUG +/** +* _Internal Class_, not generally used outside of the engine's internals. +* +*/ + +var Metrics = {}; + +module.exports = Metrics; + +var Composite = __webpack_require__(5); +var Common = __webpack_require__(0); + +(function() { + + /** + * Creates a new metrics. + * @method create + * @private + * @return {metrics} A new metrics + */ + Metrics.create = function(options) { + var defaults = { + extended: false, + narrowDetections: 0, + narrowphaseTests: 0, + narrowReuse: 0, + narrowReuseCount: 0, + midphaseTests: 0, + broadphaseTests: 0, + narrowEff: 0.0001, + midEff: 0.0001, + broadEff: 0.0001, + collisions: 0, + buckets: 0, + bodies: 0, + pairs: 0 + }; + + return Common.extend(defaults, false, options); + }; + + /** + * Resets metrics. + * @method reset + * @private + * @param {metrics} metrics + */ + Metrics.reset = function(metrics) { + if (metrics.extended) { + metrics.narrowDetections = 0; + metrics.narrowphaseTests = 0; + metrics.narrowReuse = 0; + metrics.narrowReuseCount = 0; + metrics.midphaseTests = 0; + metrics.broadphaseTests = 0; + metrics.narrowEff = 0; + metrics.midEff = 0; + metrics.broadEff = 0; + metrics.collisions = 0; + metrics.buckets = 0; + metrics.pairs = 0; + metrics.bodies = 0; + } + }; + + /** + * Updates metrics. + * @method update + * @private + * @param {metrics} metrics + * @param {engine} engine + */ + Metrics.update = function(metrics, engine) { + if (metrics.extended) { + var world = engine.world, + bodies = Composite.allBodies(world); + + metrics.collisions = metrics.narrowDetections; + metrics.pairs = engine.pairs.list.length; + metrics.bodies = bodies.length; + metrics.midEff = (metrics.narrowDetections / (metrics.midphaseTests || 1)).toFixed(2); + metrics.narrowEff = (metrics.narrowDetections / (metrics.narrowphaseTests || 1)).toFixed(2); + metrics.broadEff = (1 - (metrics.broadphaseTests / (bodies.length || 1))).toFixed(2); + metrics.narrowReuse = (metrics.narrowReuseCount / (metrics.narrowphaseTests || 1)).toFixed(2); + //var broadphase = engine.broadphase[engine.broadphase.current]; + //if (broadphase.instance) + // metrics.buckets = Common.keys(broadphase.instance.buckets).length; + } + }; + +})(); +// @endif + + +/***/ }), +/* 24 */ +/***/ (function(module, exports, __webpack_require__) { + +var Matter = module.exports = __webpack_require__(25); + +Matter.Body = __webpack_require__(6); +Matter.Composite = __webpack_require__(5); +Matter.World = __webpack_require__(19); + +Matter.Contact = __webpack_require__(18); +Matter.Detector = __webpack_require__(12); +Matter.Grid = __webpack_require__(11); +Matter.Pairs = __webpack_require__(20); +Matter.Pair = __webpack_require__(9); +Matter.Query = __webpack_require__(26); +Matter.Resolver = __webpack_require__(21); +Matter.SAT = __webpack_require__(13); + +Matter.Constraint = __webpack_require__(8); +Matter.MouseConstraint = __webpack_require__(28); + +Matter.Common = __webpack_require__(0); +Matter.Engine = __webpack_require__(22); +Matter.Events = __webpack_require__(4); +Matter.Mouse = __webpack_require__(14); +Matter.Runner = __webpack_require__(29); +Matter.Sleeping = __webpack_require__(7); +Matter.Plugin = __webpack_require__(17); + +// @if DEBUG +Matter.Metrics = __webpack_require__(23); +// @endif + +Matter.Bodies = __webpack_require__(16); +Matter.Composites = __webpack_require__(30); + +Matter.Axes = __webpack_require__(15); +Matter.Bounds = __webpack_require__(1); +Matter.Svg = __webpack_require__(31); +Matter.Vector = __webpack_require__(2); +Matter.Vertices = __webpack_require__(3); + +Matter.Render = __webpack_require__(10); +Matter.RenderPixi = __webpack_require__(32); + +// aliases + +Matter.World.add = Matter.Composite.add; +Matter.World.remove = Matter.Composite.remove; +Matter.World.addComposite = Matter.Composite.addComposite; +Matter.World.addBody = Matter.Composite.addBody; +Matter.World.addConstraint = Matter.Composite.addConstraint; +Matter.World.clear = Matter.Composite.clear; +Matter.Engine.run = Matter.Runner.run; + + +/***/ }), +/* 25 */ +/***/ (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__(17); +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.15.0" : 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); + }; + +})(); + + +/***/ }), +/* 26 */ +/***/ (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 SAT = __webpack_require__(13); +var Bounds = __webpack_require__(1); +var Bodies = __webpack_require__(16); +var Vertices = __webpack_require__(3); + +(function() { + + /** + * Returns a list of collisions between `body` and `bodies`. + * @method collides + * @param {body} body + * @param {body[]} bodies + * @return {object[]} Collisions + */ + Query.collides = function(body, bodies) { + var collisions = []; + + for (var i = 0; i < bodies.length; i++) { + var bodyA = bodies[i]; + + if (Bounds.overlaps(bodyA.bounds, body.bounds)) { + for (var j = bodyA.parts.length === 1 ? 0 : 1; j < bodyA.parts.length; j++) { + var part = bodyA.parts[j]; + + if (Bounds.overlaps(part.bounds, body.bounds)) { + var collision = SAT.collides(part, body); + + if (collision.collided) { + 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 {object[]} 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; + }; + +})(); + + +/***/ }), +/* 27 */ +/***/ (function(module, exports) { + +if(typeof __WEBPACK_EXTERNAL_MODULE__27__ === 'undefined') {var e = new Error("Cannot find module 'undefined'"); e.code = 'MODULE_NOT_FOUND'; throw e;} +module.exports = __WEBPACK_EXTERNAL_MODULE__27__; + +/***/ }), +/* 28 */ +/***/ (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__(4); +var Detector = __webpack_require__(12); +var Constraint = __webpack_require__(8); +var Composite = __webpack_require__(5); +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 + */ + +})(); + + +/***/ }), +/* 29 */ +/***/ (function(module, exports, __webpack_require__) { + +/** +* The `Matter.Runner` module is an optional utility which provides a game loop, +* that handles continuously updating a `Matter.Engine` for you within a browser. +* It is intended for development and debugging purposes, but may also be suitable for simple games. +* If you are using your own game loop instead, then you do not need the `Matter.Runner` module. +* Instead just call `Engine.update(engine, delta)` in your own loop. +* +* 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__(4); +var Engine = __webpack_require__(22); +var Common = __webpack_require__(0); + +(function() { + + var _requestAnimationFrame, + _cancelAnimationFrame; + + if (typeof window !== 'undefined') { + _requestAnimationFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame + || window.mozRequestAnimationFrame || window.msRequestAnimationFrame; + + _cancelAnimationFrame = window.cancelAnimationFrame || window.mozCancelAnimationFrame + || window.webkitCancelAnimationFrame || window.msCancelAnimationFrame; + } + + if (!_requestAnimationFrame) { + var _frameTimeout; + + _requestAnimationFrame = function(callback){ + _frameTimeout = setTimeout(function() { + callback(Common.now()); + }, 1000 / 60); + }; + + _cancelAnimationFrame = function() { + clearTimeout(_frameTimeout); + }; + } + + /** + * Creates a new Runner. The options parameter is an object that specifies any properties you wish to override the defaults. + * @method create + * @param {} options + */ + Runner.create = function(options) { + var defaults = { + fps: 60, + correction: 1, + deltaSampleSize: 60, + counterTimestamp: 0, + frameCounter: 0, + deltaHistory: [], + timePrev: null, + timeScalePrev: 1, + frameRequestId: null, + isFixed: false, + enabled: true + }; + + var runner = Common.extend(defaults, options); + + runner.delta = runner.delta || 1000 / runner.fps; + runner.deltaMin = runner.deltaMin || 1000 / runner.fps; + runner.deltaMax = runner.deltaMax || 1000 / (runner.fps * 0.5); + runner.fps = 1000 / runner.delta; + + return runner; + }; + + /** + * Continuously ticks a `Matter.Engine` by calling `Runner.tick` on the `requestAnimationFrame` event. + * @method run + * @param {engine} engine + */ + Runner.run = function(runner, engine) { + // create runner if engine is first argument + if (typeof runner.positionIterations !== 'undefined') { + engine = runner; + runner = Runner.create(); + } + + (function render(time){ + runner.frameRequestId = _requestAnimationFrame(render); + + if (time && runner.enabled) { + Runner.tick(runner, engine, time); + } + })(); + + return runner; + }; + + /** + * A game loop utility that updates the engine and renderer by one step (a 'tick'). + * Features delta smoothing, time correction and fixed or dynamic timing. + * Triggers `beforeTick`, `tick` and `afterTick` events on the engine. + * Consider just `Engine.update(engine, delta)` if you're using your own loop. + * @method tick + * @param {runner} runner + * @param {engine} engine + * @param {number} time + */ + Runner.tick = function(runner, engine, time) { + var timing = engine.timing, + correction = 1, + delta; + + // create an event object + var event = { + timestamp: timing.timestamp + }; + + Events.trigger(runner, 'beforeTick', event); + Events.trigger(engine, 'beforeTick', event); // @deprecated + + if (runner.isFixed) { + // fixed timestep + delta = runner.delta; + } else { + // dynamic timestep based on wall clock between calls + delta = (time - runner.timePrev) || runner.delta; + runner.timePrev = time; + + // optimistically filter delta over a few frames, to improve stability + runner.deltaHistory.push(delta); + runner.deltaHistory = runner.deltaHistory.slice(-runner.deltaSampleSize); + delta = Math.min.apply(null, runner.deltaHistory); + + // limit delta + delta = delta < runner.deltaMin ? runner.deltaMin : delta; + delta = delta > runner.deltaMax ? runner.deltaMax : delta; + + // correction for delta + correction = delta / runner.delta; + + // update engine timing object + runner.delta = delta; + } + + // time correction for time scaling + if (runner.timeScalePrev !== 0) + correction *= timing.timeScale / runner.timeScalePrev; + + if (timing.timeScale === 0) + correction = 0; + + runner.timeScalePrev = timing.timeScale; + runner.correction = correction; + + // fps counter + runner.frameCounter += 1; + if (time - runner.counterTimestamp >= 1000) { + runner.fps = runner.frameCounter * ((time - runner.counterTimestamp) / 1000); + runner.counterTimestamp = time; + runner.frameCounter = 0; + } + + Events.trigger(runner, 'tick', event); + Events.trigger(engine, 'tick', event); // @deprecated + + // if world has been modified, clear the render scene graph + if (engine.world.isModified + && engine.render + && engine.render.controller + && engine.render.controller.clear) { + engine.render.controller.clear(engine.render); // @deprecated + } + + // update + Events.trigger(runner, 'beforeUpdate', event); + Engine.update(engine, delta, correction); + Events.trigger(runner, 'afterUpdate', event); + + // render + // @deprecated + if (engine.render && engine.render.controller) { + Events.trigger(runner, 'beforeRender', event); + Events.trigger(engine, 'beforeRender', event); // @deprecated + + engine.render.controller.world(engine.render); + + Events.trigger(runner, 'afterRender', event); + Events.trigger(engine, 'afterRender', event); // @deprecated + } + + Events.trigger(runner, 'afterTick', event); + Events.trigger(engine, 'afterTick', event); // @deprecated + }; + + /** + * Ends execution of `Runner.run` on the given `runner`, by canceling the animation frame request event loop. + * If you wish to only temporarily pause the engine, see `engine.enabled` instead. + * @method stop + * @param {runner} runner + */ + Runner.stop = function(runner) { + _cancelAnimationFrame(runner.frameRequestId); + }; + + /** + * Alias for `Runner.run`. + * @method start + * @param {runner} runner + * @param {engine} engine + */ + Runner.start = function(runner, engine) { + Runner.run(runner, engine); + }; + + /* + * + * Events Documentation + * + */ + + /** + * Fired at the start of a tick, before any updates to the engine or timing + * + * @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 after engine timing updated, but just before update + * + * @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 at the end of a tick, after engine update and after rendering + * + * @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 update + * + * @event beforeUpdate + * @param {} event An event object + * @param {number} event.timestamp The engine.timing.timestamp of the event + * @param {} event.source The source object of the event + * @param {} event.name The name of the event + */ + + /** + * Fired after update + * + * @event afterUpdate + * @param {} event An event object + * @param {number} event.timestamp The engine.timing.timestamp of the event + * @param {} event.source The source object of the event + * @param {} event.name The name of the event + */ + + /** + * Fired 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 + * @deprecated + */ + + /** + * 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 + * @deprecated + */ + + /* + * + * Properties Documentation + * + */ + + /** + * A flag that specifies whether the runner is running or not. + * + * @property enabled + * @type boolean + * @default true + */ + + /** + * A `Boolean` that specifies if the runner should use a fixed timestep (otherwise it is variable). + * If timing is fixed, then the apparent simulation speed will change depending on the frame rate (but behaviour will be deterministic). + * If the timing is variable, then the apparent simulation speed will be constant (approximately, but at the cost of determininism). + * + * @property isFixed + * @type boolean + * @default false + */ + + /** + * A `Number` that specifies the time step between updates in milliseconds. + * If `engine.timing.isFixed` is set to `true`, then `delta` is fixed. + * If it is `false`, then `delta` can dynamically change to maintain the correct apparent simulation speed. + * + * @property delta + * @type number + * @default 1000 / 60 + */ + +})(); + + +/***/ }), +/* 30 */ +/***/ (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__(5); +var Constraint = __webpack_require__(8); +var Common = __webpack_require__(0); +var Body = __webpack_require__(6); +var Bodies = __webpack_require__(16); + +(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} xx + * @param {number} yy + * @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(xx, yy, columns, rows, columnGap, rowGap, callback) { + var stack = Composite.create({ label: 'Stack' }), + x = xx, + y = yy, + lastBody, + i = 0; + + for (var row = 0; row < rows; row++) { + var maxHeight = 0; + + for (var column = 0; column < columns; column++) { + var body = callback(x, y, 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 }); + + x = body.bounds.max.x + columnGap; + + Composite.addBody(stack, body); + + lastBody = body; + i += 1; + } else { + x += columnGap; + } + } + + y += maxHeight + rowGap; + x = xx; + } + + 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} xx + * @param {number} yy + * @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(xx, yy, columns, rows, columnGap, rowGap, callback) { + return Composites.stack(xx, yy, columns, rows, columnGap, rowGap, function(x, y, 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(xx + xOffset + column * columnGap, y, column, row, lastBody, i); + }); + }; + + /** + * Creates a composite with a Newton's Cradle setup of bodies and constraints. + * @method newtonsCradle + * @param {number} xx + * @param {number} yy + * @param {number} number + * @param {number} size + * @param {number} length + * @return {composite} A new composite newtonsCradle body + */ + Composites.newtonsCradle = function(xx, yy, number, size, length) { + var newtonsCradle = Composite.create({ label: 'Newtons Cradle' }); + + for (var i = 0; i < number; i++) { + var separation = 1.9, + circle = Bodies.circle(xx + i * (size * separation), yy + length, size, + { inertia: Infinity, restitution: 1, friction: 0, frictionAir: 0.0001, slop: 1 }), + constraint = Constraint.create({ pointA: { x: xx + i * (size * separation), y: yy }, bodyB: circle }); + + Composite.addBody(newtonsCradle, circle); + Composite.addConstraint(newtonsCradle, constraint); + } + + return newtonsCradle; + }; + + /** + * Creates a composite with simple car setup of bodies and constraints. + * @method car + * @param {number} xx + * @param {number} yy + * @param {number} width + * @param {number} height + * @param {number} wheelSize + * @return {composite} A new composite car body + */ + Composites.car = function(xx, yy, 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(xx, yy, width, height, { + collisionFilter: { + group: group + }, + chamfer: { + radius: height * 0.5 + }, + density: 0.0002 + }); + + var wheelA = Bodies.circle(xx + wheelAOffset, yy + wheelYOffset, wheelSize, { + collisionFilter: { + group: group + }, + friction: 0.8 + }); + + var wheelB = Bodies.circle(xx + wheelBOffset, yy + 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; + }; + + /** + * Creates a simple soft body like object. + * @method softBody + * @param {number} xx + * @param {number} yy + * @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(xx, yy, 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(xx, yy, columns, rows, columnGap, rowGap, function(x, y) { + return Bodies.circle(x, y, particleRadius, particleOptions); + }); + + Composites.mesh(softBody, columns, rows, crossBrace, constraintOptions); + + softBody.label = 'Soft Body'; + + return softBody; + }; + +})(); + + +/***/ }), +/* 31 */ +/***/ (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; + } + } + }; + +})(); + +/***/ }), +/* 32 */ +/***/ (function(module, exports, __webpack_require__) { + /** * The `Matter.RenderPixi` module is an example renderer using pixi.js. * See also `Matter.Render` for a canvas based renderer. @@ -9854,11 +10298,11 @@ var RenderPixi = {}; module.exports = RenderPixi; -var Bounds = _dereq_('../geometry/Bounds'); -var Composite = _dereq_('../body/Composite'); -var Common = _dereq_('../core/Common'); -var Events = _dereq_('../core/Events'); -var Vector = _dereq_('../geometry/Vector'); +var Bounds = __webpack_require__(1); +var Composite = __webpack_require__(5); +var Common = __webpack_require__(0); +var Events = __webpack_require__(4); +var Vector = __webpack_require__(2); (function() { @@ -10328,7 +10772,7 @@ var Vector = _dereq_('../geometry/Vector'); primitive.moveTo(part.position.x - body.position.x, part.position.y - body.position.y); primitive.lineTo(((part.vertices[0].x + part.vertices[part.vertices.length-1].x) / 2 - body.position.x), - ((part.vertices[0].y + part.vertices[part.vertices.length-1].y) / 2 - body.position.y)); + ((part.vertices[0].y + part.vertices[part.vertices.length-1].y) / 2 - body.position.y)); primitive.endFill(); } @@ -10357,5 +10801,7 @@ var Vector = _dereq_('../geometry/Vector'); })(); -},{"../body/Composite":2,"../core/Common":14,"../core/Events":16,"../geometry/Bounds":26,"../geometry/Vector":28}]},{},[30])(30) -}); + +/***/ }) +/******/ ]); +}); \ No newline at end of file diff --git a/build/matter.min.js b/build/matter.min.js index 8255c59..81784de 100644 --- a/build/matter.min.js +++ b/build/matter.min.js @@ -1,96 +1,6 @@ -/** -* matter-js 0.14.2 by @liabru 2018-06-11 -* http://brm.io/matter-js/ -* License MIT -*/ -!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var t;t="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,t.Matter=e()}}(function(){return function(){function e(t,n,o){function i(s,a){if(!n[s]){if(!t[s]){var l="function"==typeof require&&require;if(!a&&l)return l(s,!0);if(r)return r(s,!0);var c=new Error("Cannot find module '"+s+"'");throw c.code="MODULE_NOT_FOUND",c}var d=n[s]={exports:{}};t[s][0].call(d.exports,function(e){return i(t[s][1][e]||e)},d,d.exports,e,t,n,o)}return n[s].exports}for(var r="function"==typeof require&&require,s=0;s0&&r.rotateAbout(s.position,n,e.position,s.position)}},o.setVelocity=function(e,t){e.positionPrev.x=e.position.x-t.x,e.positionPrev.y=e.position.y-t.y, -e.velocity.x=t.x,e.velocity.y=t.y,e.speed=r.magnitude(e.velocity)},o.setAngularVelocity=function(e,t){e.anglePrev=e.angle-t,e.angularVelocity=t,e.angularSpeed=Math.abs(e.angularVelocity)},o.translate=function(e,t){o.setPosition(e,r.add(e.position,t))},o.rotate=function(e,t,n){if(n){var i=Math.cos(t),r=Math.sin(t),s=e.position.x-n.x,a=e.position.y-n.y;o.setPosition(e,{x:n.x+(s*i-a*r),y:n.y+(s*r+a*i)}),o.setAngle(e,e.angle+t)}else o.setAngle(e,e.angle+t)},o.scale=function(e,t,n,r){var s=0,a=0;r=r||e.position;for(var d=0;d0&&(s+=u.area,a+=u.inertia),u.position.x=r.x+(u.position.x-r.x)*t,u.position.y=r.y+(u.position.y-r.y)*n,l.update(u.bounds,u.vertices,e.velocity) -}e.parts.length>1&&(e.area=s,e.isStatic||(o.setMass(e,e.density*s),o.setInertia(e,a))),e.circleRadius&&(t===n?e.circleRadius*=t:e.circleRadius=null)},o.update=function(e,t,n,o){var s=Math.pow(t*n*e.timeScale,2),a=1-e.frictionAir*n*e.timeScale,d=e.position.x-e.positionPrev.x,u=e.position.y-e.positionPrev.y;e.velocity.x=d*a*o+e.force.x/e.mass*s,e.velocity.y=u*a*o+e.force.y/e.mass*s,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.angularVelocity=(e.angle-e.anglePrev)*a*o+e.torque/e.inertia*s,e.anglePrev=e.angle,e.angle+=e.angularVelocity,e.speed=r.magnitude(e.velocity),e.angularSpeed=Math.abs(e.angularVelocity);for(var p=0;p0&&(f.position.x+=e.velocity.x,f.position.y+=e.velocity.y),0!==e.angularVelocity&&(i.rotate(f.vertices,e.angularVelocity,e.position),c.rotate(f.axes,e.angularVelocity), -p>0&&r.rotateAbout(f.position,e.angularVelocity,e.position,f.position)),l.update(f.bounds,f.vertices,e.velocity)}},o.applyForce=function(e,t,n){e.force.x+=n.x,e.force.y+=n.y;var o={x:t.x-e.position.x,y:t.y-e.position.y};e.torque+=o.x*n.y-o.y*n.x},o._totalProperties=function(e){for(var t={mass:0,area:0,inertia:0,centre:{x:0,y:0}},n=1===e.parts.length?0:1;n1?1:0;u1?1:0;f0:0!=(e.mask&t.category)&&0!=(t.mask&e.category)}}()},{"../geometry/Bounds":26,"./Pair":7,"./SAT":11}],6:[function(e,t,n){var o={};t.exports=o;var i=e("./Pair"),r=e("./Detector"),s=e("../core/Common");!function(){o.create=function(e){var t={controller:o,detector:r.collisions,buckets:{},pairs:{},pairsList:[],bucketWidth:48,bucketHeight:48};return s.extend(t,e)},o.update=function(e,t,n,i){ -var r,s,a,l,c,d=n.world,u=e.buckets,p=!1;for(r=0;rd.bounds.max.x||f.bounds.max.yd.bounds.max.y)){var m=o._getRegion(e,f);if(!f.region||m.id!==f.region.id||i){f.region&&!i||(f.region=m);var v=o._regionUnion(m,f.region);for(s=v.startCol;s<=v.endCol;s++)for(a=v.startRow;a<=v.endRow;a++){c=o._getBucketId(s,a),l=u[c];var y=s>=m.startCol&&s<=m.endCol&&a>=m.startRow&&a<=m.endRow,g=s>=f.region.startCol&&s<=f.region.endCol&&a>=f.region.startRow&&a<=f.region.endRow;!y&&g&&g&&l&&o._bucketRemoveBody(e,l,f),(f.region===m||y&&!g||i)&&(l||(l=o._createBucket(u,c)),o._bucketAddBody(e,l,f))}f.region=m,p=!0}}}p&&(e.pairsList=o._createActivePairsList(e))},o.clear=function(e){e.buckets={},e.pairs={},e.pairsList=[]},o._regionUnion=function(e,t){var n=Math.min(e.startCol,t.startCol),i=Math.max(e.endCol,t.endCol),r=Math.min(e.startRow,t.startRow),s=Math.max(e.endRow,t.endRow) -;return o._createRegion(n,i,r,s)},o._getRegion=function(e,t){var n=t.bounds,i=Math.floor(n.min.x/e.bucketWidth),r=Math.floor(n.max.x/e.bucketWidth),s=Math.floor(n.min.y/e.bucketHeight),a=Math.floor(n.max.y/e.bucketHeight);return o._createRegion(i,r,s,a)},o._createRegion=function(e,t,n,o){return{id:e+","+t+","+n+","+o,startCol:e,endCol:t,startRow:n,endRow:o}},o._getBucketId=function(e,t){return"C"+e+"R"+t},o._createBucket=function(e,t){return e[t]=[]},o._bucketAddBody=function(e,t,n){for(var o=0;o0?o.push(n):delete e.pairs[t[i]];return o}}()},{"../core/Common":14,"./Detector":5,"./Pair":7}], -7:[function(e,t,n){var o={};t.exports=o;var i=e("./Contact");!function(){o.create=function(e,t){var n=e.bodyA,i=e.bodyB,r=e.parentA,s=e.parentB,a={id:o.id(n,i),bodyA:n,bodyB:i,contacts:{},activeContacts:[],separation:0,isActive:!0,isSensor:n.isSensor||i.isSensor,timeCreated:t,timeUpdated:t,inverseMass:r.inverseMass+s.inverseMass,friction:Math.min(r.friction,s.friction),frictionStatic:Math.max(r.frictionStatic,s.frictionStatic),restitution:Math.max(r.restitution,s.restitution),slop:Math.max(r.slop,s.slop)};return o.update(a,e,t),a},o.update=function(e,t,n){var r=e.contacts,s=t.supports,a=e.activeContacts,l=t.parentA,c=t.parentB;if(e.collision=t,e.inverseMass=l.inverseMass+c.inverseMass,e.friction=Math.min(l.friction,c.friction),e.frictionStatic=Math.max(l.frictionStatic,c.frictionStatic),e.restitution=Math.max(l.restitution,c.restitution),e.slop=Math.max(l.slop,c.slop),a.length=0,t.collided){for(var d=0;do._pairMaxIdleLife&&c.push(s);for(s=0;sf.friction*f.frictionStatic*E*n&&(F=T,L=s.clamp(f.friction*R*n,-F,F));var O=r.cross(A,g),q=r.cross(P,g),W=b/(v.inverseMass+y.inverseMass+v.inverseInertia*O*O+y.inverseInertia*q*q);if(V*=W,L*=W,I<0&&I*I>o._restingThresh*n)S.normalImpulse=0;else{var D=S.normalImpulse;S.normalImpulse=Math.min(S.normalImpulse+V,0),V=S.normalImpulse-D}if(_*_>o._restingThreshTangent*n)S.tangentImpulse=0;else{var N=S.tangentImpulse;S.tangentImpulse=s.clamp(S.tangentImpulse+L,-F,F),L=S.tangentImpulse-N}i.x=g.x*V+x.x*L,i.y=g.y*V+x.y*L,v.isStatic||v.isSleeping||(v.positionPrev.x+=i.x*v.inverseMass,v.positionPrev.y+=i.y*v.inverseMass, -v.anglePrev+=r.cross(A,i)*v.inverseInertia),y.isStatic||y.isSleeping||(y.positionPrev.x-=i.x*y.inverseMass,y.positionPrev.y-=i.y*y.inverseMass,y.anglePrev-=r.cross(P,i)*y.inverseInertia)}}}}}()},{"../core/Common":14,"../geometry/Bounds":26,"../geometry/Vector":28,"../geometry/Vertices":29}],11:[function(e,t,n){var o={};t.exports=o;var i=e("../geometry/Vertices"),r=e("../geometry/Vector");!function(){o.collides=function(e,t,n){var s,a,l,c,d=!1;if(n){var u=e.parent,p=t.parent,f=u.speed*u.speed+u.angularSpeed*u.angularSpeed+p.speed*p.speed+p.angularSpeed*p.angularSpeed;d=n&&n.collided&&f<.2,c=n}else c={collided:!1,bodyA:e,bodyB:t};if(n&&d){var m=c.axisBody,v=m===e?t:e,y=[m.axes[n.axisNumber]];if(l=o._overlapAxes(m.vertices,v.vertices,y),c.reused=!0,l.overlap<=0)return c.collided=!1,c}else{if(s=o._overlapAxes(e.vertices,t.vertices,e.axes),s.overlap<=0)return c.collided=!1,c;if(a=o._overlapAxes(t.vertices,e.vertices,t.axes),a.overlap<=0)return c.collided=!1,c;s.overlapi?i=a:a=0?s.index-1:d.length-1],c.x=i.x-u.x,c.y=i.y-u.y,l=-r.dot(n,c),a=i,i=d[(s.index+1)%d.length],c.x=i.x-u.x,c.y=i.y-u.y,o=-r.dot(n,c),o0?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 s={visible:!0,lineWidth:2,strokeStyle:"#ffffff",type:"line",anchors:!0};return 0===t.length&&t.stiffness>.1?(s.type="pin",s.anchors=!1):t.stiffness<.9&&(s.type="spring"),t.render=c.extend(s,t.render),t},o.preSolveAll=function(e){for(var t=0;t0&&(u.position.x+=c.x,u.position.y+=c.y),0!==c.angle&&(i.rotate(u.vertices,c.angle,n.position),l.rotate(u.axes,c.angle), -d>0&&r.rotateAbout(u.position,c.angle,n.position,u.position)),a.update(u.bounds,u.vertices,n.velocity)}c.angle*=o._warming,c.x*=o._warming,c.y*=o._warming}}}}()},{"../core/Common":14,"../core/Sleeping":22,"../geometry/Axes":25,"../geometry/Bounds":26,"../geometry/Vector":28,"../geometry/Vertices":29}],13:[function(e,t,n){var o={};t.exports=o;var i=e("../geometry/Vertices"),r=e("../core/Sleeping"),s=e("../core/Mouse"),a=e("../core/Events"),l=e("../collision/Detector"),c=e("./Constraint"),d=e("../body/Composite"),u=e("../core/Common"),p=e("../geometry/Bounds");!function(){o.create=function(e,t){var n=(e?e.mouse:null)||(t?t.mouse:null);n||(e&&e.render&&e.render.canvas?n=s.create(e.render.canvas):t&&t.element?n=s.create(t.element):(n=s.create(),u.warn("MouseConstraint.create: options.mouse was undefined, options.element was undefined, may not function as expected")));var i=c.create({label:"Mouse Constraint",pointA:n.position,pointB:{x:0,y:0},length:.01,stiffness:.1,angularStiffness:1, -render:{strokeStyle:"#90EE90",lineWidth:3}}),r={type:"mouseConstraint",mouse:n,element:null,body:null,constraint:i,collisionFilter:{category:1,mask:4294967295,group:0}},l=u.extend(r,t);return a.on(e,"beforeUpdate",function(){var t=d.allBodies(e.world);o.update(l,t),o._triggerEvents(l)}),l},o.update=function(e,t){var n=e.mouse,o=e.constraint,s=e.body;if(0===n.button){if(o.bodyB)r.set(o.bodyB,!1),o.pointA=n.position;else for(var c=0;c1?1:0;d0;t--){var n=Math.floor(o.random()*(t+1)),i=e[t];e[t]=e[n],e[n]=i}return e},o.choose=function(e){return e[Math.floor(o.random()*e.length)]},o.isElement=function(e){return"undefined"!=typeof HTMLElement?e instanceof HTMLElement:!!(e&&e.nodeType&&e.nodeName)},o.isArray=function(e){return"[object Array]"===Object.prototype.toString.call(e)},o.isFunction=function(e){return"function"==typeof e},o.isPlainObject=function(e){return"object"==typeof e&&e.constructor===Object},o.isString=function(e){return"[object String]"===toString.call(e)},o.clamp=function(e,t,n){return en?n:e},o.sign=function(e){return e<0?-1:1},o.now=function(){ -if(window.performance){if(window.performance.now)return window.performance.now();if(window.performance.webkitNow)return window.performance.webkitNow()}return new Date-o._nowStartTime},o.random=function(e,n){return e=void 0!==e?e:0,n=void 0!==n?n:1,e+t()*(n-e)};var t=function(){return o._seed=(9301*o._seed+49297)%233280,o._seed/233280};o.colorToNumber=function(e){return e=e.replace("#",""),3==e.length&&(e=e.charAt(0)+e.charAt(0)+e.charAt(1)+e.charAt(1)+e.charAt(2)+e.charAt(2)),parseInt(e,16)},o.logLevel=1,o.log=function(){console&&o.logLevel>0&&o.logLevel<=3&&console.log.apply(console,["matter-js:"].concat(Array.prototype.slice.call(arguments)))},o.info=function(){console&&o.logLevel>0&&o.logLevel<=2&&console.info.apply(console,["matter-js:"].concat(Array.prototype.slice.call(arguments)))},o.warn=function(){console&&o.logLevel>0&&o.logLevel<=3&&console.warn.apply(console,["matter-js:"].concat(Array.prototype.slice.call(arguments)))},o.nextId=function(){return o._nextId++}, -o.indexOf=function(e,t){if(e.indexOf)return e.indexOf(t);for(var n=0;n0&&d.trigger(e,"collisionStart",{pairs:h.collisionStart}),s.preSolvePosition(h.list),i=0;i0&&d.trigger(e,"collisionActive",{pairs:h.collisionActive}),h.collisionEnd.length>0&&d.trigger(e,"collisionEnd",{pairs:h.collisionEnd}),o._bodiesClearForces(y),d.trigger(e,"afterUpdate",v),e},o.merge=function(e,t){if(f.extend(e,t),t.world){e.world=t.world,o.clear(e);for(var n=u.allBodies(e.world),i=0;ir?(i.warn("Plugin.register:",o.toString(t),"was upgraded to",o.toString(e)),o._registry[e.name]=e):n-1},o.isFor=function(e,t){var n=e.for&&o.dependencyParse(e.for) -;return!e.for||t.name===n.name&&o.versionSatisfies(t.version,n.range)},o.use=function(e,t){if(e.uses=(e.uses||[]).concat(t||[]),0===e.uses.length)return void i.warn("Plugin.use:",o.toString(e),"does not specify any dependencies to install.");for(var n=o.dependencies(e),r=i.topologicalSort(n),s=[],a=0;a0&&i.info(s.join(" "))},o.dependencies=function(e,t){var n=o.dependencyParse(e),r=n.name;if(t=t||{},!(r in t)){e=o.resolve(e)||e,t[r]=i.map(e.uses||[],function(t){o.isPlugin(t)&&o.register(t);var r=o.dependencyParse(t),s=o.resolve(t) -;return s&&!o.versionSatisfies(s.version,r.range)?(i.warn("Plugin.dependencies:",o.toString(s),"does not satisfy",o.toString(r),"used by",o.toString(n)+"."),s._warned=!0,e._warned=!0):s||(i.warn("Plugin.dependencies:",o.toString(t),"used by",o.toString(n),"could not be resolved."),e._warned=!0),r.name});for(var s=0;s=i[2];if("^"===n.operator)return i[0]>0?s[0]===i[0]&&r.number>=n.number:i[1]>0?s[1]===i[1]&&s[2]>=i[2]:s[2]===i[2]}return e===t||"*"===e}}()},{"./Common":14}],21:[function(e,t,n){var o={};t.exports=o;var i=e("./Events"),r=e("./Engine"),s=e("./Common");!function(){var e,t;if("undefined"!=typeof window&&(e=window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.msRequestAnimationFrame,t=window.cancelAnimationFrame||window.mozCancelAnimationFrame||window.webkitCancelAnimationFrame||window.msCancelAnimationFrame),!e){var n;e=function(e){n=setTimeout(function(){e(s.now())},1e3/60)},t=function(){clearTimeout(n)}}o.create=function(e){var t={fps:60,correction:1,deltaSampleSize:60, -counterTimestamp:0,frameCounter:0,deltaHistory:[],timePrev:null,timeScalePrev:1,frameRequestId:null,isFixed:!1,enabled:!0},n=s.extend(t,e);return n.delta=n.delta||1e3/n.fps,n.deltaMin=n.deltaMin||1e3/n.fps,n.deltaMax=n.deltaMax||1e3/(.5*n.fps),n.fps=1e3/n.delta,n},o.run=function(t,n){return void 0!==t.positionIterations&&(n=t,t=o.create()),function i(r){t.frameRequestId=e(i),r&&t.enabled&&o.tick(t,n,r)}(),t},o.tick=function(e,t,n){var o,s=t.timing,a=1,l={timestamp:s.timestamp};i.trigger(e,"beforeTick",l),i.trigger(t,"beforeTick",l),e.isFixed?o=e.delta:(o=n-e.timePrev||e.delta,e.timePrev=n,e.deltaHistory.push(o),e.deltaHistory=e.deltaHistory.slice(-e.deltaSampleSize),o=Math.min.apply(null,e.deltaHistory),o=oe.deltaMax?e.deltaMax:o,a=o/e.delta,e.delta=o),0!==e.timeScalePrev&&(a*=s.timeScale/e.timeScalePrev),0===s.timeScale&&(a=0),e.timeScalePrev=s.timeScale,e.correction=a,e.frameCounter+=1, -n-e.counterTimestamp>=1e3&&(e.fps=e.frameCounter*((n-e.counterTimestamp)/1e3),e.counterTimestamp=n,e.frameCounter=0),i.trigger(e,"tick",l),i.trigger(t,"tick",l),t.world.isModified&&t.render&&t.render.controller&&t.render.controller.clear&&t.render.controller.clear(t.render),i.trigger(e,"beforeUpdate",l),r.update(t,o,a),i.trigger(e,"afterUpdate",l),t.render&&t.render.controller&&(i.trigger(e,"beforeRender",l),i.trigger(t,"beforeRender",l),t.render.controller.world(t.render),i.trigger(e,"afterRender",l),i.trigger(t,"afterRender",l)),i.trigger(e,"afterTick",l),i.trigger(t,"afterTick",l)},o.stop=function(e){t(e.frameRequestId)},o.start=function(e,t){o.run(e,t)}}()},{"./Common":14,"./Engine":15,"./Events":16}],22:[function(e,t,n){var o={};t.exports=o;var i=e("./Events");!function(){o._motionWakeThreshold=.18,o._motionSleepThreshold=.08,o._minBias=.9,o.update=function(e,t){for(var n=t*t*t,i=0;i0&&r.motion=r.sleepThreshold&&o.set(r,!0)):r.sleepCounter>0&&(r.sleepCounter-=1)}else o.set(r,!1)}},o.afterCollisions=function(e,t){for(var n=t*t*t,i=0;io._motionWakeThreshold*n&&o.set(c,!1)}}}},o.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||i.trigger(e,"sleepStart")):(e.isSleeping=!1,e.sleepCounter=0,n&&i.trigger(e,"sleepEnd"))}}()},{ -"./Events":16}],23:[function(e,t,n){var o={};t.exports=o;var i,r=e("../geometry/Vertices"),s=e("../core/Common"),a=e("../body/Body"),l=e("../geometry/Bounds"),c=e("../geometry/Vector");!function(){o.rectangle=function(e,t,n,o,i){i=i||{};var l={label:"Rectangle Body",position:{x:e,y:t},vertices:r.fromPath("L 0 0 L "+n+" 0 L "+n+" "+o+" L 0 "+o)};if(i.chamfer){var c=i.chamfer;l.vertices=r.chamfer(l.vertices,c.radius,c.quality,c.qualityMin,c.qualityMax),delete i.chamfer}return a.create(s.extend({},l,i))},o.trapezoid=function(e,t,n,o,i,l){l=l||{},i*=.5;var c,d=(1-2*i)*n,u=n*i,p=u+d,f=p+u;c=i<.5?"L 0 0 L "+u+" "+-o+" L "+p+" "+-o+" L "+f+" 0":"L 0 0 L "+p+" "+-o+" L "+f+" 0";var m={label:"Trapezoid Body",position:{x:e,y:t},vertices:r.fromPath(c)};if(l.chamfer){var v=l.chamfer;m.vertices=r.chamfer(m.vertices,v.radius,v.quality,v.qualityMin,v.qualityMax),delete l.chamfer}return a.create(s.extend({},m,l))},o.circle=function(e,t,n,i,r){i=i||{};var a={label:"Circle Body",circleRadius:n};r=r||25 -;var l=Math.ceil(Math.max(10,Math.min(r,n)));return l%2==1&&(l+=1),o.polygon(e,t,l,n,s.extend({},a,i))},o.polygon=function(e,t,n,i,l){if(l=l||{},n<3)return o.circle(e,t,i,l);for(var c=2*Math.PI/n,d="",u=.5*c,p=0;p0&&r.area(P)1?(f=a.create(s.extend({parts:m.slice(0)},o)),a.setPosition(f,{x:e,y:t}),f):m[0]}}()},{"../body/Body":1,"../core/Common":14,"../geometry/Bounds":26,"../geometry/Vector":28,"../geometry/Vertices":29}],24:[function(e,t,n){var o={};t.exports=o -;var i=e("../body/Composite"),r=e("../constraint/Constraint"),s=e("../core/Common"),a=e("../body/Body"),l=e("./Bodies");!function(){o.stack=function(e,t,n,o,r,s,l){for(var c,d=i.create({label:"Stack"}),u=e,p=t,f=0,m=0;mv&&(v=x),a.translate(g,{x:.5*h,y:.5*x}),u=g.bounds.max.x+r,i.addBody(d,g),c=g,f+=1}else u+=r}p+=v+s,u=e}return d},o.chain=function(e,t,n,o,a,l){for(var c=e.bodies,d=1;d0)for(c=0;c0&&(p=f[c-1+(l-1)*t],i.addConstraint(e,r.create(s.extend({bodyA:p,bodyB:u},a)))),o&&cp)){c=p-c;var m=c,v=n-1-c;if(!(sv)){1===u&&a.translate(d,{x:(s+(n%2==1?1:-1))*f,y:0});return l(e+(d?s*f:0)+s*r,o,s,c,d,u)}}})},o.newtonsCradle=function(e,t,n,o,s){for(var a=i.create({label:"Newtons Cradle"}),c=0;ce.max.x&&(e.max.x=i.x),i.xe.max.y&&(e.max.y=i.y),i.y0?e.max.x+=n.x:e.min.x+=n.x,n.y>0?e.max.y+=n.y:e.min.y+=n.y)},o.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},o.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},o.translate=function(e,t){e.min.x+=t.x, -e.max.x+=t.x,e.min.y+=t.y,e.max.y+=t.y},o.shift=function(e,t){var n=e.max.x-e.min.x,o=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+o}}()},{}],27:[function(e,t,n){var o={};t.exports=o;var i=(e("../geometry/Bounds"),e("../core/Common"));!function(){o.pathToVertices=function(e,t){"undefined"==typeof window||"SVGPathSeg"in window||i.warn("Svg.pathToVertices: SVGPathSeg not defined, a polyfill is required.");var n,r,s,a,l,c,d,u,p,f,m,v,y=[],g=0,x=0,h=0;t=t||15;var b=function(e,t,n){var o=n%2==1&&n>1;if(!p||e!=p.x||t!=p.y){p&&o?(m=p.x,v=p.y):(m=0,v=0);var i={x:m+e,y:v+t};!o&&p||(p=i),y.push(i),x=m+e,h=v+t}},w=function(e){var t=e.pathSegTypeAsLetter.toUpperCase();if("Z"!==t){switch(t){case"M":case"L":case"T":case"C":case"S":case"Q":x=e.x,h=e.y;break;case"H":x=e.x;break;case"V":h=e.y}b(x,h,e.pathSegType)}};for(o._svgPathToAbsolute(e),s=e.getTotalLength(),c=[],n=0;n0)return!1}return!0},o.scale=function(e,t,n,r){if(1===t&&1===n)return e;r=r||o.centre(e);for(var s,a,l=0;l=0?l-1:e.length-1],d=e[l],u=e[(l+1)%e.length],p=t[l0&&(r|=2),3===r)return!1;return 0!==r||null},o.hull=function(e){var t,n,o=[],r=[];for(e=e.slice(0),e.sort(function(e,t){var n=e.x-t.x;return 0!==n?n:e.y-t.y}),n=0;n=2&&i.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];o.length>=2&&i.cross3(o[o.length-2],o[o.length-1],t)<=0;)o.pop();o.push(t)}return o.pop(),r.pop(),o.concat(r)}}()},{"../core/Common":14,"../geometry/Vector":28}],30:[function(e,t,n){var o=t.exports=e("../core/Matter");o.Body=e("../body/Body"),o.Composite=e("../body/Composite"), -o.World=e("../body/World"),o.Contact=e("../collision/Contact"),o.Detector=e("../collision/Detector"),o.Grid=e("../collision/Grid"),o.Pairs=e("../collision/Pairs"),o.Pair=e("../collision/Pair"),o.Query=e("../collision/Query"),o.Resolver=e("../collision/Resolver"),o.SAT=e("../collision/SAT"),o.Constraint=e("../constraint/Constraint"),o.MouseConstraint=e("../constraint/MouseConstraint"),o.Common=e("../core/Common"),o.Engine=e("../core/Engine"),o.Events=e("../core/Events"),o.Mouse=e("../core/Mouse"),o.Runner=e("../core/Runner"),o.Sleeping=e("../core/Sleeping"),o.Plugin=e("../core/Plugin"),o.Bodies=e("../factory/Bodies"),o.Composites=e("../factory/Composites"),o.Axes=e("../geometry/Axes"),o.Bounds=e("../geometry/Bounds"),o.Svg=e("../geometry/Svg"),o.Vector=e("../geometry/Vector"),o.Vertices=e("../geometry/Vertices"),o.Render=e("../render/Render"),o.RenderPixi=e("../render/RenderPixi"),o.World.add=o.Composite.add,o.World.remove=o.Composite.remove, -o.World.addComposite=o.Composite.addComposite,o.World.addBody=o.Composite.addBody,o.World.addConstraint=o.Composite.addConstraint,o.World.clear=o.Composite.clear,o.Engine.run=o.Runner.run},{"../body/Body":1,"../body/Composite":2,"../body/World":3,"../collision/Contact":4,"../collision/Detector":5,"../collision/Grid":6,"../collision/Pair":7,"../collision/Pairs":8,"../collision/Query":9,"../collision/Resolver":10,"../collision/SAT":11,"../constraint/Constraint":12,"../constraint/MouseConstraint":13,"../core/Common":14,"../core/Engine":15,"../core/Events":16,"../core/Matter":17,"../core/Metrics":18,"../core/Mouse":19,"../core/Plugin":20,"../core/Runner":21,"../core/Sleeping":22,"../factory/Bodies":23,"../factory/Composites":24,"../geometry/Axes":25,"../geometry/Bounds":26,"../geometry/Svg":27,"../geometry/Vector":28,"../geometry/Vertices":29,"../render/Render":31,"../render/RenderPixi":32}],31:[function(e,t,n){var o={};t.exports=o -;var i=e("../core/Common"),r=e("../body/Composite"),s=e("../geometry/Bounds"),a=e("../core/Events"),l=e("../collision/Grid"),c=e("../geometry/Vector"),d=e("../core/Mouse");!function(){var e,t;"undefined"!=typeof window&&(e=window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.msRequestAnimationFrame||function(e){window.setTimeout(function(){e(i.now())},1e3/60)},t=window.cancelAnimationFrame||window.mozCancelAnimationFrame||window.webkitCancelAnimationFrame||window.msCancelAnimationFrame),o.create=function(e){var t={controller:o,engine:null,element:null,canvas:null,mouse:null,frameRequestId:null,options:{width:800,height:600,pixelRatio:1,background:"#18181d",wireframeBackground:"#0f0f13",hasBounds:!!e.bounds,enabled:!0,wireframes:!0,showSleeping:!0,showDebug:!1,showBroadphase:!1,showBounds:!1,showVelocity:!1,showCollisions:!1,showSeparations:!1,showAxes:!1,showPositions:!1,showAngleIndicator:!1,showIds:!1,showShadows:!1, -showVertexNumbers:!1,showConvexHulls:!1,showInternalEdges:!1,showMousePosition:!1}},r=i.extend(t,e);return r.canvas&&(r.canvas.width=r.options.width||r.canvas.width,r.canvas.height=r.options.height||r.canvas.height),r.mouse=e.mouse,r.engine=e.engine,r.canvas=r.canvas||n(r.options.width,r.options.height),r.context=r.canvas.getContext("2d"),r.textures={},r.bounds=r.bounds||{min:{x:0,y:0},max:{x:r.canvas.width,y:r.canvas.height}},1!==r.options.pixelRatio&&o.setPixelRatio(r,r.options.pixelRatio),i.isElement(r.element)?r.element.appendChild(r.canvas):r.canvas.parentNode||i.log("Render.create: options.element was undefined, render.canvas was created but not appended","warn"),r},o.run=function(t){!function n(i){t.frameRequestId=e(n),o.world(t)}()},o.stop=function(e){t(e.frameRequestId)},o.setPixelRatio=function(e,t){var n=e.options,o=e.canvas;"auto"===t&&(t=u(o)),n.pixelRatio=t,o.setAttribute("data-pixel-ratio",t),o.width=n.width*t,o.height=n.height*t,o.style.width=n.width+"px", -o.style.height=n.height+"px",e.context.scale(t,t)},o.lookAt=function(e,t,n,o){o=void 0===o||o,t=i.isArray(t)?t:[t],n=n||{x:0,y:0};for(var r={min:{x:1/0,y:1/0},max:{x:-1/0,y:-1/0}},s=0;sr.max.x&&(r.max.x=c.x),l.yr.max.y&&(r.max.y=c.y))}var u=r.max.x-r.min.x+2*n.x,p=r.max.y-r.min.y+2*n.y,f=e.canvas.height,m=e.canvas.width,v=m/f,y=u/p,g=1,x=1;y>v?x=y/v:g=v/y,e.options.hasBounds=!0,e.bounds.min.x=r.min.x,e.bounds.max.x=r.min.x+u*g,e.bounds.min.y=r.min.y,e.bounds.max.y=r.min.y+p*x,o&&(e.bounds.min.x+=.5*u-u*g*.5,e.bounds.max.x+=.5*u-u*g*.5,e.bounds.min.y+=.5*p-p*x*.5,e.bounds.max.y+=.5*p-p*x*.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&&(d.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}), -d.setOffset(e.mouse,e.bounds.min))},o.startViewTransform=function(e){var t=e.bounds.max.x-e.bounds.min.x,n=e.bounds.max.y-e.bounds.min.y,o=t/e.options.width,i=n/e.options.height;e.context.scale(1/o,1/i),e.context.translate(-e.bounds.min.x,-e.bounds.min.y)},o.endViewTransform=function(e){e.context.setTransform(e.options.pixelRatio,0,0,e.options.pixelRatio,0,0)},o.world=function(e){var t,n=e.engine,i=n.world,u=e.canvas,p=e.context,m=e.options,v=r.allBodies(i),y=r.allConstraints(i),g=m.wireframes?m.wireframeBackground:m.background,x=[],h=[],b={timestamp:n.timing.timestamp};if(a.trigger(e,"beforeRender",b),e.currentBackground!==g&&f(e,g),p.globalCompositeOperation="source-in",p.fillStyle="transparent",p.fillRect(0,0,u.width,u.height),p.globalCompositeOperation="source-over",m.hasBounds){for(t=0;t=500){var l="";s.timing&&(l+="fps: "+Math.round(s.timing.fps)+" "),e.debugString=l,e.debugTimestamp=o.timing.timestamp}if(e.debugString){n.font="12px Arial",a.wireframes?n.fillStyle="rgba(255,255,255,0.5)":n.fillStyle="rgba(0,0,0,0.5)";for(var c=e.debugString.split("\n"),d=0;d1?1:0;s1?1:0;a1?1:0;r1?1:0;a1?1:0;r1?1:0;r1?1:0;i0)){var u=o.activeContacts[0].vertex.x,p=o.activeContacts[0].vertex.y;2===o.activeContacts.length&&(u=(o.activeContacts[0].vertex.x+o.activeContacts[1].vertex.x)/2,p=(o.activeContacts[0].vertex.y+o.activeContacts[1].vertex.y)/2),i.bodyB===i.supports[0].body||!0===i.bodyA.isStatic?a.moveTo(u-8*i.normal.x,p-8*i.normal.y):a.moveTo(u+8*i.normal.x,p+8*i.normal.y),a.lineTo(u,p)} -l.wireframes?a.strokeStyle="rgba(255,165,0,0.7)":a.strokeStyle="orange",a.lineWidth=1,a.stroke()},o.separations=function(e,t,n){var o,i,r,s,a,l=n,c=e.options;for(l.beginPath(),a=0;a1?1:0;p0;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 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.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 s=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=s,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}return!0},i.scale=function(e,t,n,r){if(1===t&&1===n)return e;var s,a;r=r||i.centre(e);for(var l=0;l=0?l-1:e.length-1],d=e[l],u=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(0);i.on=function(e,t,n){for(var i,o=t.split(" "),r=0;r0){n||(n={}),i=t.split(" ");for(var c=0;c0&&r.rotateAbout(s.position,n,e.position,s.position)}},i.setVelocity=function(e,t){e.positionPrev.x=e.position.x-t.x,e.positionPrev.y=e.position.y-t.y,e.velocity.x=t.x,e.velocity.y=t.y,e.speed=r.magnitude(e.velocity)},i.setAngularVelocity=function(e,t){e.anglePrev=e.angle-t,e.angularVelocity=t,e.angularSpeed=Math.abs(e.angularVelocity)},i.translate=function(e,t){i.setPosition(e,r.add(e.position,t))},i.rotate=function(e,t,n){if(n){var o=Math.cos(t),r=Math.sin(t),s=e.position.x-n.x,a=e.position.y-n.y;i.setPosition(e,{x:n.x+(s*o-a*r),y:n.y+(s*r+a*o)}),i.setAngle(e,e.angle+t)}else i.setAngle(e,e.angle+t)},i.scale=function(e,t,n,r){var s=0,a=0;r=r||e.position;for(var d=0;d0&&(s+=u.area,a+=u.inertia),u.position.x=r.x+(u.position.x-r.x)*t,u.position.y=r.y+(u.position.y-r.y)*n,l.update(u.bounds,u.vertices,e.velocity)}e.parts.length>1&&(e.area=s,e.isStatic||(i.setMass(e,e.density*s),i.setInertia(e,a))),e.circleRadius&&(t===n?e.circleRadius*=t:e.circleRadius=null)},i.update=function(e,t,n,i){var s=Math.pow(t*n*e.timeScale,2),a=1-e.frictionAir*n*e.timeScale,d=e.position.x-e.positionPrev.x,u=e.position.y-e.positionPrev.y;e.velocity.x=d*a*i+e.force.x/e.mass*s,e.velocity.y=u*a*i+e.force.y/e.mass*s,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.angularVelocity=(e.angle-e.anglePrev)*a*i+e.torque/e.inertia*s,e.anglePrev=e.angle,e.angle+=e.angularVelocity,e.speed=r.magnitude(e.velocity),e.angularSpeed=Math.abs(e.angularVelocity);for(var p=0;p0&&(f.position.x+=e.velocity.x,f.position.y+=e.velocity.y),0!==e.angularVelocity&&(o.rotate(f.vertices,e.angularVelocity,e.position),c.rotate(f.axes,e.angularVelocity),p>0&&r.rotateAbout(f.position,e.angularVelocity,e.position,f.position)),l.update(f.bounds,f.vertices,e.velocity)}},i.applyForce=function(e,t,n){e.force.x+=n.x,e.force.y+=n.y;var i=t.x-e.position.x,o=t.y-e.position.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&&r.motion=r.sleepThreshold&&i.set(r,!0)):r.sleepCounter>0&&(r.sleepCounter-=1)}else i.set(r,!1)}},i.afterCollisions=function(e,t){for(var n=t*t*t,o=0;oi._motionWakeThreshold*n&&i.set(c,!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||o.trigger(e,"sleepStart")):(e.isSleeping=!1,e.sleepCounter=0,n&&o.trigger(e,"sleepEnd"))}},function(e,t,n){var i={};e.exports=i;var o=n(3),r=n(2),s=n(7),a=n(1),l=n(15),c=n(0);i._warming=.4,i._torqueDampen=1,i._minLength=1e-6,i.create=function(e){var t=e;t.bodyA&&!t.pointA&&(t.pointA={x:0,y:0}),t.bodyB&&!t.pointB&&(t.pointB={x:0,y:0});var n=t.bodyA?r.add(t.bodyA.position,t.pointA):t.pointA,i=t.bodyB?r.add(t.bodyB.position,t.pointB):t.pointB,o=r.magnitude(r.sub(n,i));t.length=void 0!==t.length?t.length:o,t.id=t.id||c.nextId(),t.label=t.label||"Constraint",t.type="constraint",t.stiffness=t.stiffness||(t.length>0?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 s={visible:!0,lineWidth:2,strokeStyle:"#ffffff",type:"line",anchors:!0};return 0===t.length&&t.stiffness>.1?(s.type="pin",s.anchors=!1):t.stiffness<.9&&(s.type="spring"),t.render=c.extend(s,t.render),t},i.preSolveAll=function(e){for(var t=0;t0&&(u.position.x+=c.x,u.position.y+=c.y),0!==c.angle&&(o.rotate(u.vertices,c.angle,n.position),l.rotate(u.axes,c.angle),d>0&&r.rotateAbout(u.position,c.angle,n.position,u.position)),a.update(u.bounds,u.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.x,y:(e.bodyA?e.bodyA.position.y:0)+e.pointA.y}},i.pointBWorld=function(e){return{x:(e.bodyB?e.bodyB.position.x:0)+e.pointB.x,y:(e.bodyB?e.bodyB.position.y:0)+e.pointB.y}}},function(e,t,n){var i={};e.exports=i;var o=n(18);i.create=function(e,t){var n=e.bodyA,o=e.bodyB,r=e.parentA,s=e.parentB,a={id:i.id(n,o),bodyA:n,bodyB:o,contacts:{},activeContacts:[],separation:0,isActive:!0,confirmedActive:!0,isSensor:n.isSensor||o.isSensor,timeCreated:t,timeUpdated:t,inverseMass:r.inverseMass+s.inverseMass,friction:Math.min(r.friction,s.friction),frictionStatic:Math.max(r.frictionStatic,s.frictionStatic),restitution:Math.max(r.restitution,s.restitution),slop:Math.max(r.slop,s.slop)};return i.update(a,e,t),a},i.update=function(e,t,n){var r=e.contacts,s=t.supports,a=e.activeContacts,l=t.parentA,c=t.parentB;if(e.collision=t,e.inverseMass=l.inverseMass+c.inverseMass,e.friction=Math.min(l.friction,c.friction),e.frictionStatic=Math.max(l.frictionStatic,c.frictionStatic),e.restitution=Math.max(l.restitution,c.restitution),e.slop=Math.max(l.slop,c.slop),a.length=0,t.collided){for(var d=0;dr.max.x&&(r.max.x=c.x),l.yr.max.y&&(r.max.y=c.y))}var u=r.max.x-r.min.x+2*n.x,p=r.max.y-r.min.y+2*n.y,f=e.canvas.height,v=e.canvas.width/f,m=u/p,y=1,g=1;m>v?g=m/v:y=v/m,e.options.hasBounds=!0,e.bounds.min.x=r.min.x,e.bounds.max.x=r.min.x+u*y,e.bounds.min.y=r.min.y,e.bounds.max.y=r.min.y+p*g,i&&(e.bounds.min.x+=.5*u-u*y*.5,e.bounds.max.x+=.5*u-u*y*.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&&(d.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}),d.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){var t,n=e.engine,o=n.world,u=e.canvas,p=e.context,v=e.options,m=r.allBodies(o),y=r.allConstraints(o),g=v.wireframes?v.wireframeBackground:v.background,x=[],h=[],b={timestamp:n.timing.timestamp};if(a.trigger(e,"beforeRender",b),e.currentBackground!==g&&f(e,g),p.globalCompositeOperation="source-in",p.fillStyle="transparent",p.fillRect(0,0,u.width,u.height),p.globalCompositeOperation="source-over",v.hasBounds){for(t=0;t=500){var d="";s.timing&&(d+="fps: "+Math.round(s.timing.fps)+" "),s.extended&&(s.timing&&(d+="delta: "+s.timing.delta.toFixed(3)+" ",d+="correction: "+s.timing.correction.toFixed(3)+" "),d+="bodies: "+c.length+" ",i.broadphase.controller===l&&(d+="buckets: "+s.buckets+" "),d+="\n",d+="collisions: "+s.collisions+" ",d+="pairs: "+i.pairs.list.length+" ",d+="broad: "+s.broadEff+" ",d+="mid: "+s.midEff+" ",d+="narrow: "+s.narrowEff+" "),e.debugString=d,e.debugTimestamp=i.timing.timestamp}if(e.debugString){n.font="12px Arial",a.wireframes?n.fillStyle="rgba(255,255,255,0.5)":n.fillStyle="rgba(0,0,0,0.5)";for(var u=e.debugString.split("\n"),p=0;p1?1:0;s1?1:0;a1?1:0;r1?1:0;a1?1:0;r1?1:0;r1?1:0;o0)){var d=i.activeContacts[0].vertex.x,u=i.activeContacts[0].vertex.y;2===i.activeContacts.length&&(d=(i.activeContacts[0].vertex.x+i.activeContacts[1].vertex.x)/2,u=(i.activeContacts[0].vertex.y+i.activeContacts[1].vertex.y)/2),o.bodyB===o.supports[0].body||!0===o.bodyA.isStatic?a.moveTo(d-8*o.normal.x,u-8*o.normal.y):a.moveTo(d+8*o.normal.x,u+8*o.normal.y),a.lineTo(d,u)}l.wireframes?a.strokeStyle="rgba(255,165,0,0.7)":a.strokeStyle="orange",a.lineWidth=1,a.stroke()},i.separations=function(e,t,n){var i,o,r,s,a,l=n,c=e.options;for(l.beginPath(),a=0;ad.bounds.max.x||v.bounds.max.yd.bounds.max.y)){var m=i._getRegion(e,v);if(!v.region||m.id!==v.region.id||o){f.broadphaseTests+=1,v.region&&!o||(v.region=m);var y=i._regionUnion(m,v.region);for(s=y.startCol;s<=y.endCol;s++)for(a=y.startRow;a<=y.endRow;a++){l=u[c=i._getBucketId(s,a)];var g=s>=m.startCol&&s<=m.endCol&&a>=m.startRow&&a<=m.endRow,x=s>=v.region.startCol&&s<=v.region.endCol&&a>=v.region.startRow&&a<=v.region.endRow;!g&&x&&x&&l&&i._bucketRemoveBody(e,l,v),(v.region===m||g&&!x||o)&&(l||(l=i._createBucket(u,c)),i._bucketAddBody(e,l,v))}v.region=m,p=!0}}}p&&(e.pairsList=i._createActivePairsList(e))},i.clear=function(e){e.buckets={},e.pairs={},e.pairsList=[]},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),s=Math.max(e.endRow,t.endRow);return i._createRegion(n,o,r,s)},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),s=Math.floor(n.min.y/e.bucketHeight),a=Math.floor(n.max.y/e.bucketHeight);return i._createRegion(o,r,s,a)},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){for(var i=0;i0?i.push(n):delete e.pairs[t[o]];return i}},function(e,t,n){var i={};e.exports=i;var o=n(13),r=n(9),s=n(1);i.collisions=function(e,t){for(var n=[],a=t.pairs.table,l=t.metrics,c=0;c1?1:0;p1?1:0;v0:0!=(e.mask&t.category)&&0!=(t.mask&e.category)}},function(e,t,n){var i={};e.exports=i;var o=n(3),r=n(2);i.collides=function(e,t,n){var s,a,l,c,d=!1;if(n){var u=e.parent,p=t.parent,f=u.speed*u.speed+u.angularSpeed*u.angularSpeed+p.speed*p.speed+p.angularSpeed*p.angularSpeed;d=n&&n.collided&&f<.2,c=n}else c={collided:!1,bodyA:e,bodyB:t};if(n&&d){var v=c.axisBody,m=v===e?t:e,y=[v.axes[n.axisNumber]];if(l=i._overlapAxes(v.vertices,m.vertices,y),c.reused=!0,l.overlap<=0)return c.collided=!1,c}else{if((s=i._overlapAxes(e.vertices,t.vertices,e.axes)).overlap<=0)return c.collided=!1,c;if((a=i._overlapAxes(t.vertices,e.vertices,t.axes)).overlap<=0)return c.collided=!1,c;s.overlapo?o=a:a=0?s.index-1:d.length-1],c.x=o.x-u.x,c.y=o.y-u.y,l=-r.dot(n,c),a=o,o=d[(s.index+1)%d.length],c.x=o.x-u.x,c.y=o.y-u.y,(i=-r.dot(n,c))0&&o.area(M)1?(v=s.create(r.extend({parts:m.slice(0)},c)),s.setPosition(v,{x:e,y:t}),v):m[0]}},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),s=[],a=0;a0&&o.info(s.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),s=i.resolve(t);return s&&!i.versionSatisfies(s.version,r.range)?(o.warn("Plugin.dependencies:",i.toString(s),"does not satisfy",i.toString(r),"used by",i.toString(n)+"."),s._warned=!0,e._warned=!0):s||(o.warn("Plugin.dependencies:",i.toString(t),"used by",i.toString(n),"could not be resolved."),e._warned=!0),r.name}));for(var s=0;s=o[2];if("^"===n.operator)return o[0]>0?s[0]===o[0]&&r.number>=n.number:o[1]>0?s[1]===o[1]&&s[2]>=o[2]:s[2]===o[2]}return e===t||"*"===e}},function(e,t){var n={};e.exports=n,n.create=function(e){return{id:n.id(e),vertex:e,normalImpulse:0,tangentImpulse:0}},n.id=function(e){return e.body.id+"_"+e.index}},function(e,t,n){var i={};e.exports=i;var o=n(5),r=(n(8),n(0));i.create=function(e){var t=o.create(),n={label:"World",gravity:{x:0,y:1,scale:.001},bounds:{min:{x:-1/0,y:-1/0},max:{x:1/0,y:1/0}}};return r.extend(t,n,e)}},function(e,t,n){var i={};e.exports=i;var o=n(9),r=n(0);i._pairMaxIdleLife=1e3,i.create=function(e){return r.extend({table:{},list:[],collisionStart:[],collisionActive:[],collisionEnd:[]},e)},i.update=function(e,t,n){var i,r,s,a,l=e.list,c=e.table,d=e.collisionStart,u=e.collisionEnd,p=e.collisionActive;for(d.length=0,u.length=0,p.length=0,a=0;ai._pairMaxIdleLife&&c.push(s);for(s=0;sf.friction*f.frictionStatic*O*n&&(F=T,E=s.clamp(f.friction*R*n,-F,F));var V=r.cross(P,g),W=r.cross(C,g),q=b/(m.inverseMass+y.inverseMass+m.inverseInertia*V*V+y.inverseInertia*W*W);if(L*=q,E*=q,I<0&&I*I>i._restingThresh*n)S.normalImpulse=0;else{var j=S.normalImpulse;S.normalImpulse=Math.min(S.normalImpulse+L,0),L=S.normalImpulse-j}if(_*_>i._restingThreshTangent*n)S.tangentImpulse=0;else{var D=S.tangentImpulse;S.tangentImpulse=s.clamp(S.tangentImpulse+E,-F,F),E=S.tangentImpulse-D}o.x=g.x*L+x.x*E,o.y=g.y*L+x.y*E,m.isStatic||m.isSleeping||(m.positionPrev.x+=o.x*m.inverseMass,m.positionPrev.y+=o.y*m.inverseMass,m.anglePrev+=r.cross(P,o)*m.inverseInertia),y.isStatic||y.isSleeping||(y.positionPrev.x-=o.x*y.inverseMass,y.positionPrev.y-=o.y*y.inverseMass,y.anglePrev-=r.cross(C,o)*y.inverseInertia)}}}}},function(e,t,n){var i={};e.exports=i;var o=n(19),r=n(7),s=n(21),a=n(10),l=n(20),c=n(23),d=n(11),u=n(4),p=n(5),f=n(8),v=n(0),m=n(6);i.create=function(e,t){t=(t=v.isElement(e)?t:e)||{},((e=v.isElement(e)?e:null)||t.render)&&v.warn("Engine.create: engine.render is deprecated (see docs)");var n={positionIterations:6,velocityIterations:4,constraintIterations:2,enableSleeping:!1,events:[],plugin:{},timing:{timestamp:0,timeScale:1},broadphase:{controller:d}},i=v.extend(n,t);if(e||i.render){var r={element:e,controller:a};i.render=v.extend(r,i.render)}return i.render&&i.render.controller&&(i.render=i.render.controller.create(i.render)),i.render&&(i.render.engine=i),i.world=t.world||o.create(i.world),i.pairs=l.create(),i.broadphase=i.broadphase.controller.create(i.broadphase),i.metrics=i.metrics||{extended:!1},i.metrics=c.create(i.metrics),i},i.update=function(e,t,n){t=t||1e3/60,n=n||1;var o,a=e.world,d=e.timing,v=e.broadphase,m=[];d.timestamp+=t*d.timeScale;var y={timestamp:d.timestamp};u.trigger(e,"beforeUpdate",y);var g=p.allBodies(a),x=p.allConstraints(a);for(c.reset(e.metrics),e.enableSleeping&&r.update(g,d.timeScale),i._bodiesApplyGravity(g,a.gravity),i._bodiesUpdate(g,t,d.timeScale,n,a.bounds),f.preSolveAll(g),o=0;o0&&u.trigger(e,"collisionStart",{pairs:b.collisionStart}),s.preSolvePosition(b.list),o=0;o0&&u.trigger(e,"collisionActive",{pairs:b.collisionActive}),b.collisionEnd.length>0&&u.trigger(e,"collisionEnd",{pairs:b.collisionEnd}),c.update(e.metrics,e),i._bodiesClearForces(g),u.trigger(e,"afterUpdate",y),e},i.merge=function(e,t){if(v.extend(e,t),t.world){e.world=t.world,i.clear(e);for(var n=p.allBodies(e.world),o=0;o1?1:0;de.deltaMax?e.deltaMax:i)/e.delta,e.delta=i),0!==e.timeScalePrev&&(a*=s.timeScale/e.timeScalePrev),0===s.timeScale&&(a=0),e.timeScalePrev=s.timeScale,e.correction=a,e.frameCounter+=1,n-e.counterTimestamp>=1e3&&(e.fps=e.frameCounter*((n-e.counterTimestamp)/1e3),e.counterTimestamp=n,e.frameCounter=0),o.trigger(e,"tick",l),o.trigger(t,"tick",l),t.world.isModified&&t.render&&t.render.controller&&t.render.controller.clear&&t.render.controller.clear(t.render),o.trigger(e,"beforeUpdate",l),r.update(t,i,a),o.trigger(e,"afterUpdate",l),t.render&&t.render.controller&&(o.trigger(e,"beforeRender",l),o.trigger(t,"beforeRender",l),t.render.controller.world(t.render),o.trigger(e,"afterRender",l),o.trigger(t,"afterRender",l)),o.trigger(e,"afterTick",l),o.trigger(t,"afterTick",l)},i.stop=function(e){t(e.frameRequestId)},i.start=function(e,t){i.run(e,t)}}()},function(e,t,n){var i={};e.exports=i;var o=n(5),r=n(8),s=n(0),a=n(6),l=n(16);i.stack=function(e,t,n,i,r,s,l){for(var c,d=o.create({label:"Stack"}),u=e,p=t,f=0,v=0;vm&&(m=x),a.translate(g,{x:.5*h,y:.5*x}),u=g.bounds.max.x+r,o.addBody(d,g),c=g,f+=1}else u+=r}p+=m+s,u=e}return d},i.chain=function(e,t,n,i,a,l){for(var c=e.bodies,d=1;d0)for(c=0;c0&&(p=f[c-1+(l-1)*t],o.addConstraint(e,r.create(s.extend({bodyA:p,bodyB:u},a)))),i&&cp||s<(c=p-c)||s>n-1-c))return 1===u&&a.translate(d,{x:(s+(n%2==1?1:-1))*f,y:0}),l(e+(d?s*f:0)+s*r,i,s,c,d,u)}))},i.newtonsCradle=function(e,t,n,i,s){for(var a=o.create({label:"Newtons Cradle"}),c=0;c1;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),m.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),s=e.getTotalLength(),c=[],n=0;n1?1:0;p + + + @@ -104,6 +107,10 @@ opacity: 0.5; background: transparent !important; } + + .matter-demo canvas { + border: 1px solid rgba(255, 255, 255, 0.07); + } diff --git a/demo/js/Demo.js b/demo/js/Demo.js index 55a9e83..301d69b 100644 --- a/demo/js/Demo.js +++ b/demo/js/Demo.js @@ -100,6 +100,8 @@ examples: examples }); + window.MatterDemo = demo; + document.body.appendChild(demo.dom.root); MatterTools.Demo.start(demo); diff --git a/demo/js/Examples.js b/demo/js/Examples.js new file mode 100644 index 0000000..0aa0cc6 --- /dev/null +++ b/demo/js/Examples.js @@ -0,0 +1,5699 @@ +/*! + * matter-js-examples 0.15.0 by @liabru 2020-12-26 + * 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("Example", [], factory); + else if(typeof exports === 'object') + exports["Example"] = factory(); + else + root["Example"] = 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 = 0); +/******/ }) +/************************************************************************/ +/******/ ([ +/* 0 */ +/***/ (function(module, exports, __webpack_require__) { + +module.exports = { + airFriction: __webpack_require__(1), + avalanche: __webpack_require__(2), + ballPool: __webpack_require__(3), + bridge: __webpack_require__(4), + broadphase: __webpack_require__(5), + car: __webpack_require__(6), + catapult: __webpack_require__(7), + chains: __webpack_require__(8), + circleStack: __webpack_require__(9), + cloth: __webpack_require__(10), + collisionFiltering: __webpack_require__(11), + compositeManipulation: __webpack_require__(12), + compound: __webpack_require__(13), + compoundStack: __webpack_require__(14), + concave: __webpack_require__(15), + constraints: __webpack_require__(16), + doublePendulum: __webpack_require__(17), + events: __webpack_require__(18), + friction: __webpack_require__(19), + gravity: __webpack_require__(20), + gyro: __webpack_require__(21), + manipulation: __webpack_require__(22), + mixed: __webpack_require__(23), + newtonsCradle: __webpack_require__(24), + ragdoll: __webpack_require__(25), + pyramid: __webpack_require__(26), + raycasting: __webpack_require__(27), + restitution: __webpack_require__(28), + rounded: __webpack_require__(29), + sensors: __webpack_require__(30), + sleeping: __webpack_require__(31), + slingshot: __webpack_require__(32), + softBody: __webpack_require__(33), + sprites: __webpack_require__(34), + stack: __webpack_require__(35), + staticFriction: __webpack_require__(36), + stress: __webpack_require__(37), + stress2: __webpack_require__(38), + svg: __webpack_require__(39), + terrain: __webpack_require__(40), + timescale: __webpack_require__(41), + views: __webpack_require__(42), + wreckingBall: __webpack_require__(43) +}; + +/***/ }), +/* 1 */ +/***/ (function(module, exports, __webpack_require__) { + +var Example = Example || {}; + +Example.airFriction = function() { + var Engine = Matter.Engine, + Render = Matter.Render, + Runner = Matter.Runner, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + World = Matter.World, + Bodies = Matter.Bodies; + + // create engine + var engine = Engine.create(), + world = engine.world; + + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: 800, + height: 600, + showVelocity: true + } + }); + + Render.run(render); + + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); + + // add bodies + World.add(world, [ + // falling blocks + Bodies.rectangle(200, 100, 60, 60, { frictionAir: 0.001 }), + Bodies.rectangle(400, 100, 60, 60, { frictionAir: 0.05 }), + Bodies.rectangle(600, 100, 60, 60, { frictionAir: 0.1 }), + + // walls + Bodies.rectangle(400, 0, 800, 50, { isStatic: true }), + Bodies.rectangle(400, 600, 800, 50, { isStatic: true }), + Bodies.rectangle(800, 300, 50, 600, { isStatic: true }), + Bodies.rectangle(0, 300, 50, 600, { isStatic: true }) + ]); + + // add mouse control + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 0.2, + render: { + visible: false + } + } + }); + + World.add(world, mouseConstraint); + + // keep the mouse in sync with rendering + render.mouse = mouse; + + // fit the render viewport to the scene + Render.lookAt(render, { + min: { x: 0, y: 0 }, + max: { x: 800, y: 600 } + }); + + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); + } + }; +}; + +if (true) { + module.exports = Example[Object.keys(Example)[0]]; +} + +/***/ }), +/* 2 */ +/***/ (function(module, exports, __webpack_require__) { + +var Example = Example || {}; + +Example.avalanche = function() { + Matter.use( + 'matter-wrap' + ); + + var Engine = Matter.Engine, + Render = Matter.Render, + Runner = Matter.Runner, + Composite = Matter.Composite, + Composites = Matter.Composites, + Common = Matter.Common, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + World = Matter.World, + Bodies = Matter.Bodies; + + // create engine + var engine = Engine.create(), + world = engine.world; + + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: 800, + height: 600, + showAngleIndicator: true + } + }); + + Render.run(render); + + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); + + // add bodies + var stack = Composites.stack(20, 20, 20, 5, 0, 0, function(x, y) { + return Bodies.circle(x, y, Common.random(10, 20), { friction: 0.00001, restitution: 0.5, density: 0.001 }); + }); + + World.add(world, stack); + + World.add(world, [ + Bodies.rectangle(200, 150, 700, 20, { isStatic: true, angle: Math.PI * 0.06, render: { fillStyle: '#060a19' } }), + Bodies.rectangle(500, 350, 700, 20, { isStatic: true, angle: -Math.PI * 0.06, render: { fillStyle: '#060a19' } }), + Bodies.rectangle(340, 580, 700, 20, { isStatic: true, angle: Math.PI * 0.04, render: { fillStyle: '#060a19' } }) + ]); + + // add mouse control + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 0.2, + render: { + visible: false + } + } + }); + + World.add(world, mouseConstraint); + + // keep the mouse in sync with rendering + render.mouse = mouse; + + // fit the render viewport to the scene + Render.lookAt(render, Composite.allBodies(world)); + + // wrapping using matter-wrap plugin + for (var i = 0; i < stack.bodies.length; i += 1) { + stack.bodies[i].plugin.wrap = { + min: { x: render.bounds.min.x, y: render.bounds.min.y }, + max: { x: render.bounds.max.x, y: render.bounds.max.y } + }; + } + + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); + } + }; +}; + +if (true) { + module.exports = Example[Object.keys(Example)[0]]; +} + +/***/ }), +/* 3 */ +/***/ (function(module, exports, __webpack_require__) { + +var Example = Example || {}; + +Example.ballPool = function() { + Matter.use( + 'matter-wrap' + ); + + var Engine = Matter.Engine, + Render = Matter.Render, + Runner = Matter.Runner, + Composite = Matter.Composite, + Composites = Matter.Composites, + Common = Matter.Common, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + World = Matter.World, + Bodies = Matter.Bodies; + + // create engine + var engine = Engine.create(), + world = engine.world; + + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: 800, + height: 600, + showAngleIndicator: true + } + }); + + Render.run(render); + + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); + + // add bodies + World.add(world, [ + Bodies.rectangle(400, 600, 1200, 50.5, { isStatic: true, render: { fillStyle: '#060a19' } }) + ]); + + var stack = Composites.stack(100, 0, 10, 8, 10, 10, function(x, y) { + return Bodies.circle(x, y, Common.random(15, 30), { restitution: 0.6, friction: 0.1 }); + }); + + World.add(world, [ + stack, + Bodies.polygon(200, 460, 3, 60), + Bodies.polygon(400, 460, 5, 60), + Bodies.rectangle(600, 460, 80, 80) + ]); + + // add mouse control + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 0.2, + render: { + visible: false + } + } + }); + + World.add(world, mouseConstraint); + + // keep the mouse in sync with rendering + render.mouse = mouse; + + // fit the render viewport to the scene + Render.lookAt(render, { + min: { x: 0, y: 0 }, + max: { x: 800, y: 600 } + }); + + // wrapping using matter-wrap plugin + var allBodies = Composite.allBodies(world); + + for (var i = 0; i < allBodies.length; i += 1) { + allBodies[i].plugin.wrap = { + min: { x: render.bounds.min.x - 100, y: render.bounds.min.y }, + max: { x: render.bounds.max.x + 100, y: render.bounds.max.y } + }; + } + + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); + } + }; +}; + +if (true) { + module.exports = Example[Object.keys(Example)[0]]; +} + +/***/ }), +/* 4 */ +/***/ (function(module, exports, __webpack_require__) { + +var Example = Example || {}; + +Example.bridge = function() { + var Engine = Matter.Engine, + Render = Matter.Render, + Runner = Matter.Runner, + Body = Matter.Body, + Composites = Matter.Composites, + Common = Matter.Common, + Constraint = Matter.Constraint, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + World = Matter.World, + Bodies = Matter.Bodies; + + // create engine + var engine = Engine.create(), + world = engine.world; + + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: 800, + height: 600, + showAngleIndicator: true + } + }); + + Render.run(render); + + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); + + // add bodies + var group = Body.nextGroup(true); + + var bridge = Composites.stack(160, 290, 15, 1, 0, 0, function(x, y) { + return Bodies.rectangle(x - 20, y, 53, 20, { + collisionFilter: { group: group }, + chamfer: 5, + density: 0.005, + frictionAir: 0.05, + render: { + fillStyle: '#060a19' + } + }); + }); + + Composites.chain(bridge, 0.3, 0, -0.3, 0, { + stiffness: 1, + length: 0, + render: { + visible: false + } + }); + + var stack = Composites.stack(250, 50, 6, 3, 0, 0, function(x, y) { + return Bodies.rectangle(x, y, 50, 50, Common.random(20, 40)); + }); + + World.add(world, [ + bridge, + stack, + Bodies.rectangle(30, 490, 220, 380, { + isStatic: true, + chamfer: { radius: 20 } + }), + Bodies.rectangle(770, 490, 220, 380, { + isStatic: true, + chamfer: { radius: 20 } + }), + Constraint.create({ + pointA: { x: 140, y: 300 }, + bodyB: bridge.bodies[0], + pointB: { x: -25, y: 0 }, + length: 2, + stiffness: 0.9 + }), + Constraint.create({ + pointA: { x: 660, y: 300 }, + bodyB: bridge.bodies[bridge.bodies.length - 1], + pointB: { x: 25, y: 0 }, + length: 2, + stiffness: 0.9 + }) + ]); + + // add mouse control + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 0.1, + render: { + visible: false + } + } + }); + + World.add(world, mouseConstraint); + + // keep the mouse in sync with rendering + render.mouse = mouse; + + // fit the render viewport to the scene + Render.lookAt(render, { + min: { x: 0, y: 0 }, + max: { x: 800, y: 600 } + }); + + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); + } + }; +}; + +if (true) { + module.exports = Example[Object.keys(Example)[0]]; +} + +/***/ }), +/* 5 */ +/***/ (function(module, exports, __webpack_require__) { + +var Example = Example || {}; + +Example.broadphase = function() { + var Engine = Matter.Engine, + Render = Matter.Render, + Runner = Matter.Runner, + Composites = Matter.Composites, + Common = Matter.Common, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + World = Matter.World, + Bodies = Matter.Bodies; + + // create engine + var engine = Engine.create(), + world = engine.world; + + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: 800, + height: 600, + showAngleIndicator: true, + showBroadphase: true + } + }); + + Render.run(render); + + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); + + // add bodies + World.add(world, [ + // walls + Bodies.rectangle(400, 0, 800, 50, { isStatic: true }), + Bodies.rectangle(400, 600, 800, 50, { isStatic: true }), + Bodies.rectangle(800, 300, 50, 600, { isStatic: true }), + Bodies.rectangle(0, 300, 50, 600, { isStatic: true }) + ]); + + var stack = Composites.stack(20, 20, 12, 5, 0, 0, function(x, y) { + switch (Math.round(Common.random(0, 1))) { + + case 0: + if (Common.random() < 0.8) { + return Bodies.rectangle(x, y, Common.random(20, 50), Common.random(20, 50)); + } else { + return Bodies.rectangle(x, y, Common.random(80, 120), Common.random(20, 30)); + } + case 1: + return Bodies.polygon(x, y, Math.round(Common.random(1, 8)), Common.random(20, 50)); + + } + }); + + World.add(world, stack); + + // add mouse control + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 0.2, + render: { + visible: false + } + } + }); + + World.add(world, mouseConstraint); + + // keep the mouse in sync with rendering + render.mouse = mouse; + + // fit the render viewport to the scene + Render.lookAt(render, { + min: { x: 0, y: 0 }, + max: { x: 800, y: 600 } + }); + + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); + } + }; +}; + +if (true) { + module.exports = Example[Object.keys(Example)[0]]; +} + +/***/ }), +/* 6 */ +/***/ (function(module, exports, __webpack_require__) { + +var Example = Example || {}; + +Example.car = function() { + var Engine = Matter.Engine, + Render = Matter.Render, + Runner = Matter.Runner, + Composites = Matter.Composites, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + World = Matter.World, + Bodies = Matter.Bodies; + + // create engine + var engine = Engine.create(), + world = engine.world; + + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: 800, + height: 600, + showAngleIndicator: true, + showCollisions: true + } + }); + + Render.run(render); + + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); + + // add bodies + World.add(world, [ + // walls + Bodies.rectangle(400, 0, 800, 50, { isStatic: true }), + Bodies.rectangle(400, 600, 800, 50, { isStatic: true }), + Bodies.rectangle(800, 300, 50, 600, { isStatic: true }), + Bodies.rectangle(0, 300, 50, 600, { isStatic: true }) + ]); + + var scale = 0.9; + World.add(world, Composites.car(150, 100, 150 * scale, 30 * scale, 30 * scale)); + + scale = 0.8; + World.add(world, Composites.car(350, 300, 150 * scale, 30 * scale, 30 * scale)); + + World.add(world, [ + Bodies.rectangle(200, 150, 400, 20, { isStatic: true, angle: Math.PI * 0.06, render: { fillStyle: '#060a19' }}), + Bodies.rectangle(500, 350, 650, 20, { isStatic: true, angle: -Math.PI * 0.06, render: { fillStyle: '#060a19' }}), + Bodies.rectangle(300, 560, 600, 20, { isStatic: true, angle: Math.PI * 0.04, render: { fillStyle: '#060a19' }}) + ]); + + // add mouse control + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 0.2, + render: { + visible: false + } + } + }); + + World.add(world, mouseConstraint); + + // keep the mouse in sync with rendering + render.mouse = mouse; + + // fit the render viewport to the scene + Render.lookAt(render, { + min: { x: 0, y: 0 }, + max: { x: 800, y: 600 } + }); + + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); + } + }; +}; + +if (true) { + module.exports = Example[Object.keys(Example)[0]]; +} + +/***/ }), +/* 7 */ +/***/ (function(module, exports, __webpack_require__) { + +var Example = Example || {}; + +Example.catapult = function() { + var Engine = Matter.Engine, + Render = Matter.Render, + Runner = Matter.Runner, + Composites = Matter.Composites, + Constraint = Matter.Constraint, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + World = Matter.World, + Bodies = Matter.Bodies, + Body = Matter.Body, + Vector = Matter.Vector; + + // create engine + var engine = Engine.create(), + world = engine.world; + + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: 800, + height: 600, + showAngleIndicator: true, + showCollisions: true, + showVelocity: true + } + }); + + Render.run(render); + + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); + + // add bodies + var group = Body.nextGroup(true); + + var stack = Composites.stack(250, 255, 1, 6, 0, 0, function(x, y) { + return Bodies.rectangle(x, y, 30, 30); + }); + + var catapult = Bodies.rectangle(400, 520, 320, 20, { collisionFilter: { group: group } }); + + World.add(world, [ + stack, + catapult, + Bodies.rectangle(400, 600, 800, 50.5, { isStatic: true, render: { fillStyle: '#060a19' } }), + Bodies.rectangle(250, 555, 20, 50, { isStatic: true, render: { fillStyle: '#060a19' } }), + Bodies.rectangle(400, 535, 20, 80, { isStatic: true, collisionFilter: { group: group }, render: { fillStyle: '#060a19' } }), + Bodies.circle(560, 100, 50, { density: 0.005 }), + Constraint.create({ + bodyA: catapult, + pointB: Vector.clone(catapult.position), + stiffness: 1, + length: 0 + }) + ]); + + // add mouse control + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 0.2, + render: { + visible: false + } + } + }); + + World.add(world, mouseConstraint); + + // keep the mouse in sync with rendering + render.mouse = mouse; + + // fit the render viewport to the scene + Render.lookAt(render, { + min: { x: 0, y: 0 }, + max: { x: 800, y: 600 } + }); + + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); + } + }; +}; + +if (true) { + module.exports = Example[Object.keys(Example)[0]]; +} + +/***/ }), +/* 8 */ +/***/ (function(module, exports, __webpack_require__) { + +var Example = Example || {}; + +Example.chains = function() { + var Engine = Matter.Engine, + Render = Matter.Render, + Runner = Matter.Runner, + Body = Matter.Body, + Composite = Matter.Composite, + Composites = Matter.Composites, + Constraint = Matter.Constraint, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + World = Matter.World, + Bodies = Matter.Bodies; + + // create engine + var engine = Engine.create(), + world = engine.world; + + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: 800, + height: 600, + showAngleIndicator: true, + showCollisions: true, + showVelocity: true + } + }); + + Render.run(render); + + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); + + // add bodies + var group = Body.nextGroup(true); + + var ropeA = Composites.stack(100, 50, 8, 1, 10, 10, function(x, y) { + return Bodies.rectangle(x, y, 50, 20, { collisionFilter: { group: group } }); + }); + + Composites.chain(ropeA, 0.5, 0, -0.5, 0, { stiffness: 0.8, length: 2, render: { type: 'line' } }); + Composite.add(ropeA, Constraint.create({ + bodyB: ropeA.bodies[0], + pointB: { x: -25, y: 0 }, + pointA: { x: ropeA.bodies[0].position.x, y: ropeA.bodies[0].position.y }, + stiffness: 0.5 + })); + + group = Body.nextGroup(true); + + var ropeB = Composites.stack(350, 50, 10, 1, 10, 10, function(x, y) { + return Bodies.circle(x, y, 20, { collisionFilter: { group: group } }); + }); + + Composites.chain(ropeB, 0.5, 0, -0.5, 0, { stiffness: 0.8, length: 2, render: { type: 'line' } }); + Composite.add(ropeB, Constraint.create({ + bodyB: ropeB.bodies[0], + pointB: { x: -20, y: 0 }, + pointA: { x: ropeB.bodies[0].position.x, y: ropeB.bodies[0].position.y }, + stiffness: 0.5 + })); + + group = Body.nextGroup(true); + + var ropeC = Composites.stack(600, 50, 13, 1, 10, 10, function(x, y) { + return Bodies.rectangle(x - 20, y, 50, 20, { collisionFilter: { group: group }, chamfer: 5 }); + }); + + Composites.chain(ropeC, 0.3, 0, -0.3, 0, { stiffness: 1, length: 0 }); + Composite.add(ropeC, Constraint.create({ + bodyB: ropeC.bodies[0], + pointB: { x: -20, y: 0 }, + pointA: { x: ropeC.bodies[0].position.x, y: ropeC.bodies[0].position.y }, + stiffness: 0.5 + })); + + World.add(world, [ + ropeA, + ropeB, + ropeC, + Bodies.rectangle(400, 600, 1200, 50.5, { isStatic: true }) + ]); + + // add mouse control + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 0.2, + render: { + visible: false + } + } + }); + + World.add(world, mouseConstraint); + + // keep the mouse in sync with rendering + render.mouse = mouse; + + // fit the render viewport to the scene + Render.lookAt(render, { + min: { x: 0, y: 0 }, + max: { x: 700, y: 600 } + }); + + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); + } + }; +}; + +if (true) { + module.exports = Example[Object.keys(Example)[0]]; +} + +/***/ }), +/* 9 */ +/***/ (function(module, exports, __webpack_require__) { + +var Example = Example || {}; + +Example.circleStack = function() { + var Engine = Matter.Engine, + Render = Matter.Render, + Runner = Matter.Runner, + Composites = Matter.Composites, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + World = Matter.World, + Bodies = Matter.Bodies; + + // create engine + var engine = Engine.create(), + world = engine.world; + + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: 800, + height: 600, + showAngleIndicator: true + } + }); + + Render.run(render); + + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); + + // add bodies + var stack = Composites.stack(100, 185, 10, 10, 20, 0, function(x, y) { + return Bodies.circle(x, y, 20); + }); + + World.add(world, [ + // walls + Bodies.rectangle(400, 0, 800, 50, { isStatic: true }), + Bodies.rectangle(400, 600, 800, 50, { isStatic: true }), + Bodies.rectangle(800, 300, 50, 600, { isStatic: true }), + Bodies.rectangle(0, 300, 50, 600, { isStatic: true }), + stack + ]); + + // add mouse control + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 0.2, + render: { + visible: false + } + } + }); + + World.add(world, mouseConstraint); + + // keep the mouse in sync with rendering + render.mouse = mouse; + + // fit the render viewport to the scene + Render.lookAt(render, { + min: { x: 0, y: 0 }, + max: { x: 800, y: 600 } + }); + + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); + } + }; +}; + +if (true) { + module.exports = Example[Object.keys(Example)[0]]; +} + +/***/ }), +/* 10 */ +/***/ (function(module, exports, __webpack_require__) { + +var Example = Example || {}; + +Example.cloth = function() { + var Engine = Matter.Engine, + Render = Matter.Render, + Runner = Matter.Runner, + Body = Matter.Body, + Composites = Matter.Composites, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + World = Matter.World, + Bodies = Matter.Bodies; + + // create engine + var engine = Engine.create(), + world = engine.world; + + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: 800, + height: 600 + } + }); + + Render.run(render); + + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); + + // add bodies + var group = Body.nextGroup(true), + particleOptions = { friction: 0.00001, collisionFilter: { group: group }, render: { visible: false }}, + constraintOptions = { stiffness: 0.06 }, + cloth = Composites.softBody(200, 200, 20, 12, 5, 5, false, 8, particleOptions, constraintOptions); + + for (var i = 0; i < 20; i++) { + cloth.bodies[i].isStatic = true; + } + + World.add(world, [ + cloth, + Bodies.circle(300, 500, 80, { isStatic: true, render: { fillStyle: '#060a19' }}), + Bodies.rectangle(500, 480, 80, 80, { isStatic: true, render: { fillStyle: '#060a19' }}), + Bodies.rectangle(400, 609, 800, 50, { isStatic: true }) + ]); + + // add mouse control + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 0.98, + render: { + visible: false + } + } + }); + + World.add(world, mouseConstraint); + + // keep the mouse in sync with rendering + render.mouse = mouse; + + // fit the render viewport to the scene + Render.lookAt(render, { + min: { x: 0, y: 0 }, + max: { x: 800, y: 600 } + }); + + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); + } + }; +}; + +if (true) { + module.exports = Example[Object.keys(Example)[0]]; +} + +/***/ }), +/* 11 */ +/***/ (function(module, exports, __webpack_require__) { + +var Example = Example || {}; + +Example.collisionFiltering = function() { + var Engine = Matter.Engine, + Render = Matter.Render, + Runner = Matter.Runner, + Composite = Matter.Composite, + Composites = Matter.Composites, + Common = Matter.Common, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + World = Matter.World, + Bodies = Matter.Bodies; + + // create engine + var engine = Engine.create(), + world = engine.world; + + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: 800, + height: 600, + wireframes: false + } + }); + + Render.run(render); + + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); + + // define our categories (as bit fields, there are up to 32 available) + var defaultCategory = 0x0001, + redCategory = 0x0002, + greenCategory = 0x0004, + blueCategory = 0x0008; + + var colorA = '#f55a3c', + colorB = '#063e7b', + colorC = '#f5d259'; + + // add floor + World.add(world, Bodies.rectangle(400, 600, 900, 50, { + isStatic: true, + render: { + fillStyle: 'transparent', + lineWidth: 1 + } + })); + + // create a stack with varying body categories (but these bodies can all collide with each other) + World.add(world, + Composites.stack(275, 100, 5, 9, 10, 10, function(x, y, column, row) { + var category = redCategory, + color = colorA; + + if (row > 5) { + category = blueCategory; + color = colorB; + } else if (row > 2) { + category = greenCategory; + color = colorC; + } + + return Bodies.circle(x, y, 20, { + collisionFilter: { + category: category + }, + render: { + strokeStyle: color, + fillStyle: 'transparent', + lineWidth: 1 + } + }); + }) + ); + + // this body will only collide with the walls and the green bodies + World.add(world, + Bodies.circle(310, 40, 30, { + collisionFilter: { + mask: defaultCategory | greenCategory + }, + render: { + fillStyle: colorC + } + }) + ); + + // this body will only collide with the walls and the red bodies + World.add(world, + Bodies.circle(400, 40, 30, { + collisionFilter: { + mask: defaultCategory | redCategory + }, + render: { + fillStyle: colorA + } + }) + ); + + // this body will only collide with the walls and the blue bodies + World.add(world, + Bodies.circle(480, 40, 30, { + collisionFilter: { + mask: defaultCategory | blueCategory + }, + render: { + fillStyle: colorB + } + }) + ); + + // add mouse control + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 0.2, + render: { + visible: false + } + } + }); + + World.add(world, mouseConstraint); + + // keep the mouse in sync with rendering + render.mouse = mouse; + + // red category objects should not be draggable with the mouse + mouseConstraint.collisionFilter.mask = defaultCategory | blueCategory | greenCategory; + + // fit the render viewport to the scene + Render.lookAt(render, { + min: { x: 0, y: 0 }, + max: { x: 800, y: 600 } + }); + + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); + } + }; +}; + +if (true) { + module.exports = Example[Object.keys(Example)[0]]; +} + +/***/ }), +/* 12 */ +/***/ (function(module, exports, __webpack_require__) { + +var Example = Example || {}; + +Example.compositeManipulation = function() { + var Engine = Matter.Engine, + Render = Matter.Render, + Runner = Matter.Runner, + Events = Matter.Events, + Composite = Matter.Composite, + Composites = Matter.Composites, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + World = Matter.World, + Bodies = Matter.Bodies; + + // create engine + var engine = Engine.create(), + world = engine.world; + + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: 800, + height: 600, + showAngleIndicator: true + } + }); + + Render.run(render); + + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); + + // add bodies + World.add(world, [ + // walls + Bodies.rectangle(400, 0, 800, 50, { isStatic: true }), + Bodies.rectangle(400, 600, 800, 50, { isStatic: true }), + Bodies.rectangle(800, 300, 50, 600, { isStatic: true }), + Bodies.rectangle(0, 300, 50, 600, { isStatic: true }) + ]); + + var stack = Composites.stack(200, 200, 4, 4, 0, 0, function(x, y) { + return Bodies.rectangle(x, y, 40, 40); + }); + + World.add(world, stack); + + world.gravity.y = 0; + + Events.on(engine, 'afterUpdate', function(event) { + var time = engine.timing.timestamp; + + Composite.translate(stack, { + x: Math.sin(time * 0.001) * 2, + y: 0 + }); + + Composite.rotate(stack, Math.sin(time * 0.001) * 0.01, { + x: 300, + y: 300 + }); + + var scale = 1 + (Math.sin(time * 0.001) * 0.01); + + Composite.scale(stack, scale, scale, { + x: 300, + y: 300 + }); + }); + + // add mouse control + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 0.2, + render: { + visible: false + } + } + }); + + World.add(world, mouseConstraint); + + // keep the mouse in sync with rendering + render.mouse = mouse; + + // fit the render viewport to the scene + Render.lookAt(render, { + min: { x: 0, y: 0 }, + max: { x: 800, y: 600 } + }); + + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); + } + }; +}; + +if (true) { + module.exports = Example[Object.keys(Example)[0]]; +} + +/***/ }), +/* 13 */ +/***/ (function(module, exports, __webpack_require__) { + +var Example = Example || {}; + +Example.compound = function() { + var Engine = Matter.Engine, + Render = Matter.Render, + Runner = Matter.Runner, + Body = Matter.Body, + Constraint = Matter.Constraint, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + World = Matter.World, + Bodies = Matter.Bodies; + + // create engine + var engine = Engine.create(), + world = engine.world; + + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: 800, + height: 600, + showAxes: true, + showConvexHulls: true + } + }); + + Render.run(render); + + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); + + // add bodies + var size = 200, + x = 200, + y = 200, + partA = Bodies.rectangle(x, y, size, size / 5), + partB = Bodies.rectangle(x, y, size / 5, size, { render: partA.render }); + + var compoundBodyA = Body.create({ + parts: [partA, partB] + }); + + size = 150; + x = 400; + y = 300; + + var partC = Bodies.circle(x, y, 30), + partD = Bodies.circle(x + size, y, 30), + partE = Bodies.circle(x + size, y + size, 30), + partF = Bodies.circle(x, y + size, 30); + + var compoundBodyB = Body.create({ + parts: [partC, partD, partE, partF] + }); + + var constraint = Constraint.create({ + pointA: { x: 400, y: 100 }, + bodyB: compoundBodyB, + pointB: { x: 0, y: 0 } + }); + + World.add(world, [ + compoundBodyA, + compoundBodyB, + constraint, + Bodies.rectangle(400, 600, 800, 50.5, { isStatic: true }) + ]); + + // add mouse control + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 0.2, + render: { + visible: false + } + } + }); + + World.add(world, mouseConstraint); + + // keep the mouse in sync with rendering + render.mouse = mouse; + + // fit the render viewport to the scene + Render.lookAt(render, { + min: { x: 0, y: 0 }, + max: { x: 800, y: 600 } + }); + + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); + } + }; +}; + +if (true) { + module.exports = Example[Object.keys(Example)[0]]; +} + +/***/ }), +/* 14 */ +/***/ (function(module, exports, __webpack_require__) { + +var Example = Example || {}; + +Example.compoundStack = function() { + var Engine = Matter.Engine, + Render = Matter.Render, + Runner = Matter.Runner, + Body = Matter.Body, + Composites = Matter.Composites, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + World = Matter.World, + Bodies = Matter.Bodies; + + // create engine + var engine = Engine.create(), + world = engine.world; + + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: 800, + height: 600, + showAngleIndicator: true + } + }); + + Render.run(render); + + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); + + // add bodies + var size = 50; + + var stack = Composites.stack(100, 280, 12, 6, 0, 0, function(x, y) { + var partA = Bodies.rectangle(x, y, size, size / 5), + partB = Bodies.rectangle(x, y, size / 5, size, { render: partA.render }); + + return Body.create({ + parts: [partA, partB] + }); + }); + + World.add(world, [ + stack, + // walls + Bodies.rectangle(400, 0, 800, 50, { isStatic: true }), + Bodies.rectangle(800, 300, 50, 600, { isStatic: true }), + Bodies.rectangle(0, 300, 50, 600, { isStatic: true }), + Bodies.rectangle(400, 609, 800, 50, { isStatic: true }) + ]); + + // add mouse control + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 0.2, + render: { + visible: false + } + } + }); + + World.add(world, mouseConstraint); + + // keep the mouse in sync with rendering + render.mouse = mouse; + + // fit the render viewport to the scene + Render.lookAt(render, { + min: { x: 0, y: 0 }, + max: { x: 800, y: 600 } + }); + + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); + } + }; +}; + +if (true) { + module.exports = Example[Object.keys(Example)[0]]; +} + +/***/ }), +/* 15 */ +/***/ (function(module, exports, __webpack_require__) { + +var Example = Example || {}; + +Example.concave = function() { + var Engine = Matter.Engine, + Render = Matter.Render, + Runner = Matter.Runner, + Composites = Matter.Composites, + Common = Matter.Common, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + World = Matter.World, + Vertices = Matter.Vertices, + Bodies = Matter.Bodies; + + // create engine + var engine = Engine.create(), + world = engine.world; + + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: 800, + height: 600 + } + }); + + Render.run(render); + + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); + + // add bodies + World.add(world, [ + // walls + Bodies.rectangle(400, 0, 800, 50, { isStatic: true }), + Bodies.rectangle(400, 600, 800, 50, { isStatic: true }), + Bodies.rectangle(800, 300, 50, 600, { isStatic: true }), + Bodies.rectangle(0, 300, 50, 600, { isStatic: true }) + ]); + + var arrow = Vertices.fromPath('40 0 40 20 100 20 100 80 40 80 40 100 0 50'), + chevron = Vertices.fromPath('100 0 75 50 100 100 25 100 0 50 25 0'), + star = Vertices.fromPath('50 0 63 38 100 38 69 59 82 100 50 75 18 100 31 59 0 38 37 38'), + horseShoe = Vertices.fromPath('35 7 19 17 14 38 14 58 25 79 45 85 65 84 65 66 46 67 34 59 30 44 33 29 45 23 66 23 66 7 53 7'); + + var stack = Composites.stack(50, 50, 6, 4, 10, 10, function(x, y) { + var color = Common.choose(['#f19648', '#f5d259', '#f55a3c', '#063e7b', '#ececd1']); + return Bodies.fromVertices(x, y, Common.choose([arrow, chevron, star, horseShoe]), { + render: { + fillStyle: color, + strokeStyle: color, + lineWidth: 1 + } + }, true); + }); + + World.add(world, stack); + + // add mouse control + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 0.2, + render: { + visible: false + } + } + }); + + World.add(world, mouseConstraint); + + // keep the mouse in sync with rendering + render.mouse = mouse; + + // fit the render viewport to the scene + Render.lookAt(render, { + min: { x: 0, y: 0 }, + max: { x: 800, y: 600 } + }); + + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); + } + }; +}; + +if (true) { + module.exports = Example[Object.keys(Example)[0]]; +} + +/***/ }), +/* 16 */ +/***/ (function(module, exports, __webpack_require__) { + +var Example = Example || {}; + +Example.constraints = function() { + var Engine = Matter.Engine, + Render = Matter.Render, + Runner = Matter.Runner, + Composites = Matter.Composites, + Common = Matter.Common, + Constraint = Matter.Constraint, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + World = Matter.World, + Bodies = Matter.Bodies; + + // create engine + var engine = Engine.create(), + world = engine.world; + + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: 800, + height: 600, + showAngleIndicator: true + } + }); + + Render.run(render); + + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); + + // add stiff global constraint + var body = Bodies.polygon(150, 200, 5, 30); + + var constraint = Constraint.create({ + pointA: { x: 150, y: 100 }, + bodyB: body, + pointB: { x: -10, y: -10 } + }); + + World.add(world, [body, constraint]); + + // add soft global constraint + var body = Bodies.polygon(280, 100, 3, 30); + + var constraint = Constraint.create({ + pointA: { x: 280, y: 120 }, + bodyB: body, + pointB: { x: -10, y: -7 }, + stiffness: 0.001 + }); + + World.add(world, [body, constraint]); + + // add damped soft global constraint + var body = Bodies.polygon(400, 100, 4, 30); + + var constraint = Constraint.create({ + pointA: { x: 400, y: 120 }, + bodyB: body, + pointB: { x: -10, y: -10 }, + stiffness: 0.001, + damping: 0.05 + }); + + World.add(world, [body, constraint]); + + // add revolute constraint + var body = Bodies.rectangle(600, 200, 200, 20); + var ball = Bodies.circle(550, 150, 20); + + var constraint = Constraint.create({ + pointA: { x: 600, y: 200 }, + bodyB: body, + length: 0 + }); + + World.add(world, [body, ball, constraint]); + + // add revolute multi-body constraint + var body = Bodies.rectangle(500, 400, 100, 20, { collisionFilter: { group: -1 } }); + var ball = Bodies.circle(600, 400, 20, { collisionFilter: { group: -1 } }); + + var constraint = Constraint.create({ + bodyA: body, + bodyB: ball + }); + + World.add(world, [body, ball, constraint]); + + // add stiff multi-body constraint + var bodyA = Bodies.polygon(100, 400, 6, 20); + var bodyB = Bodies.polygon(200, 400, 1, 50); + + var constraint = Constraint.create({ + bodyA: bodyA, + pointA: { x: -10, y: -10 }, + bodyB: bodyB, + pointB: { x: -10, y: -10 } + }); + + World.add(world, [bodyA, bodyB, constraint]); + + // add soft global constraint + var bodyA = Bodies.polygon(300, 400, 4, 20); + var bodyB = Bodies.polygon(400, 400, 3, 30); + + var constraint = Constraint.create({ + bodyA: bodyA, + pointA: { x: -10, y: -10 }, + bodyB: bodyB, + pointB: { x: -10, y: -7 }, + stiffness: 0.001 + }); + + World.add(world, [bodyA, bodyB, constraint]); + + // add damped soft global constraint + var bodyA = Bodies.polygon(500, 400, 6, 30); + var bodyB = Bodies.polygon(600, 400, 7, 60); + + var constraint = Constraint.create({ + bodyA: bodyA, + pointA: { x: -10, y: -10 }, + bodyB: bodyB, + pointB: { x: -10, y: -10 }, + stiffness: 0.001, + damping: 0.1 + }); + + World.add(world, [bodyA, bodyB, constraint]); + + World.add(world, [ + // walls + Bodies.rectangle(400, 0, 800, 50, { isStatic: true }), + Bodies.rectangle(400, 600, 800, 50, { isStatic: true }), + Bodies.rectangle(800, 300, 50, 600, { isStatic: true }), + Bodies.rectangle(0, 300, 50, 600, { isStatic: true }) + ]); + + // add mouse control + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + // allow bodies on mouse to rotate + angularStiffness: 0, + render: { + visible: false + } + } + }); + + World.add(world, mouseConstraint); + + // keep the mouse in sync with rendering + render.mouse = mouse; + + // fit the render viewport to the scene + Render.lookAt(render, { + min: { x: 0, y: 0 }, + max: { x: 800, y: 600 } + }); + + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); + } + }; +}; + +if (true) { + module.exports = Example[Object.keys(Example)[0]]; +} + +/***/ }), +/* 17 */ +/***/ (function(module, exports, __webpack_require__) { + +var Example = Example || {}; + +Example.doublePendulum = function() { + var Engine = Matter.Engine, + Events = Matter.Events, + Render = Matter.Render, + Runner = Matter.Runner, + Body = Matter.Body, + Composite = Matter.Composite, + Composites = Matter.Composites, + Constraint = Matter.Constraint, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + World = Matter.World, + Bodies = Matter.Bodies, + Vector = Matter.Vector; + + // create engine + var engine = Engine.create(), + world = engine.world; + + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: 800, + height: 600, + wireframes: false + } + }); + + Render.run(render); + + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); + + // add bodies + var group = Body.nextGroup(true), + length = 200, + width = 25; + + var pendulum = Composites.stack(350, 160, 2, 1, -20, 0, function(x, y) { + return Bodies.rectangle(x, y, length, width, { + collisionFilter: { group: group }, + frictionAir: 0, + chamfer: 5, + render: { + fillStyle: 'transparent', + lineWidth: 1 + } + }); + }); + + world.gravity.scale = 0.002; + + Composites.chain(pendulum, 0.45, 0, -0.45, 0, { + stiffness: 0.9, + length: 0, + angularStiffness: 0.7, + render: { + strokeStyle: '#4a485b' + } + }); + + Composite.add(pendulum, Constraint.create({ + bodyB: pendulum.bodies[0], + pointB: { x: -length * 0.42, y: 0 }, + pointA: { x: pendulum.bodies[0].position.x - length * 0.42, y: pendulum.bodies[0].position.y }, + stiffness: 0.9, + length: 0, + render: { + strokeStyle: '#4a485b' + } + })); + + var lowerArm = pendulum.bodies[1]; + + Body.rotate(lowerArm, -Math.PI * 0.3, { + x: lowerArm.position.x - 100, + y: lowerArm.position.y + }); + + World.add(world, pendulum); + + var trail = []; + + Events.on(render, 'afterRender', function() { + trail.unshift({ + position: Vector.clone(lowerArm.position), + speed: lowerArm.speed + }); + + Render.startViewTransform(render); + render.context.globalAlpha = 0.7; + + for (var i = 0; i < trail.length; i += 1) { + var point = trail[i].position, + speed = trail[i].speed; + + var hue = 250 + Math.round((1 - Math.min(1, speed / 10)) * 170); + render.context.fillStyle = 'hsl(' + hue + ', 100%, 55%)'; + render.context.fillRect(point.x, point.y, 2, 2); + } + + render.context.globalAlpha = 1; + Render.endViewTransform(render); + + if (trail.length > 2000) { + trail.pop(); + } + }); + + // add mouse control + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 0.2, + render: { + visible: false + } + } + }); + + World.add(world, mouseConstraint); + + // keep the mouse in sync with rendering + render.mouse = mouse; + + // fit the render viewport to the scene + Render.lookAt(render, { + min: { x: 0, y: 0 }, + max: { x: 700, y: 600 } + }); + + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); + } + }; +}; + +if (true) { + module.exports = Example[Object.keys(Example)[0]]; +} + +/***/ }), +/* 18 */ +/***/ (function(module, exports, __webpack_require__) { + +var Example = Example || {}; + +Example.events = function() { + var Engine = Matter.Engine, + Render = Matter.Render, + Runner = Matter.Runner, + Body = Matter.Body, + Events = Matter.Events, + Composite = Matter.Composite, + Composites = Matter.Composites, + Common = Matter.Common, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + World = Matter.World, + Bodies = Matter.Bodies; + + // create engine + var engine = Engine.create(), + world = engine.world; + + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: 800, + height: 600, + wireframes: false + } + }); + + Render.run(render); + + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); + + // an example of using composite events on the world + Events.on(world, 'afterAdd', function(event) { + console.log('added to world:', event.object); + }); + + // an example of using beforeUpdate event on an engine + Events.on(engine, 'beforeUpdate', function(event) { + var engine = event.source; + + // apply random forces every 5 secs + if (event.timestamp % 5000 < 50) + shakeScene(engine); + }); + + // an example of using collisionStart event on an engine + Events.on(engine, 'collisionStart', function(event) { + var pairs = event.pairs; + + // change object colours to show those starting a collision + for (var i = 0; i < pairs.length; i++) { + var pair = pairs[i]; + pair.bodyA.render.fillStyle = '#333'; + pair.bodyB.render.fillStyle = '#333'; + } + }); + + // an example of using collisionActive event on an engine + Events.on(engine, 'collisionActive', function(event) { + var pairs = event.pairs; + + // change object colours to show those in an active collision (e.g. resting contact) + for (var i = 0; i < pairs.length; i++) { + var pair = pairs[i]; + pair.bodyA.render.fillStyle = '#333'; + pair.bodyB.render.fillStyle = '#333'; + } + }); + + // an example of using collisionEnd event on an engine + Events.on(engine, 'collisionEnd', function(event) { + var pairs = event.pairs; + + // change object colours to show those ending a collision + for (var i = 0; i < pairs.length; i++) { + var pair = pairs[i]; + + pair.bodyA.render.fillStyle = '#222'; + pair.bodyB.render.fillStyle = '#222'; + } + }); + + var bodyStyle = { fillStyle: '#222' }; + + // scene code + World.add(world, [ + Bodies.rectangle(400, 0, 800, 50, { isStatic: true, render: bodyStyle }), + Bodies.rectangle(400, 600, 800, 50, { isStatic: true, render: bodyStyle }), + Bodies.rectangle(800, 300, 50, 600, { isStatic: true, render: bodyStyle }), + Bodies.rectangle(0, 300, 50, 600, { isStatic: true, render: bodyStyle }) + ]); + + var stack = Composites.stack(70, 100, 9, 4, 50, 50, function(x, y) { + return Bodies.circle(x, y, 15, { restitution: 1, render: bodyStyle }); + }); + + World.add(world, stack); + + var shakeScene = function(engine) { + var bodies = Composite.allBodies(engine.world); + + for (var i = 0; i < bodies.length; i++) { + var body = bodies[i]; + + if (!body.isStatic && body.position.y >= 500) { + var forceMagnitude = 0.02 * body.mass; + + Body.applyForce(body, body.position, { + x: (forceMagnitude + Common.random() * forceMagnitude) * Common.choose([1, -1]), + y: -forceMagnitude + Common.random() * -forceMagnitude + }); + } + } + }; + + // add mouse control + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 0.2, + render: { + visible: false + } + } + }); + + World.add(world, mouseConstraint); + + // keep the mouse in sync with rendering + render.mouse = mouse; + + // an example of using mouse events on a mouse + Events.on(mouseConstraint, 'mousedown', function(event) { + var mousePosition = event.mouse.position; + console.log('mousedown at ' + mousePosition.x + ' ' + mousePosition.y); + shakeScene(engine); + }); + + // an example of using mouse events on a mouse + Events.on(mouseConstraint, 'mouseup', function(event) { + var mousePosition = event.mouse.position; + console.log('mouseup at ' + mousePosition.x + ' ' + mousePosition.y); + }); + + // an example of using mouse events on a mouse + Events.on(mouseConstraint, 'startdrag', function(event) { + console.log('startdrag', event); + }); + + // an example of using mouse events on a mouse + Events.on(mouseConstraint, 'enddrag', function(event) { + console.log('enddrag', event); + }); + + // fit the render viewport to the scene + Render.lookAt(render, { + min: { x: 0, y: 0 }, + max: { x: 800, y: 600 } + }); + + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); + } + }; +}; + +if (true) { + module.exports = Example[Object.keys(Example)[0]]; +} + +/***/ }), +/* 19 */ +/***/ (function(module, exports, __webpack_require__) { + +var Example = Example || {}; + +Example.friction = function() { + var Engine = Matter.Engine, + Render = Matter.Render, + Runner = Matter.Runner, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + World = Matter.World, + Bodies = Matter.Bodies; + + // create engine + var engine = Engine.create(), + world = engine.world; + + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: 800, + height: 600, + showVelocity: true + } + }); + + Render.run(render); + + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); + + // add bodies + World.add(world, [ + // walls + Bodies.rectangle(400, 0, 800, 50, { isStatic: true }), + Bodies.rectangle(400, 600, 800, 50, { isStatic: true }), + Bodies.rectangle(800, 300, 50, 600, { isStatic: true }), + Bodies.rectangle(0, 300, 50, 600, { isStatic: true }) + ]); + + World.add(world, [ + Bodies.rectangle(300, 180, 700, 20, { isStatic: true, angle: Math.PI * 0.06, render: { fillStyle: '#060a19' } }), + Bodies.rectangle(300, 70, 40, 40, { friction: 0.001 }) + ]); + + World.add(world, [ + Bodies.rectangle(300, 350, 700, 20, { isStatic: true, angle: Math.PI * 0.06, render: { fillStyle: '#060a19' } }), + Bodies.rectangle(300, 250, 40, 40, { friction: 0.0005 }) + ]); + + World.add(world, [ + Bodies.rectangle(300, 520, 700, 20, { isStatic: true, angle: Math.PI * 0.06, render: { fillStyle: '#060a19' } }), + Bodies.rectangle(300, 430, 40, 40, { friction: 0 }) + ]); + + // add mouse control + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 0.2, + render: { + visible: false + } + } + }); + + World.add(world, mouseConstraint); + + // keep the mouse in sync with rendering + render.mouse = mouse; + + // fit the render viewport to the scene + Render.lookAt(render, { + min: { x: 0, y: 0 }, + max: { x: 800, y: 600 } + }); + + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); + } + }; +}; + +if (true) { + module.exports = Example[Object.keys(Example)[0]]; +} + +/***/ }), +/* 20 */ +/***/ (function(module, exports, __webpack_require__) { + +var Example = Example || {}; + +Example.gravity = function() { + var Engine = Matter.Engine, + Render = Matter.Render, + Runner = Matter.Runner, + Composites = Matter.Composites, + Common = Matter.Common, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + World = Matter.World, + Bodies = Matter.Bodies; + + // create engine + var engine = Engine.create(), + world = engine.world; + + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: 800, + height: 600, + showVelocity: true, + showAngleIndicator: true + } + }); + + Render.run(render); + + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); + + // add bodies + World.add(world, [ + Bodies.rectangle(400, 0, 800, 50, { isStatic: true }), + Bodies.rectangle(400, 600, 800, 50.5, { isStatic: true }), + Bodies.rectangle(800, 300, 50, 600, { isStatic: true }), + Bodies.rectangle(0, 300, 50, 600, { isStatic: true }) + ]); + + engine.world.gravity.y = -1; + + var stack = Composites.stack(50, 120, 11, 5, 0, 0, function(x, y) { + switch (Math.round(Common.random(0, 1))) { + + case 0: + if (Common.random() < 0.8) { + return Bodies.rectangle(x, y, Common.random(20, 50), Common.random(20, 50)); + } else { + return Bodies.rectangle(x, y, Common.random(80, 120), Common.random(20, 30)); + } + case 1: + return Bodies.polygon(x, y, Math.round(Common.random(1, 8)), Common.random(20, 50)); + + } + }); + + World.add(world, stack); + + // add mouse control + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 0.2, + render: { + visible: false + } + } + }); + + World.add(world, mouseConstraint); + + // keep the mouse in sync with rendering + render.mouse = mouse; + + // fit the render viewport to the scene + Render.lookAt(render, { + min: { x: 0, y: 0 }, + max: { x: 800, y: 600 } + }); + + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); + } + }; +}; + +if (true) { + module.exports = Example[Object.keys(Example)[0]]; +} + +/***/ }), +/* 21 */ +/***/ (function(module, exports, __webpack_require__) { + +var Example = Example || {}; + +Example.gyro = function() { + var Engine = Matter.Engine, + Render = Matter.Render, + Runner = Matter.Runner, + Composites = Matter.Composites, + Common = Matter.Common, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + World = Matter.World, + Bodies = Matter.Bodies; + + // create engine + var engine = Engine.create(), + world = engine.world; + + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: 800, + height: 600, + showAngleIndicator: true + } + }); + + Render.run(render); + + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); + + // add bodies + var stack = Composites.stack(20, 20, 10, 5, 0, 0, function(x, y) { + var sides = Math.round(Common.random(1, 8)); + + // triangles can be a little unstable, so avoid until fixed + sides = (sides === 3) ? 4 : sides; + + // round the edges of some bodies + var chamfer = null; + if (sides > 2 && Common.random() > 0.7) { + chamfer = { + radius: 10 + }; + } + + switch (Math.round(Common.random(0, 1))) { + case 0: + if (Common.random() < 0.8) { + return Bodies.rectangle(x, y, Common.random(25, 50), Common.random(25, 50), { chamfer: chamfer }); + } else { + return Bodies.rectangle(x, y, Common.random(80, 120), Common.random(25, 30), { chamfer: chamfer }); + } + case 1: + return Bodies.polygon(x, y, sides, Common.random(25, 50), { chamfer: chamfer }); + } + }); + + World.add(world, [ + stack, + Bodies.rectangle(400, 0, 800, 50, { isStatic: true }), + Bodies.rectangle(400, 600, 800, 50, { isStatic: true }), + Bodies.rectangle(800, 300, 50, 600, { isStatic: true }), + Bodies.rectangle(0, 300, 50, 600, { isStatic: true }) + ]); + + // add gyro control + if (typeof window !== 'undefined') { + var updateGravity = function(event) { + var orientation = typeof window.orientation !== 'undefined' ? window.orientation : 0, + gravity = engine.world.gravity; + + if (orientation === 0) { + gravity.x = Common.clamp(event.gamma, -90, 90) / 90; + gravity.y = Common.clamp(event.beta, -90, 90) / 90; + } else if (orientation === 180) { + gravity.x = Common.clamp(event.gamma, -90, 90) / 90; + gravity.y = Common.clamp(-event.beta, -90, 90) / 90; + } else if (orientation === 90) { + gravity.x = Common.clamp(event.beta, -90, 90) / 90; + gravity.y = Common.clamp(-event.gamma, -90, 90) / 90; + } else if (orientation === -90) { + gravity.x = Common.clamp(-event.beta, -90, 90) / 90; + gravity.y = Common.clamp(event.gamma, -90, 90) / 90; + } + }; + + window.addEventListener('deviceorientation', updateGravity); + } + + // add mouse control + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 0.2, + render: { + visible: false + } + } + }); + + World.add(world, mouseConstraint); + + // keep the mouse in sync with rendering + render.mouse = mouse; + + // fit the render viewport to the scene + Render.lookAt(render, { + min: { x: 0, y: 0 }, + max: { x: 800, y: 600 } + }); + + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); + if (typeof window !== 'undefined') { + window.removeEventListener('deviceorientation', updateGravity); + } + } + }; +}; + +if (true) { + module.exports = Example[Object.keys(Example)[0]]; +} + +/***/ }), +/* 22 */ +/***/ (function(module, exports, __webpack_require__) { + +var Example = Example || {}; + +Example.manipulation = function() { + var Engine = Matter.Engine, + Render = Matter.Render, + Runner = Matter.Runner, + Body = Matter.Body, + Events = Matter.Events, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + World = Matter.World, + Bodies = Matter.Bodies; + + // create engine + var engine = Engine.create(), + world = engine.world; + + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: 800, + height: 600, + showAxes: true, + showCollisions: true, + showConvexHulls: true + } + }); + + Render.run(render); + + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); + + // add bodies + var bodyA = Bodies.rectangle(100, 200, 50, 50, { isStatic: true, render: { fillStyle: '#060a19' } }), + bodyB = Bodies.rectangle(200, 200, 50, 50), + bodyC = Bodies.rectangle(300, 200, 50, 50), + bodyD = Bodies.rectangle(400, 200, 50, 50), + bodyE = Bodies.rectangle(550, 200, 50, 50), + bodyF = Bodies.rectangle(700, 200, 50, 50), + bodyG = Bodies.circle(400, 100, 25, { render: { fillStyle: '#060a19' } }), + partA = Bodies.rectangle(600, 200, 120, 50, { render: { fillStyle: '#060a19' } }), + partB = Bodies.rectangle(660, 200, 50, 190, { render: { fillStyle: '#060a19' } }), + compound = Body.create({ + parts: [partA, partB], + isStatic: true + }); + + World.add(world, [bodyA, bodyB, bodyC, bodyD, bodyE, bodyF, bodyG, compound]); + + World.add(world, [ + // walls + Bodies.rectangle(400, 0, 800, 50, { isStatic: true }), + Bodies.rectangle(400, 600, 800, 50, { isStatic: true }), + Bodies.rectangle(800, 300, 50, 600, { isStatic: true }), + Bodies.rectangle(0, 300, 50, 600, { isStatic: true }) + ]); + + var counter = 0, + scaleFactor = 1.01; + + Events.on(engine, 'beforeUpdate', function(event) { + counter += 1; + + if (counter === 40) + Body.setStatic(bodyG, true); + + if (scaleFactor > 1) { + Body.scale(bodyF, scaleFactor, scaleFactor); + Body.scale(compound, 0.995, 0.995); + + // modify bodyE vertices + bodyE.vertices[0].x -= 0.2; + bodyE.vertices[0].y -= 0.2; + bodyE.vertices[1].x += 0.2; + bodyE.vertices[1].y -= 0.2; + Body.setVertices(bodyE, bodyE.vertices); + } + + // make bodyA move up and down + // body is static so must manually update velocity for friction to work + var py = 300 + 100 * Math.sin(engine.timing.timestamp * 0.002); + Body.setVelocity(bodyA, { x: 0, y: py - bodyA.position.y }); + Body.setPosition(bodyA, { x: 100, y: py }); + + // make compound body move up and down and rotate constantly + Body.setVelocity(compound, { x: 0, y: py - compound.position.y }); + Body.setAngularVelocity(compound, 0.02); + Body.setPosition(compound, { x: 600, y: py }); + Body.rotate(compound, 0.02); + + // every 1.5 sec + if (counter >= 60 * 1.5) { + Body.setVelocity(bodyB, { x: 0, y: -10 }); + Body.setAngle(bodyC, -Math.PI * 0.26); + Body.setAngularVelocity(bodyD, 0.2); + + // reset counter + counter = 0; + scaleFactor = 1; + } + }); + + // add mouse control + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 0.2, + render: { + visible: false + } + } + }); + + World.add(world, mouseConstraint); + + // keep the mouse in sync with rendering + render.mouse = mouse; + + // fit the render viewport to the scene + Render.lookAt(render, { + min: { x: 0, y: 0 }, + max: { x: 800, y: 600 } + }); + + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); + } + }; +}; + +if (true) { + module.exports = Example[Object.keys(Example)[0]]; +} + +/***/ }), +/* 23 */ +/***/ (function(module, exports, __webpack_require__) { + +var Example = Example || {}; + +Example.mixed = function() { + var Engine = Matter.Engine, + Render = Matter.Render, + Runner = Matter.Runner, + Composites = Matter.Composites, + Common = Matter.Common, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + World = Matter.World, + Bodies = Matter.Bodies; + + // create engine + var engine = Engine.create(), + world = engine.world; + + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: 800, + height: 600, + showAngleIndicator: true, + } + }); + + Render.run(render); + + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); + + // add bodies + var stack = Composites.stack(20, 20, 10, 5, 0, 0, function(x, y) { + var sides = Math.round(Common.random(1, 8)); + + // triangles can be a little unstable, so avoid until fixed + sides = (sides === 3) ? 4 : sides; + + // round the edges of some bodies + var chamfer = null; + if (sides > 2 && Common.random() > 0.7) { + chamfer = { + radius: 10 + }; + } + + switch (Math.round(Common.random(0, 1))) { + case 0: + if (Common.random() < 0.8) { + return Bodies.rectangle(x, y, Common.random(25, 50), Common.random(25, 50), { chamfer: chamfer }); + } else { + return Bodies.rectangle(x, y, Common.random(80, 120), Common.random(25, 30), { chamfer: chamfer }); + } + case 1: + return Bodies.polygon(x, y, sides, Common.random(25, 50), { chamfer: chamfer }); + } + }); + + World.add(world, stack); + + World.add(world, [ + // walls + Bodies.rectangle(400, 0, 800, 50, { isStatic: true }), + Bodies.rectangle(400, 600, 800, 50, { isStatic: true }), + Bodies.rectangle(800, 300, 50, 600, { isStatic: true }), + Bodies.rectangle(0, 300, 50, 600, { isStatic: true }) + ]); + + // add mouse control + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 0.2, + render: { + visible: false + } + } + }); + + World.add(world, mouseConstraint); + + // keep the mouse in sync with rendering + render.mouse = mouse; + + // fit the render viewport to the scene + Render.lookAt(render, { + min: { x: 0, y: 0 }, + max: { x: 800, y: 600 } + }); + + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); + } + }; +}; + +if (true) { + module.exports = Example[Object.keys(Example)[0]]; +} + +/***/ }), +/* 24 */ +/***/ (function(module, exports, __webpack_require__) { + +var Example = Example || {}; + +Example.newtonsCradle = function() { + var Engine = Matter.Engine, + Render = Matter.Render, + Runner = Matter.Runner, + Body = Matter.Body, + Composites = Matter.Composites, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + World = Matter.World; + + // create engine + var engine = Engine.create(), + world = engine.world; + + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: 800, + height: 600, + showVelocity: true + } + }); + + Render.run(render); + + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); + + // add bodies + var cradle = Composites.newtonsCradle(280, 100, 5, 30, 200); + World.add(world, cradle); + Body.translate(cradle.bodies[0], { x: -180, y: -100 }); + + cradle = Composites.newtonsCradle(280, 380, 7, 20, 140); + World.add(world, cradle); + Body.translate(cradle.bodies[0], { x: -140, y: -100 }); + + // add mouse control + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 0.2, + render: { + visible: false + } + } + }); + + World.add(world, mouseConstraint); + + // keep the mouse in sync with rendering + render.mouse = mouse; + + // fit the render viewport to the scene + Render.lookAt(render, { + min: { x: 0, y: 50 }, + max: { x: 800, y: 600 } + }); + + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); + } + }; +}; + +if (true) { + module.exports = Example[Object.keys(Example)[0]]; +} + +/***/ }), +/* 25 */ +/***/ (function(module, exports, __webpack_require__) { + +var Example = Example || {}; + +Example.ragdoll = function() { + var Engine = Matter.Engine, + Events = Matter.Events, + Render = Matter.Render, + Runner = Matter.Runner, + Body = Matter.Body, + Common = Matter.Common, + Composite = Matter.Composite, + Composites = Matter.Composites, + Constraint = Matter.Constraint, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + World = Matter.World, + Bodies = Matter.Bodies, + Vector = Matter.Vector; + + // create engine + var engine = Engine.create(), + world = engine.world; + + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: 800, + height: 600, + showAngleIndicator: true + } + }); + + Render.run(render); + + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); + + // create stairs + var stairCount = (render.bounds.max.y - render.bounds.min.y) / 50; + + var stack = Composites.stack(0, 0, stairCount + 2, 1, 0, 0, function(x, y, column) { + return Bodies.rectangle(x - 50, y + column * 50, 100, 1000, { + isStatic: true, + render: { + fillStyle: '#060a19', + strokeStyle: '#ffffff', + lineWidth: 1 + } + }); + }); + + // create obstacles + var obstacles = Composites.stack(300, 0, 15, 3, 10, 10, function(x, y, column) { + var sides = Math.round(Common.random(1, 8)), + options = { + render: { + fillStyle: Common.choose(['#f19648', '#f5d259', '#f55a3c', '#063e7b', '#ececd1']) + } + }; + + switch (Math.round(Common.random(0, 1))) { + case 0: + if (Common.random() < 0.8) { + return Bodies.rectangle(x, y, Common.random(25, 50), Common.random(25, 50), options); + } else { + return Bodies.rectangle(x, y, Common.random(80, 120), Common.random(25, 30), options); + } + case 1: + return Bodies.polygon(x, y, sides, Common.random(25, 50), options); + } + }); + + var ragdolls = Composite.create(); + + for (var i = 0; i < 1; i += 1) { + var ragdoll = Example.ragdoll.ragdoll(200, -1000 * i, 1.3); + + Composite.add(ragdolls, ragdoll); + } + + World.add(world, [stack, obstacles, ragdolls]); + + var timeScaleTarget = 1, + counter = 0; + + Events.on(engine, 'afterUpdate', function(event) { + // tween the timescale for slow-mo + if (mouse.button === -1) { + engine.timing.timeScale += (timeScaleTarget - engine.timing.timeScale) * 0.05; + } else { + engine.timing.timeScale = 1; + } + + counter += 1; + + // every 1.5 sec + if (counter >= 60 * 1.5) { + + // flip the timescale + if (timeScaleTarget < 1) { + timeScaleTarget = 1; + } else { + timeScaleTarget = 0.05; + } + + // reset counter + counter = 0; + } + + for (var i = 0; i < stack.bodies.length; i += 1) { + var body = stack.bodies[i]; + + // animate stairs + Body.translate(body, { + x: -0.5 * engine.timing.timeScale, + y: -0.5 * engine.timing.timeScale + }); + + // loop stairs when they go off screen + if (body.position.x < -50) { + Body.setPosition(body, { + x: 50 * (stack.bodies.length - 1), + y: 25 + render.bounds.max.y + (body.bounds.max.y - body.bounds.min.y) * 0.5 + }); + + Body.setVelocity(body, { + x: 0, + y: 0 + }); + } + } + + for (i = 0; i < ragdolls.composites.length; i += 1) { + var ragdoll = ragdolls.composites[i], + bounds = Composite.bounds(ragdoll); + + // move ragdolls back to the top of the screen + if (bounds.min.y > render.bounds.max.y + 100) { + Composite.translate(ragdoll, { + x: -bounds.min.x * 0.9, + y: -render.bounds.max.y - 400 + }); + } + } + + for (i = 0; i < obstacles.bodies.length; i += 1) { + var body = obstacles.bodies[i], + bounds = body.bounds; + + // move obstacles back to the top of the screen + if (bounds.min.y > render.bounds.max.y + 100) { + Body.translate(body, { + x: -bounds.min.x, + y: -render.bounds.max.y - 300 + }); + } + } + }); + + // add mouse control and make the mouse revolute + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 0.6, + length: 0, + angularStiffness: 0, + render: { + visible: false + } + } + }); + + World.add(world, mouseConstraint); + + // keep the mouse in sync with rendering + render.mouse = mouse; + + // fit the render viewport to the scene + Render.lookAt(render, { + min: { x: 0, y: 0 }, + max: { x: 800, y: 600 } + }); + + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); + } + }; +}; + +Example.ragdoll.ragdoll = function(x, y, scale, options) { + scale = typeof scale === 'undefined' ? 1 : scale; + + var Body = Matter.Body, + Bodies = Matter.Bodies, + Constraint = Matter.Constraint, + Composite = Matter.Composite, + Common = Matter.Common; + + var headOptions = Common.extend({ + label: 'head', + collisionFilter: { + group: Body.nextGroup(true) + }, + chamfer: { + radius: [15 * scale, 15 * scale, 15 * scale, 15 * scale] + }, + render: { + fillStyle: '#FFBC42' + } + }, options); + + var chestOptions = Common.extend({ + label: 'chest', + collisionFilter: { + group: Body.nextGroup(true) + }, + chamfer: { + radius: [20 * scale, 20 * scale, 26 * scale, 26 * scale] + }, + render: { + fillStyle: '#E0A423' + } + }, options); + + var leftArmOptions = Common.extend({ + label: 'left-arm', + collisionFilter: { + group: Body.nextGroup(true) + }, + chamfer: { + radius: 10 * scale + }, + render: { + fillStyle: '#FFBC42' + } + }, options); + + var leftLowerArmOptions = Common.extend({}, leftArmOptions, { + render: { + fillStyle: '#E59B12' + } + }); + + var rightArmOptions = Common.extend({ + label: 'right-arm', + collisionFilter: { + group: Body.nextGroup(true) + }, + chamfer: { + radius: 10 * scale + }, + render: { + fillStyle: '#FFBC42' + } + }, options); + + var rightLowerArmOptions = Common.extend({}, rightArmOptions, { + render: { + fillStyle: '#E59B12' + } + }); + + var leftLegOptions = Common.extend({ + label: 'left-leg', + collisionFilter: { + group: Body.nextGroup(true) + }, + chamfer: { + radius: 10 * scale + }, + render: { + fillStyle: '#FFBC42' + } + }, options); + + var leftLowerLegOptions = Common.extend({}, leftLegOptions, { + render: { + fillStyle: '#E59B12' + } + }); + + var rightLegOptions = Common.extend({ + label: 'right-leg', + collisionFilter: { + group: Body.nextGroup(true) + }, + chamfer: { + radius: 10 * scale + }, + render: { + fillStyle: '#FFBC42' + } + }, options); + + var rightLowerLegOptions = Common.extend({}, rightLegOptions, { + render: { + fillStyle: '#E59B12' + } + }); + + var head = Bodies.rectangle(x, y - 60 * scale, 34 * scale, 40 * scale, headOptions); + var chest = Bodies.rectangle(x, y, 55 * scale, 80 * scale, chestOptions); + var rightUpperArm = Bodies.rectangle(x + 39 * scale, y - 15 * scale, 20 * scale, 40 * scale, rightArmOptions); + var rightLowerArm = Bodies.rectangle(x + 39 * scale, y + 25 * scale, 20 * scale, 60 * scale, rightLowerArmOptions); + var leftUpperArm = Bodies.rectangle(x - 39 * scale, y - 15 * scale, 20 * scale, 40 * scale, leftArmOptions); + var leftLowerArm = Bodies.rectangle(x - 39 * scale, y + 25 * scale, 20 * scale, 60 * scale, leftLowerArmOptions); + var leftUpperLeg = Bodies.rectangle(x - 20 * scale, y + 57 * scale, 20 * scale, 40 * scale, leftLegOptions); + var leftLowerLeg = Bodies.rectangle(x - 20 * scale, y + 97 * scale, 20 * scale, 60 * scale, leftLowerLegOptions); + var rightUpperLeg = Bodies.rectangle(x + 20 * scale, y + 57 * scale, 20 * scale, 40 * scale, rightLegOptions); + var rightLowerLeg = Bodies.rectangle(x + 20 * scale, y + 97 * scale, 20 * scale, 60 * scale, rightLowerLegOptions); + + var chestToRightUpperArm = Constraint.create({ + bodyA: chest, + pointA: { + x: 24 * scale, + y: -23 * scale + }, + pointB: { + x: 0, + y: -8 * scale + }, + bodyB: rightUpperArm, + stiffness: 0.6, + render: { + visible: false + } + }); + + var chestToLeftUpperArm = Constraint.create({ + bodyA: chest, + pointA: { + x: -24 * scale, + y: -23 * scale + }, + pointB: { + x: 0, + y: -8 * scale + }, + bodyB: leftUpperArm, + stiffness: 0.6, + render: { + visible: false + } + }); + + var chestToLeftUpperLeg = Constraint.create({ + bodyA: chest, + pointA: { + x: -10 * scale, + y: 30 * scale + }, + pointB: { + x: 0, + y: -10 * scale + }, + bodyB: leftUpperLeg, + stiffness: 0.6, + render: { + visible: false + } + }); + + var chestToRightUpperLeg = Constraint.create({ + bodyA: chest, + pointA: { + x: 10 * scale, + y: 30 * scale + }, + pointB: { + x: 0, + y: -10 * scale + }, + bodyB: rightUpperLeg, + stiffness: 0.6, + render: { + visible: false + } + }); + + var upperToLowerRightArm = Constraint.create({ + bodyA: rightUpperArm, + bodyB: rightLowerArm, + pointA: { + x: 0, + y: 15 * scale + }, + pointB: { + x: 0, + y: -25 * scale + }, + stiffness: 0.6, + render: { + visible: false + } + }); + + var upperToLowerLeftArm = Constraint.create({ + bodyA: leftUpperArm, + bodyB: leftLowerArm, + pointA: { + x: 0, + y: 15 * scale + }, + pointB: { + x: 0, + y: -25 * scale + }, + stiffness: 0.6, + render: { + visible: false + } + }); + + var upperToLowerLeftLeg = Constraint.create({ + bodyA: leftUpperLeg, + bodyB: leftLowerLeg, + pointA: { + x: 0, + y: 20 * scale + }, + pointB: { + x: 0, + y: -20 * scale + }, + stiffness: 0.6, + render: { + visible: false + } + }); + + var upperToLowerRightLeg = Constraint.create({ + bodyA: rightUpperLeg, + bodyB: rightLowerLeg, + pointA: { + x: 0, + y: 20 * scale + }, + pointB: { + x: 0, + y: -20 * scale + }, + stiffness: 0.6, + render: { + visible: false + } + }); + + var headContraint = Constraint.create({ + bodyA: head, + pointA: { + x: 0, + y: 25 * scale + }, + pointB: { + x: 0, + y: -35 * scale + }, + bodyB: chest, + stiffness: 0.6, + render: { + visible: false + } + }); + + var legToLeg = Constraint.create({ + bodyA: leftLowerLeg, + bodyB: rightLowerLeg, + stiffness: 0.01, + render: { + visible: false + } + }); + + var person = Composite.create({ + bodies: [ + chest, head, leftLowerArm, leftUpperArm, + rightLowerArm, rightUpperArm, leftLowerLeg, + rightLowerLeg, leftUpperLeg, rightUpperLeg + ], + constraints: [ + upperToLowerLeftArm, upperToLowerRightArm, chestToLeftUpperArm, + chestToRightUpperArm, headContraint, upperToLowerLeftLeg, + upperToLowerRightLeg, chestToLeftUpperLeg, chestToRightUpperLeg, + legToLeg + ] + }); + + return person; +}; + +if (true) { + module.exports = Example[Object.keys(Example)[0]]; +} + +/***/ }), +/* 26 */ +/***/ (function(module, exports, __webpack_require__) { + +var Example = Example || {}; + +Example.pyramid = function() { + var Engine = Matter.Engine, + Render = Matter.Render, + Runner = Matter.Runner, + Composites = Matter.Composites, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + World = Matter.World, + Bodies = Matter.Bodies; + + // create engine + var engine = Engine.create(), + world = engine.world; + + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: 800, + height: 600, + showAngleIndicator: true + } + }); + + Render.run(render); + + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); + + // add bodies + var stack = Composites.pyramid(100, 258, 15, 10, 0, 0, function(x, y) { + return Bodies.rectangle(x, y, 40, 40); + }); + + World.add(world, [ + stack, + // walls + Bodies.rectangle(400, 0, 800, 50, { isStatic: true }), + Bodies.rectangle(800, 300, 50, 600, { isStatic: true }), + Bodies.rectangle(0, 300, 50, 600, { isStatic: true }), + Bodies.rectangle(400, 605, 800, 50, { isStatic: true }) + ]); + + // add mouse control + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 0.2, + render: { + visible: false + } + } + }); + + World.add(world, mouseConstraint); + + // keep the mouse in sync with rendering + render.mouse = mouse; + + // fit the render viewport to the scene + Render.lookAt(render, { + min: { x: 0, y: 0 }, + max: { x: 800, y: 600 } + }); + + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); + } + }; +}; + +if (true) { + module.exports = Example[Object.keys(Example)[0]]; +} + +/***/ }), +/* 27 */ +/***/ (function(module, exports, __webpack_require__) { + +var Example = Example || {}; + +Example.raycasting = function() { + var Engine = Matter.Engine, + Render = Matter.Render, + Runner = Matter.Runner, + Composite = Matter.Composite, + Composites = Matter.Composites, + Common = Matter.Common, + Query = Matter.Query, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + Events = Matter.Events, + World = Matter.World, + Vertices = Matter.Vertices, + Bodies = Matter.Bodies; + + // create engine + var engine = Engine.create(), + world = engine.world; + + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: 800, + height: 600, + showAngleIndicator: true + } + }); + + Render.run(render); + + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); + + // add bodies + var stack = Composites.stack(20, 20, 12, 4, 0, 0, function(x, y) { + switch (Math.round(Common.random(0, 1))) { + + case 0: + if (Common.random() < 0.8) { + return Bodies.rectangle(x, y, Common.random(20, 50), Common.random(20, 50)); + } else { + return Bodies.rectangle(x, y, Common.random(80, 120), Common.random(20, 30)); + } + case 1: + var sides = Math.round(Common.random(1, 8)); + sides = (sides === 3) ? 4 : sides; + return Bodies.polygon(x, y, sides, Common.random(20, 50)); + } + }); + + var star = Vertices.fromPath('50 0 63 38 100 38 69 59 82 100 50 75 18 100 31 59 0 38 37 38'), + concave = Bodies.fromVertices(200, 200, star); + + World.add(world, [ + stack, + concave, + // walls + Bodies.rectangle(400, 0, 800, 50, { isStatic: true }), + Bodies.rectangle(400, 600, 800, 50, { isStatic: true }), + Bodies.rectangle(800, 300, 50, 600, { isStatic: true }), + Bodies.rectangle(0, 300, 50, 600, { isStatic: true }) + ]); + + Events.on(render, 'afterRender', function() { + var mouse = mouseConstraint.mouse, + context = render.context, + bodies = Composite.allBodies(engine.world), + startPoint = { x: 400, y: 100 }, + endPoint = mouse.position; + + var collisions = Query.ray(bodies, startPoint, endPoint); + + Render.startViewTransform(render); + + context.beginPath(); + context.moveTo(startPoint.x, startPoint.y); + context.lineTo(endPoint.x, endPoint.y); + if (collisions.length > 0) { + context.strokeStyle = '#fff'; + } else { + context.strokeStyle = '#555'; + } + context.lineWidth = 0.5; + context.stroke(); + + for (var i = 0; i < collisions.length; i++) { + var collision = collisions[i]; + context.rect(collision.bodyA.position.x - 4.5, collision.bodyA.position.y - 4.5, 8, 8); + } + + context.fillStyle = 'rgba(255,165,0,0.7)'; + context.fill(); + + Render.endViewTransform(render); + }); + + // add mouse control + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 0.2, + render: { + visible: false + } + } + }); + + World.add(world, mouseConstraint); + + // keep the mouse in sync with rendering + render.mouse = mouse; + + // fit the render viewport to the scene + Render.lookAt(render, { + min: { x: 0, y: 0 }, + max: { x: 800, y: 600 } + }); + + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); + } + }; +}; + +if (true) { + module.exports = Example[Object.keys(Example)[0]]; +} + +/***/ }), +/* 28 */ +/***/ (function(module, exports, __webpack_require__) { + +var Example = Example || {}; + +Example.restitution = function() { + var Engine = Matter.Engine, + Render = Matter.Render, + Runner = Matter.Runner, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + World = Matter.World, + Bodies = Matter.Bodies; + + // create engine + var engine = Engine.create(), + world = engine.world; + + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: 800, + height: 600, + showAngleIndicator: true, + showCollisions: true, + showVelocity: true + } + }); + + Render.run(render); + + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); + + // add bodies + var rest = 0.9, + space = 600 / 5; + + World.add(world, [ + Bodies.rectangle(100 + space * 0, 150, 50, 50, { restitution: rest }), + Bodies.rectangle(100 + space * 1, 150, 50, 50, { restitution: rest, angle: -Math.PI * 0.15 }), + Bodies.rectangle(100 + space * 2, 150, 50, 50, { restitution: rest, angle: -Math.PI * 0.25 }), + Bodies.circle(100 + space * 3, 150, 25, { restitution: rest }), + Bodies.rectangle(100 + space * 5, 150, 180, 20, { restitution: rest, angle: -Math.PI * 0.5 }), + // walls + Bodies.rectangle(400, 0, 800, 50, { isStatic: true }), + Bodies.rectangle(400, 600, 800, 50, { isStatic: true }), + Bodies.rectangle(800, 300, 50, 600, { isStatic: true }), + Bodies.rectangle(0, 300, 50, 600, { isStatic: true }) + ]); + + // add mouse control + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 0.2, + render: { + visible: false + } + } + }); + + World.add(world, mouseConstraint); + + // keep the mouse in sync with rendering + render.mouse = mouse; + + // fit the render viewport to the scene + Render.lookAt(render, { + min: { x: 0, y: 0 }, + max: { x: 800, y: 600 } + }); + + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); + } + }; +}; + +if (true) { + module.exports = Example[Object.keys(Example)[0]]; +} + +/***/ }), +/* 29 */ +/***/ (function(module, exports, __webpack_require__) { + +var Example = Example || {}; + +Example.rounded = function() { + var Engine = Matter.Engine, + Render = Matter.Render, + Runner = Matter.Runner, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + World = Matter.World, + Bodies = Matter.Bodies; + + // create engine + var engine = Engine.create(), + world = engine.world; + + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: 800, + height: 600, + showAxes: true + } + }); + + Render.run(render); + + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); + + // add bodies + World.add(world, [ + // walls + Bodies.rectangle(400, 0, 800, 50, { isStatic: true }), + Bodies.rectangle(400, 600, 800, 50, { isStatic: true }), + Bodies.rectangle(800, 300, 50, 600, { isStatic: true }), + Bodies.rectangle(0, 300, 50, 600, { isStatic: true }) + ]); + + World.add(world, [ + Bodies.rectangle(200, 200, 100, 100, { + chamfer: { radius: 20 } + }), + + Bodies.rectangle(300, 200, 100, 100, { + chamfer: { radius: [90, 0, 0, 0] } + }), + + Bodies.rectangle(400, 200, 200, 200, { + chamfer: { radius: [150, 20, 40, 20] } + }), + + Bodies.rectangle(200, 200, 200, 200, { + chamfer: { radius: [150, 20, 150, 20] } + }), + + Bodies.rectangle(300, 200, 200, 50, { + chamfer: { radius: [25, 25, 0, 0] } + }), + + Bodies.polygon(200, 100, 8, 80, { + chamfer: { radius: 30 } + }), + + Bodies.polygon(300, 100, 5, 80, { + chamfer: { radius: [10, 40, 20, 40, 10] } + }), + + Bodies.polygon(400, 200, 3, 50, { + chamfer: { radius: [20, 0, 20] } + }) + ]); + + // add mouse control + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 0.2, + render: { + visible: false + } + } + }); + + World.add(world, mouseConstraint); + + // keep the mouse in sync with rendering + render.mouse = mouse; + + // fit the render viewport to the scene + Render.lookAt(render, { + min: { x: 0, y: 0 }, + max: { x: 800, y: 600 } + }); + + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); + } + }; +}; + +if (true) { + module.exports = Example[Object.keys(Example)[0]]; +} + +/***/ }), +/* 30 */ +/***/ (function(module, exports, __webpack_require__) { + +var Example = Example || {}; + +Example.sensors = function() { + var Engine = Matter.Engine, + Render = Matter.Render, + Runner = Matter.Runner, + Events = Matter.Events, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + World = Matter.World, + Bodies = Matter.Bodies; + + // create engine + var engine = Engine.create(), + world = engine.world; + + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: 800, + height: 600, + wireframes: false + } + }); + + Render.run(render); + + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); + + // add bodies + var colorA = '#f55a3c', + colorB = '#f5d259'; + + var collider = Bodies.rectangle(400, 300, 500, 50, { + isSensor: true, + isStatic: true, + render: { + strokeStyle: colorA, + fillStyle: 'transparent', + lineWidth: 1 + } + }); + + World.add(world, [ + collider, + Bodies.rectangle(400, 600, 800, 50, { + isStatic: true, + render: { + fillStyle: '#060a19', + lineWidth: 0 + } + }) + ]); + + World.add(world, + Bodies.circle(400, 40, 30, { + render: { + strokeStyle: colorB, + fillStyle: 'transparent', + lineWidth: 1 + } + }) + ); + + Events.on(engine, 'collisionStart', function(event) { + var pairs = event.pairs; + + for (var i = 0, j = pairs.length; i != j; ++i) { + var pair = pairs[i]; + + if (pair.bodyA === collider) { + pair.bodyB.render.strokeStyle = colorA; + } else if (pair.bodyB === collider) { + pair.bodyA.render.strokeStyle = colorA; + } + } + }); + + Events.on(engine, 'collisionEnd', function(event) { + var pairs = event.pairs; + + for (var i = 0, j = pairs.length; i != j; ++i) { + var pair = pairs[i]; + + if (pair.bodyA === collider) { + pair.bodyB.render.strokeStyle = colorB; + } else if (pair.bodyB === collider) { + pair.bodyA.render.strokeStyle = colorB; + } + } + }); + + // add mouse control + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 0.2, + render: { + visible: false + } + } + }); + + World.add(world, mouseConstraint); + + // keep the mouse in sync with rendering + render.mouse = mouse; + + // fit the render viewport to the scene + Render.lookAt(render, { + min: { x: 0, y: 0 }, + max: { x: 800, y: 600 } + }); + + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); + } + }; +}; + +if (true) { + module.exports = Example[Object.keys(Example)[0]]; +} + +/***/ }), +/* 31 */ +/***/ (function(module, exports, __webpack_require__) { + +var Example = Example || {}; + +Example.sleeping = function() { + var Engine = Matter.Engine, + Render = Matter.Render, + Runner = Matter.Runner, + Composites = Matter.Composites, + Common = Matter.Common, + Events = Matter.Events, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + World = Matter.World, + Bodies = Matter.Bodies; + + // create engine + var engine = Engine.create({ + enableSleeping: true + }), + world = engine.world; + + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: 800, + height: 600, + showAngleIndicator: true + } + }); + + Render.run(render); + + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); + + // add bodies + World.add(world, [ + // walls + Bodies.rectangle(400, 0, 800, 50, { isStatic: true }), + Bodies.rectangle(400, 600, 800, 50, { isStatic: true }), + Bodies.rectangle(800, 300, 50, 600, { isStatic: true }), + Bodies.rectangle(0, 300, 50, 600, { isStatic: true }) + ]); + + var stack = Composites.stack(50, 50, 12, 3, 0, 0, function(x, y) { + switch (Math.round(Common.random(0, 1))) { + + case 0: + if (Common.random() < 0.8) { + return Bodies.rectangle(x, y, Common.random(20, 50), Common.random(20, 50)); + } else { + return Bodies.rectangle(x, y, Common.random(80, 120), Common.random(20, 30)); + } + case 1: + return Bodies.polygon(x, y, Math.round(Common.random(1, 8)), Common.random(20, 50)); + + } + }); + + World.add(world, stack); + + for (var i = 0; i < stack.bodies.length; i++) { + Events.on(stack.bodies[i], 'sleepStart sleepEnd', function(event) { + var body = this; + console.log('body id', body.id, 'sleeping:', body.isSleeping); + }); + } + + // add mouse control + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 0.2, + render: { + visible: false + } + } + }); + + World.add(world, mouseConstraint); + + // keep the mouse in sync with rendering + render.mouse = mouse; + + // fit the render viewport to the scene + Render.lookAt(render, { + min: { x: 0, y: 0 }, + max: { x: 800, y: 600 } + }); + + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); + } + }; +}; + +if (true) { + module.exports = Example[Object.keys(Example)[0]]; +} + +/***/ }), +/* 32 */ +/***/ (function(module, exports, __webpack_require__) { + +var Example = Example || {}; + +Example.slingshot = function() { + var Engine = Matter.Engine, + Render = Matter.Render, + Runner = Matter.Runner, + Composites = Matter.Composites, + Events = Matter.Events, + Constraint = Matter.Constraint, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + World = Matter.World, + Bodies = Matter.Bodies; + + // create engine + var engine = Engine.create(), + world = engine.world; + + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: 800, + height: 600, + showAngleIndicator: true + } + }); + + Render.run(render); + + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); + + // add bodies + var ground = Bodies.rectangle(395, 600, 815, 50, { isStatic: true, render: { fillStyle: '#060a19' } }), + rockOptions = { density: 0.004 }, + rock = Bodies.polygon(170, 450, 8, 20, rockOptions), + anchor = { x: 170, y: 450 }, + elastic = Constraint.create({ + pointA: anchor, + bodyB: rock, + stiffness: 0.05 + }); + + var pyramid = Composites.pyramid(500, 300, 9, 10, 0, 0, function(x, y) { + return Bodies.rectangle(x, y, 25, 40); + }); + + var ground2 = Bodies.rectangle(610, 250, 200, 20, { isStatic: true, render: { fillStyle: '#060a19' } }); + + var pyramid2 = Composites.pyramid(550, 0, 5, 10, 0, 0, function(x, y) { + return Bodies.rectangle(x, y, 25, 40); + }); + + World.add(engine.world, [ground, pyramid, ground2, pyramid2, rock, elastic]); + + Events.on(engine, 'afterUpdate', function() { + if (mouseConstraint.mouse.button === -1 && (rock.position.x > 190 || rock.position.y < 430)) { + rock = Bodies.polygon(170, 450, 7, 20, rockOptions); + World.add(engine.world, rock); + elastic.bodyB = rock; + } + }); + + // add mouse control + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 0.2, + render: { + visible: false + } + } + }); + + World.add(world, mouseConstraint); + + // keep the mouse in sync with rendering + render.mouse = mouse; + + // fit the render viewport to the scene + Render.lookAt(render, { + min: { x: 0, y: 0 }, + max: { x: 800, y: 600 } + }); + + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); + } + }; +}; + +if (true) { + module.exports = Example[Object.keys(Example)[0]]; +} + +/***/ }), +/* 33 */ +/***/ (function(module, exports, __webpack_require__) { + +var Example = Example || {}; + +Example.softBody = function() { + var Engine = Matter.Engine, + Render = Matter.Render, + Runner = Matter.Runner, + Composites = Matter.Composites, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + World = Matter.World, + Bodies = Matter.Bodies; + + // create engine + var engine = Engine.create(), + world = engine.world; + + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: 800, + height: 600, + showAngleIndicator: false + } + }); + + Render.run(render); + + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); + + // add bodies + var particleOptions = { + friction: 0.05, + frictionStatic: 0.1, + render: { visible: true } + }; + + World.add(world, [ + Composites.softBody(250, 100, 5, 5, 0, 0, true, 18, particleOptions), + Composites.softBody(400, 300, 8, 3, 0, 0, true, 15, particleOptions), + Composites.softBody(250, 400, 4, 4, 0, 0, true, 15, particleOptions), + // walls + Bodies.rectangle(400, 0, 800, 50, { isStatic: true }), + Bodies.rectangle(400, 600, 800, 50, { isStatic: true }), + Bodies.rectangle(800, 300, 50, 600, { isStatic: true }), + Bodies.rectangle(0, 300, 50, 600, { isStatic: true }) + ]); + + // add mouse control + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 0.9, + render: { + visible: false + } + } + }); + + World.add(world, mouseConstraint); + + // keep the mouse in sync with rendering + render.mouse = mouse; + + // fit the render viewport to the scene + Render.lookAt(render, { + min: { x: 0, y: 0 }, + max: { x: 800, y: 600 } + }); + + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); + } + }; +}; + +if (true) { + module.exports = Example[Object.keys(Example)[0]]; +} + +/***/ }), +/* 34 */ +/***/ (function(module, exports, __webpack_require__) { + +var Example = Example || {}; + +Example.sprites = function() { + var Engine = Matter.Engine, + Render = Matter.Render, + Runner = Matter.Runner, + Composites = Matter.Composites, + Common = Matter.Common, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + World = Matter.World, + Bodies = Matter.Bodies; + + // create engine + var engine = Engine.create(), + world = engine.world; + + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: 800, + height: 600, + showAngleIndicator: false, + wireframes: false + } + }); + + Render.run(render); + + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); + + // add bodies + var offset = 10, + options = { + isStatic: true + }; + + world.bodies = []; + + // these static walls will not be rendered in this sprites example, see options + World.add(world, [ + Bodies.rectangle(400, -offset, 800.5 + 2 * offset, 50.5, options), + Bodies.rectangle(400, 600 + offset, 800.5 + 2 * offset, 50.5, options), + Bodies.rectangle(800 + offset, 300, 50.5, 600.5 + 2 * offset, options), + Bodies.rectangle(-offset, 300, 50.5, 600.5 + 2 * offset, options) + ]); + + var stack = Composites.stack(20, 20, 10, 4, 0, 0, function(x, y) { + if (Common.random() > 0.35) { + return Bodies.rectangle(x, y, 64, 64, { + render: { + strokeStyle: '#ffffff', + sprite: { + texture: './img/box.png' + } + } + }); + } else { + return Bodies.circle(x, y, 46, { + density: 0.0005, + frictionAir: 0.06, + restitution: 0.3, + friction: 0.01, + render: { + sprite: { + texture: './img/ball.png' + } + } + }); + } + }); + + World.add(world, stack); + + // add mouse control + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 0.2, + render: { + visible: false + } + } + }); + + World.add(world, mouseConstraint); + + // keep the mouse in sync with rendering + render.mouse = mouse; + + // fit the render viewport to the scene + Render.lookAt(render, { + min: { x: 0, y: 0 }, + max: { x: 800, y: 600 } + }); + + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); + } + }; +}; + +if (true) { + module.exports = Example[Object.keys(Example)[0]]; +} + +/***/ }), +/* 35 */ +/***/ (function(module, exports, __webpack_require__) { + +var Example = Example || {}; + +Example.stack = function() { + var Engine = Matter.Engine, + Render = Matter.Render, + Runner = Matter.Runner, + Composites = Matter.Composites, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + World = Matter.World, + Bodies = Matter.Bodies; + + // create engine + var engine = Engine.create(), + world = engine.world; + + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: 800, + height: 600, + showAngleIndicator: true + } + }); + + Render.run(render); + + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); + + // add bodies + var stack = Composites.stack(200, 380, 10, 5, 0, 0, function(x, y) { + return Bodies.rectangle(x, y, 40, 40); + }); + + World.add(world, [ + stack, + // walls + Bodies.rectangle(400, 0, 800, 50, { isStatic: true }), + Bodies.rectangle(800, 300, 50, 600, { isStatic: true }), + Bodies.rectangle(0, 300, 50, 600, { isStatic: true }), + Bodies.rectangle(400, 606, 800, 50.5, { isStatic: true }) + ]); + + // add mouse control + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 0.2, + render: { + visible: false + } + } + }); + + World.add(world, mouseConstraint); + + // keep the mouse in sync with rendering + render.mouse = mouse; + + // fit the render viewport to the scene + Render.lookAt(render, { + min: { x: 0, y: 0 }, + max: { x: 800, y: 600 } + }); + + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); + } + }; +}; + +if (true) { + module.exports = Example[Object.keys(Example)[0]]; +} + +/***/ }), +/* 36 */ +/***/ (function(module, exports, __webpack_require__) { + +var Example = Example || {}; + +Example.staticFriction = function() { + var Engine = Matter.Engine, + Render = Matter.Render, + Runner = Matter.Runner, + Body = Matter.Body, + Composites = Matter.Composites, + Events = Matter.Events, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + World = Matter.World, + Bodies = Matter.Bodies; + + // create engine + var engine = Engine.create(), + world = engine.world; + + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: 800, + height: 600, + showVelocity: true + } + }); + + Render.run(render); + + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); + + // add bodies + var body = Bodies.rectangle(400, 500, 200, 60, { isStatic: true, chamfer: 10, render: { fillStyle: '#060a19' } }), + size = 50, + counter = -1; + + var stack = Composites.stack(350, 470 - 6 * size, 1, 6, 0, 0, function(x, y) { + return Bodies.rectangle(x, y, size * 2, size, { + slop: 0.5, + friction: 1, + frictionStatic: Infinity + }); + }); + + World.add(world, [ + body, + stack, + // walls + Bodies.rectangle(400, 0, 800, 50, { isStatic: true }), + Bodies.rectangle(400, 600, 800, 50, { isStatic: true }), + Bodies.rectangle(800, 300, 50, 600, { isStatic: true }), + Bodies.rectangle(0, 300, 50, 600, { isStatic: true }) + ]); + + Events.on(engine, 'beforeUpdate', function(event) { + counter += 0.014; + + if (counter < 0) { + return; + } + + var px = 400 + 100 * Math.sin(counter); + + // body is static so must manually update velocity for friction to work + Body.setVelocity(body, { x: px - body.position.x, y: 0 }); + Body.setPosition(body, { x: px, y: body.position.y }); + }); + + // add mouse control + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 0.2, + render: { + visible: false + } + } + }); + + World.add(world, mouseConstraint); + + // keep the mouse in sync with rendering + render.mouse = mouse; + + // fit the render viewport to the scene + Render.lookAt(render, { + min: { x: 0, y: 0 }, + max: { x: 800, y: 600 } + }); + + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); + } + }; +}; + +if (true) { + module.exports = Example[Object.keys(Example)[0]]; +} + +/***/ }), +/* 37 */ +/***/ (function(module, exports, __webpack_require__) { + +var Example = Example || {}; + +Example.stress = function() { + var Engine = Matter.Engine, + Render = Matter.Render, + Runner = Matter.Runner, + Composites = Matter.Composites, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + World = Matter.World, + Bodies = Matter.Bodies; + + // create engine + var engine = Engine.create(), + world = engine.world; + + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: 800, + height: 600 + } + }); + + Render.run(render); + + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); + + // scene code + var stack = Composites.stack(90, 50, 18, 15, 0, 0, function(x, y) { + return Bodies.rectangle(x, y, 35, 35); + }); + + World.add(world, [ + stack, + Bodies.rectangle(400, 0, 800, 50, { isStatic: true }), + Bodies.rectangle(400, 600, 800, 50, { isStatic: true }), + Bodies.rectangle(800, 300, 50, 600, { isStatic: true }), + Bodies.rectangle(0, 300, 50, 600, { isStatic: true }) + ]); + + // add mouse control + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 0.2, + render: { + visible: false + } + } + }); + + World.add(world, mouseConstraint); + + // keep the mouse in sync with rendering + render.mouse = mouse; + + // fit the render viewport to the scene + Render.lookAt(render, { + min: { x: 0, y: 0 }, + max: { x: 800, y: 600 } + }); + + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); + } + }; +}; + +if (true) { + module.exports = Example[Object.keys(Example)[0]]; +} + +/***/ }), +/* 38 */ +/***/ (function(module, exports, __webpack_require__) { + +var Example = Example || {}; + +Example.stress2 = function() { + var Engine = Matter.Engine, + Render = Matter.Render, + Runner = Matter.Runner, + Composites = Matter.Composites, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + World = Matter.World, + Bodies = Matter.Bodies; + + // create engine + var engine = Engine.create(), + world = engine.world; + + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: 800, + height: 600 + } + }); + + Render.run(render); + + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); + + // scene code + var stack = Composites.stack(100, 120, 25, 18, 0, 0, function(x, y) { + return Bodies.rectangle(x, y, 25, 25); + }); + + World.add(world, [ + stack, + Bodies.rectangle(400, 0, 800, 50, { isStatic: true }), + Bodies.rectangle(400, 600, 800, 50, { isStatic: true }), + Bodies.rectangle(800, 300, 50, 600, { isStatic: true }), + Bodies.rectangle(0, 300, 50, 600, { isStatic: true }) + ]); + + // add mouse control + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 0.2, + render: { + visible: false + } + } + }); + + World.add(world, mouseConstraint); + + // keep the mouse in sync with rendering + render.mouse = mouse; + + // fit the render viewport to the scene + Render.lookAt(render, { + min: { x: 0, y: 0 }, + max: { x: 800, y: 600 } + }); + + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); + } + }; +}; + +if (true) { + module.exports = Example[Object.keys(Example)[0]]; +} + +/***/ }), +/* 39 */ +/***/ (function(module, exports, __webpack_require__) { + +var Example = Example || {}; + +Example.svg = function() { + var Engine = Matter.Engine, + Render = Matter.Render, + Runner = Matter.Runner, + Common = Matter.Common, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + World = Matter.World, + Vertices = Matter.Vertices, + Svg = Matter.Svg, + Bodies = Matter.Bodies; + + // create engine + var engine = Engine.create(), + world = engine.world; + + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: 800, + height: 600 + } + }); + + Render.run(render); + + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); + + // add bodies + var svgs = [ + 'iconmonstr-check-mark-8-icon', + 'iconmonstr-paperclip-2-icon', + 'iconmonstr-puzzle-icon', + 'iconmonstr-user-icon' + ]; + + if (typeof $ !== 'undefined') { + for (var i = 0; i < svgs.length; i += 1) { + (function(i) { + $.get('./svg/' + svgs[i] + '.svg').done(function(data) { + var vertexSets = [], + color = Common.choose(['#f19648', '#f5d259', '#f55a3c', '#063e7b', '#ececd1']); + + $(data).find('path').each(function(i, path) { + var points = Svg.pathToVertices(path, 30); + vertexSets.push(Vertices.scale(points, 0.4, 0.4)); + }); + + World.add(world, Bodies.fromVertices(100 + i * 150, 200 + i * 50, vertexSets, { + render: { + fillStyle: color, + strokeStyle: color, + lineWidth: 1 + } + }, true)); + }); + })(i); + } + + $.get('./svg/svg.svg').done(function(data) { + var vertexSets = [], + color = Common.choose(['#f19648', '#f5d259', '#f55a3c', '#063e7b', '#ececd1']); + + $(data).find('path').each(function(i, path) { + vertexSets.push(Svg.pathToVertices(path, 30)); + }); + + World.add(world, Bodies.fromVertices(400, 80, vertexSets, { + render: { + fillStyle: color, + strokeStyle: color, + lineWidth: 1 + } + }, true)); + }); + } + + World.add(world, [ + Bodies.rectangle(400, 0, 800, 50, { isStatic: true }), + Bodies.rectangle(400, 600, 800, 50, { isStatic: true }), + Bodies.rectangle(800, 300, 50, 600, { isStatic: true }), + Bodies.rectangle(0, 300, 50, 600, { isStatic: true }) + ]); + + // add mouse control + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 0.2, + render: { + visible: false + } + } + }); + + World.add(world, mouseConstraint); + + // keep the mouse in sync with rendering + render.mouse = mouse; + + // fit the render viewport to the scene + Render.lookAt(render, { + min: { x: 0, y: 0 }, + max: { x: 800, y: 600 } + }); + + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); + } + }; +}; + +if (true) { + module.exports = Example[Object.keys(Example)[0]]; +} + +/***/ }), +/* 40 */ +/***/ (function(module, exports, __webpack_require__) { + +var Example = Example || {}; + +Example.terrain = function() { + var Engine = Matter.Engine, + Render = Matter.Render, + Runner = Matter.Runner, + Composites = Matter.Composites, + Common = Matter.Common, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + World = Matter.World, + Query = Matter.Query, + Svg = Matter.Svg, + Bodies = Matter.Bodies; + + // create engine + var engine = Engine.create(), + world = engine.world; + + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: 800, + height: 600 + } + }); + + Render.run(render); + + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); + + // add bodies + var terrain; + + if (typeof $ !== 'undefined') { + $.get('./svg/terrain.svg').done(function(data) { + var vertexSets = []; + + $(data).find('path').each(function(i, path) { + vertexSets.push(Svg.pathToVertices(path, 30)); + }); + + terrain = Bodies.fromVertices(400, 350, vertexSets, { + isStatic: true, + render: { + fillStyle: '#060a19', + strokeStyle: '#060a19', + lineWidth: 1 + } + }, true); + + World.add(world, terrain); + + var bodyOptions = { + frictionAir: 0, + friction: 0.0001, + restitution: 0.6 + }; + + World.add(world, Composites.stack(80, 100, 20, 20, 10, 10, function(x, y) { + if (Query.point([terrain], { x: x, y: y }).length === 0) { + return Bodies.polygon(x, y, 5, 12, bodyOptions); + } + })); + }); + } + + // add mouse control + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 0.2, + render: { + visible: false + } + } + }); + + World.add(world, mouseConstraint); + + // keep the mouse in sync with rendering + render.mouse = mouse; + + // fit the render viewport to the scene + Render.lookAt(render, { + min: { x: 0, y: 0 }, + max: { x: 800, y: 600 } + }); + + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); + } + }; +}; + +if (true) { + module.exports = Example[Object.keys(Example)[0]]; +} + +/***/ }), +/* 41 */ +/***/ (function(module, exports, __webpack_require__) { + +var Example = Example || {}; + +Example.timescale = function() { + var Engine = Matter.Engine, + Render = Matter.Render, + Runner = Matter.Runner, + Body = Matter.Body, + Events = Matter.Events, + Composite = Matter.Composite, + Composites = Matter.Composites, + Common = Matter.Common, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + World = Matter.World, + Bodies = Matter.Bodies; + + // create engine + var engine = Engine.create(), + world = engine.world; + + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: 800, + height: 600, + showAngleIndicator: true + } + }); + + Render.run(render); + + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); + + // add bodies + World.add(world, [ + Bodies.rectangle(400, 0, 800, 50, { isStatic: true }), + Bodies.rectangle(400, 600, 800, 50, { isStatic: true }), + Bodies.rectangle(800, 300, 50, 600, { isStatic: true }), + Bodies.rectangle(0, 300, 50, 600, { isStatic: true }) + ]); + + var explosion = function(engine) { + var bodies = Composite.allBodies(engine.world); + + for (var i = 0; i < bodies.length; i++) { + var body = bodies[i]; + + if (!body.isStatic && body.position.y >= 500) { + var forceMagnitude = 0.05 * body.mass; + + Body.applyForce(body, body.position, { + x: (forceMagnitude + Common.random() * forceMagnitude) * Common.choose([1, -1]), + y: -forceMagnitude + Common.random() * -forceMagnitude + }); + } + } + }; + + var timeScaleTarget = 1, + counter = 0; + + + Events.on(engine, 'afterUpdate', function(event) { + // tween the timescale for bullet time slow-mo + engine.timing.timeScale += (timeScaleTarget - engine.timing.timeScale) * 0.05; + + counter += 1; + + // every 1.5 sec + if (counter >= 60 * 1.5) { + + // flip the timescale + if (timeScaleTarget < 1) { + timeScaleTarget = 1; + } else { + timeScaleTarget = 0.05; + } + + // create some random forces + explosion(engine); + + // reset counter + counter = 0; + } + }); + + var bodyOptions = { + frictionAir: 0, + friction: 0.0001, + restitution: 0.8 + }; + + // add some small bouncy circles... remember Swordfish? + World.add(world, Composites.stack(20, 100, 15, 3, 20, 40, function(x, y) { + return Bodies.circle(x, y, Common.random(10, 20), bodyOptions); + })); + + // add some larger random bouncy objects + World.add(world, Composites.stack(50, 50, 8, 3, 0, 0, function(x, y) { + switch (Math.round(Common.random(0, 1))) { + + case 0: + if (Common.random() < 0.8) { + return Bodies.rectangle(x, y, Common.random(20, 50), Common.random(20, 50), bodyOptions); + } else { + return Bodies.rectangle(x, y, Common.random(80, 120), Common.random(20, 30), bodyOptions); + } + case 1: + return Bodies.polygon(x, y, Math.round(Common.random(4, 8)), Common.random(20, 50), bodyOptions); + + } + })); + + // add mouse control + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 0.2, + render: { + visible: false + } + } + }); + + World.add(world, mouseConstraint); + + // keep the mouse in sync with rendering + render.mouse = mouse; + + // fit the render viewport to the scene + Render.lookAt(render, { + min: { x: 0, y: 0 }, + max: { x: 800, y: 600 } + }); + + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); + } + }; +}; + +if (true) { + module.exports = Example[Object.keys(Example)[0]]; +} + +/***/ }), +/* 42 */ +/***/ (function(module, exports, __webpack_require__) { + +var Example = Example || {}; + +Example.views = function() { + var Engine = Matter.Engine, + Render = Matter.Render, + Runner = Matter.Runner, + Events = Matter.Events, + Composites = Matter.Composites, + Common = Matter.Common, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + World = Matter.World, + Vector = Matter.Vector, + Bounds = Matter.Bounds, + Bodies = Matter.Bodies; + + // create engine + var engine = Engine.create(), + world = engine.world; + + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: 800, + height: 600, + hasBounds: true, + showAngleIndicator: true + } + }); + + Render.run(render); + + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); + + // add mouse control + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 0.2, + render: { + visible: false + } + } + }); + + World.add(world, mouseConstraint); + + // keep the mouse in sync with rendering + render.mouse = mouse; + + // add bodies + var stack = Composites.stack(20, 20, 15, 4, 0, 0, function(x, y) { + switch (Math.round(Common.random(0, 1))) { + + case 0: + if (Common.random() < 0.8) { + return Bodies.rectangle(x, y, Common.random(20, 50), Common.random(20, 50)); + } else { + return Bodies.rectangle(x, y, Common.random(80, 120), Common.random(20, 30)); + } + case 1: + var sides = Math.round(Common.random(1, 8)); + sides = (sides === 3) ? 4 : sides; + return Bodies.polygon(x, y, sides, Common.random(20, 50)); + } + }); + + World.add(world, [ + stack, + // walls + Bodies.rectangle(400, 0, 800, 50, { isStatic: true }), + Bodies.rectangle(400, 600, 800, 50, { isStatic: true }), + Bodies.rectangle(800, 300, 50, 600, { isStatic: true }), + Bodies.rectangle(0, 300, 50, 600, { isStatic: true }) + ]); + + // get the centre of the viewport + var viewportCentre = { + x: render.options.width * 0.5, + y: render.options.height * 0.5 + }; + + // make the world bounds a little bigger than the render bounds + world.bounds.min.x = -300; + world.bounds.min.y = -300; + world.bounds.max.x = 1100; + world.bounds.max.y = 900; + + // keep track of current bounds scale (view zoom) + var boundsScaleTarget = 1, + boundsScale = { + x: 1, + y: 1 + }; + + // use the engine tick event to control our view + Events.on(engine, 'beforeTick', function() { + var world = engine.world, + mouse = mouseConstraint.mouse, + translate; + + // mouse wheel controls zoom + var scaleFactor = mouse.wheelDelta * -0.1; + if (scaleFactor !== 0) { + if ((scaleFactor < 0 && boundsScale.x >= 0.6) || (scaleFactor > 0 && boundsScale.x <= 1.4)) { + boundsScaleTarget += scaleFactor; + } + } + + // if scale has changed + if (Math.abs(boundsScale.x - boundsScaleTarget) > 0.01) { + // smoothly tween scale factor + scaleFactor = (boundsScaleTarget - boundsScale.x) * 0.2; + boundsScale.x += scaleFactor; + boundsScale.y += scaleFactor; + + // scale the render bounds + render.bounds.max.x = render.bounds.min.x + render.options.width * boundsScale.x; + render.bounds.max.y = render.bounds.min.y + render.options.height * boundsScale.y; + + // translate so zoom is from centre of view + translate = { + x: render.options.width * scaleFactor * -0.5, + y: render.options.height * scaleFactor * -0.5 + }; + + Bounds.translate(render.bounds, translate); + + // update mouse + Mouse.setScale(mouse, boundsScale); + Mouse.setOffset(mouse, render.bounds.min); + } + + // get vector from mouse relative to centre of viewport + var deltaCentre = Vector.sub(mouse.absolute, viewportCentre), + centreDist = Vector.magnitude(deltaCentre); + + // translate the view if mouse has moved over 50px from the centre of viewport + if (centreDist > 50) { + // create a vector to translate the view, allowing the user to control view speed + var direction = Vector.normalise(deltaCentre), + speed = Math.min(10, Math.pow(centreDist - 50, 2) * 0.0002); + + translate = Vector.mult(direction, speed); + + // prevent the view moving outside the world bounds + if (render.bounds.min.x + translate.x < world.bounds.min.x) + translate.x = world.bounds.min.x - render.bounds.min.x; + + if (render.bounds.max.x + translate.x > world.bounds.max.x) + translate.x = world.bounds.max.x - render.bounds.max.x; + + if (render.bounds.min.y + translate.y < world.bounds.min.y) + translate.y = world.bounds.min.y - render.bounds.min.y; + + if (render.bounds.max.y + translate.y > world.bounds.max.y) + translate.y = world.bounds.max.y - render.bounds.max.y; + + // move the view + Bounds.translate(render.bounds, translate); + + // we must update the mouse too + Mouse.setOffset(mouse, render.bounds.min); + } + }); + + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); + } + }; +}; + +if (true) { + module.exports = Example[Object.keys(Example)[0]]; +} + +/***/ }), +/* 43 */ +/***/ (function(module, exports, __webpack_require__) { + +var Example = Example || {}; + +Example.wreckingBall = function() { + var Engine = Matter.Engine, + Render = Matter.Render, + Runner = Matter.Runner, + Composites = Matter.Composites, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + World = Matter.World, + Constraint = Matter.Constraint, + Bodies = Matter.Bodies; + + // create engine + var engine = Engine.create(), + world = engine.world; + + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: 800, + height: 600, + showAngleIndicator: true + } + }); + + Render.run(render); + + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); + + // add bodies + var rows = 10, + yy = 600 - 21 - 40 * rows; + + var stack = Composites.stack(400, yy, 5, rows, 0, 0, function(x, y) { + return Bodies.rectangle(x, y, 40, 40); + }); + + World.add(world, [ + stack, + // walls + Bodies.rectangle(400, 0, 800, 50, { isStatic: true }), + Bodies.rectangle(400, 600, 800, 50, { isStatic: true }), + Bodies.rectangle(800, 300, 50, 600, { isStatic: true }), + Bodies.rectangle(0, 300, 50, 600, { isStatic: true }) + ]); + + var ball = Bodies.circle(100, 400, 50, { density: 0.04, frictionAir: 0.005}); + + World.add(world, ball); + World.add(world, Constraint.create({ + pointA: { x: 300, y: 100 }, + bodyB: ball + })); + + // add mouse control + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 0.2, + render: { + visible: false + } + } + }); + + World.add(world, mouseConstraint); + + // keep the mouse in sync with rendering + render.mouse = mouse; + + // fit the render viewport to the scene + Render.lookAt(render, { + min: { x: 0, y: 0 }, + max: { x: 800, y: 600 } + }); + + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); + } + }; +}; + +if (true) { + module.exports = Example[Object.keys(Example)[0]]; +} + +/***/ }) +/******/ ]); +}); \ No newline at end of file diff --git a/demo/js/Server.js b/demo/js/Server.js new file mode 100644 index 0000000..afcc7f2 --- /dev/null +++ b/demo/js/Server.js @@ -0,0 +1,3 @@ +// bundle entry point for the development server +Example = require('../../examples/index.js'); +module.exports = require('../../src/module/main.js'); diff --git a/demo/lib/jquery-1.11.0.min.js b/demo/lib/jquery-1.11.0.min.js deleted file mode 100644 index 73f33fb..0000000 --- a/demo/lib/jquery-1.11.0.min.js +++ /dev/null @@ -1,4 +0,0 @@ -/*! jQuery v1.11.0 | (c) 2005, 2014 jQuery Foundation, Inc. | jquery.org/license */ -!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=c.slice,e=c.concat,f=c.push,g=c.indexOf,h={},i=h.toString,j=h.hasOwnProperty,k="".trim,l={},m="1.11.0",n=function(a,b){return new n.fn.init(a,b)},o=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,p=/^-ms-/,q=/-([\da-z])/gi,r=function(a,b){return b.toUpperCase()};n.fn=n.prototype={jquery:m,constructor:n,selector:"",length:0,toArray:function(){return d.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:d.call(this)},pushStack:function(a){var b=n.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a,b){return n.each(this,a,b)},map:function(a){return this.pushStack(n.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:c.sort,splice:c.splice},n.extend=n.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||n.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(e=arguments[h]))for(d in e)a=g[d],c=e[d],g!==c&&(j&&c&&(n.isPlainObject(c)||(b=n.isArray(c)))?(b?(b=!1,f=a&&n.isArray(a)?a:[]):f=a&&n.isPlainObject(a)?a:{},g[d]=n.extend(j,f,c)):void 0!==c&&(g[d]=c));return g},n.extend({expando:"jQuery"+(m+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===n.type(a)},isArray:Array.isArray||function(a){return"array"===n.type(a)},isWindow:function(a){return null!=a&&a==a.window},isNumeric:function(a){return a-parseFloat(a)>=0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},isPlainObject:function(a){var b;if(!a||"object"!==n.type(a)||a.nodeType||n.isWindow(a))return!1;try{if(a.constructor&&!j.call(a,"constructor")&&!j.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}if(l.ownLast)for(b in a)return j.call(a,b);for(b in a);return void 0===b||j.call(a,b)},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?h[i.call(a)]||"object":typeof a},globalEval:function(b){b&&n.trim(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(p,"ms-").replace(q,r)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b,c){var d,e=0,f=a.length,g=s(a);if(c){if(g){for(;f>e;e++)if(d=b.apply(a[e],c),d===!1)break}else for(e in a)if(d=b.apply(a[e],c),d===!1)break}else if(g){for(;f>e;e++)if(d=b.call(a[e],e,a[e]),d===!1)break}else for(e in a)if(d=b.call(a[e],e,a[e]),d===!1)break;return a},trim:k&&!k.call("\ufeff\xa0")?function(a){return null==a?"":k.call(a)}:function(a){return null==a?"":(a+"").replace(o,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(s(Object(a))?n.merge(c,"string"==typeof a?[a]:a):f.call(c,a)),c},inArray:function(a,b,c){var d;if(b){if(g)return g.call(b,a,c);for(d=b.length,c=c?0>c?Math.max(0,d+c):c:0;d>c;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,b){var c=+b.length,d=0,e=a.length;while(c>d)a[e++]=b[d++];if(c!==c)while(void 0!==b[d])a[e++]=b[d++];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,f=0,g=a.length,h=s(a),i=[];if(h)for(;g>f;f++)d=b(a[f],f,c),null!=d&&i.push(d);else for(f in a)d=b(a[f],f,c),null!=d&&i.push(d);return e.apply([],i)},guid:1,proxy:function(a,b){var c,e,f;return"string"==typeof b&&(f=a[b],b=a,a=f),n.isFunction(a)?(c=d.call(arguments,2),e=function(){return a.apply(b||this,c.concat(d.call(arguments)))},e.guid=a.guid=a.guid||n.guid++,e):void 0},now:function(){return+new Date},support:l}),n.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(a,b){h["[object "+b+"]"]=b.toLowerCase()});function s(a){var b=a.length,c=n.type(a);return"function"===c||n.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var t=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s="sizzle"+-new Date,t=a.document,u=0,v=0,w=eb(),x=eb(),y=eb(),z=function(a,b){return a===b&&(j=!0),0},A="undefined",B=1<<31,C={}.hasOwnProperty,D=[],E=D.pop,F=D.push,G=D.push,H=D.slice,I=D.indexOf||function(a){for(var b=0,c=this.length;c>b;b++)if(this[b]===a)return b;return-1},J="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",K="[\\x20\\t\\r\\n\\f]",L="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",M=L.replace("w","w#"),N="\\["+K+"*("+L+")"+K+"*(?:([*^$|!~]?=)"+K+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+M+")|)|)"+K+"*\\]",O=":("+L+")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|"+N.replace(3,8)+")*)|.*)\\)|)",P=new RegExp("^"+K+"+|((?:^|[^\\\\])(?:\\\\.)*)"+K+"+$","g"),Q=new RegExp("^"+K+"*,"+K+"*"),R=new RegExp("^"+K+"*([>+~]|"+K+")"+K+"*"),S=new RegExp("="+K+"*([^\\]'\"]*?)"+K+"*\\]","g"),T=new RegExp(O),U=new RegExp("^"+M+"$"),V={ID:new RegExp("^#("+L+")"),CLASS:new RegExp("^\\.("+L+")"),TAG:new RegExp("^("+L.replace("w","w*")+")"),ATTR:new RegExp("^"+N),PSEUDO:new RegExp("^"+O),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+K+"*(even|odd|(([+-]|)(\\d*)n|)"+K+"*(?:([+-]|)"+K+"*(\\d+)|))"+K+"*\\)|)","i"),bool:new RegExp("^(?:"+J+")$","i"),needsContext:new RegExp("^"+K+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+K+"*((?:-\\d)?\\d*)"+K+"*\\)|)(?=[^-]|$)","i")},W=/^(?:input|select|textarea|button)$/i,X=/^h\d$/i,Y=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,$=/[+~]/,_=/'|\\/g,ab=new RegExp("\\\\([\\da-f]{1,6}"+K+"?|("+K+")|.)","ig"),bb=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)};try{G.apply(D=H.call(t.childNodes),t.childNodes),D[t.childNodes.length].nodeType}catch(cb){G={apply:D.length?function(a,b){F.apply(a,H.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function db(a,b,d,e){var f,g,h,i,j,m,p,q,u,v;if((b?b.ownerDocument||b:t)!==l&&k(b),b=b||l,d=d||[],!a||"string"!=typeof a)return d;if(1!==(i=b.nodeType)&&9!==i)return[];if(n&&!e){if(f=Z.exec(a))if(h=f[1]){if(9===i){if(g=b.getElementById(h),!g||!g.parentNode)return d;if(g.id===h)return d.push(g),d}else if(b.ownerDocument&&(g=b.ownerDocument.getElementById(h))&&r(b,g)&&g.id===h)return d.push(g),d}else{if(f[2])return G.apply(d,b.getElementsByTagName(a)),d;if((h=f[3])&&c.getElementsByClassName&&b.getElementsByClassName)return G.apply(d,b.getElementsByClassName(h)),d}if(c.qsa&&(!o||!o.test(a))){if(q=p=s,u=b,v=9===i&&a,1===i&&"object"!==b.nodeName.toLowerCase()){m=ob(a),(p=b.getAttribute("id"))?q=p.replace(_,"\\$&"):b.setAttribute("id",q),q="[id='"+q+"'] ",j=m.length;while(j--)m[j]=q+pb(m[j]);u=$.test(a)&&mb(b.parentNode)||b,v=m.join(",")}if(v)try{return G.apply(d,u.querySelectorAll(v)),d}catch(w){}finally{p||b.removeAttribute("id")}}}return xb(a.replace(P,"$1"),b,d,e)}function eb(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function fb(a){return a[s]=!0,a}function gb(a){var b=l.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function hb(a,b){var c=a.split("|"),e=a.length;while(e--)d.attrHandle[c[e]]=b}function ib(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||B)-(~a.sourceIndex||B);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function jb(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function kb(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function lb(a){return fb(function(b){return b=+b,fb(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function mb(a){return a&&typeof a.getElementsByTagName!==A&&a}c=db.support={},f=db.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},k=db.setDocument=function(a){var b,e=a?a.ownerDocument||a:t,g=e.defaultView;return e!==l&&9===e.nodeType&&e.documentElement?(l=e,m=e.documentElement,n=!f(e),g&&g!==g.top&&(g.addEventListener?g.addEventListener("unload",function(){k()},!1):g.attachEvent&&g.attachEvent("onunload",function(){k()})),c.attributes=gb(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=gb(function(a){return a.appendChild(e.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=Y.test(e.getElementsByClassName)&&gb(function(a){return a.innerHTML="
",a.firstChild.className="i",2===a.getElementsByClassName("i").length}),c.getById=gb(function(a){return m.appendChild(a).id=s,!e.getElementsByName||!e.getElementsByName(s).length}),c.getById?(d.find.ID=function(a,b){if(typeof b.getElementById!==A&&n){var c=b.getElementById(a);return c&&c.parentNode?[c]:[]}},d.filter.ID=function(a){var b=a.replace(ab,bb);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(ab,bb);return function(a){var c=typeof a.getAttributeNode!==A&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return typeof b.getElementsByTagName!==A?b.getElementsByTagName(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return typeof b.getElementsByClassName!==A&&n?b.getElementsByClassName(a):void 0},p=[],o=[],(c.qsa=Y.test(e.querySelectorAll))&&(gb(function(a){a.innerHTML="",a.querySelectorAll("[t^='']").length&&o.push("[*^$]="+K+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||o.push("\\["+K+"*(?:value|"+J+")"),a.querySelectorAll(":checked").length||o.push(":checked")}),gb(function(a){var b=e.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&o.push("name"+K+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||o.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),o.push(",.*:")})),(c.matchesSelector=Y.test(q=m.webkitMatchesSelector||m.mozMatchesSelector||m.oMatchesSelector||m.msMatchesSelector))&&gb(function(a){c.disconnectedMatch=q.call(a,"div"),q.call(a,"[s!='']:x"),p.push("!=",O)}),o=o.length&&new RegExp(o.join("|")),p=p.length&&new RegExp(p.join("|")),b=Y.test(m.compareDocumentPosition),r=b||Y.test(m.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},z=b?function(a,b){if(a===b)return j=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===e||a.ownerDocument===t&&r(t,a)?-1:b===e||b.ownerDocument===t&&r(t,b)?1:i?I.call(i,a)-I.call(i,b):0:4&d?-1:1)}:function(a,b){if(a===b)return j=!0,0;var c,d=0,f=a.parentNode,g=b.parentNode,h=[a],k=[b];if(!f||!g)return a===e?-1:b===e?1:f?-1:g?1:i?I.call(i,a)-I.call(i,b):0;if(f===g)return ib(a,b);c=a;while(c=c.parentNode)h.unshift(c);c=b;while(c=c.parentNode)k.unshift(c);while(h[d]===k[d])d++;return d?ib(h[d],k[d]):h[d]===t?-1:k[d]===t?1:0},e):l},db.matches=function(a,b){return db(a,null,null,b)},db.matchesSelector=function(a,b){if((a.ownerDocument||a)!==l&&k(a),b=b.replace(S,"='$1']"),!(!c.matchesSelector||!n||p&&p.test(b)||o&&o.test(b)))try{var d=q.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return db(b,l,null,[a]).length>0},db.contains=function(a,b){return(a.ownerDocument||a)!==l&&k(a),r(a,b)},db.attr=function(a,b){(a.ownerDocument||a)!==l&&k(a);var e=d.attrHandle[b.toLowerCase()],f=e&&C.call(d.attrHandle,b.toLowerCase())?e(a,b,!n):void 0;return void 0!==f?f:c.attributes||!n?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},db.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},db.uniqueSort=function(a){var b,d=[],e=0,f=0;if(j=!c.detectDuplicates,i=!c.sortStable&&a.slice(0),a.sort(z),j){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return i=null,a},e=db.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=db.selectors={cacheLength:50,createPseudo:fb,match:V,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(ab,bb),a[3]=(a[4]||a[5]||"").replace(ab,bb),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||db.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&db.error(a[0]),a},PSEUDO:function(a){var b,c=!a[5]&&a[2];return V.CHILD.test(a[0])?null:(a[3]&&void 0!==a[4]?a[2]=a[4]:c&&T.test(c)&&(b=ob(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(ab,bb).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=w[a+" "];return b||(b=new RegExp("(^|"+K+")"+a+"("+K+"|$)"))&&w(a,function(a){return b.test("string"==typeof a.className&&a.className||typeof a.getAttribute!==A&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=db.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),t=!i&&!h;if(q){if(f){while(p){l=b;while(l=l[p])if(h?l.nodeName.toLowerCase()===r:1===l.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&t){k=q[s]||(q[s]={}),j=k[a]||[],n=j[0]===u&&j[1],m=j[0]===u&&j[2],l=n&&q.childNodes[n];while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if(1===l.nodeType&&++m&&l===b){k[a]=[u,n,m];break}}else if(t&&(j=(b[s]||(b[s]={}))[a])&&j[0]===u)m=j[1];else while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if((h?l.nodeName.toLowerCase()===r:1===l.nodeType)&&++m&&(t&&((l[s]||(l[s]={}))[a]=[u,m]),l===b))break;return m-=e,m===d||m%d===0&&m/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||db.error("unsupported pseudo: "+a);return e[s]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?fb(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=I.call(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:fb(function(a){var b=[],c=[],d=g(a.replace(P,"$1"));return d[s]?fb(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),!c.pop()}}),has:fb(function(a){return function(b){return db(a,b).length>0}}),contains:fb(function(a){return function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:fb(function(a){return U.test(a||"")||db.error("unsupported lang: "+a),a=a.replace(ab,bb).toLowerCase(),function(b){var c;do if(c=n?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===m},focus:function(a){return a===l.activeElement&&(!l.hasFocus||l.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return X.test(a.nodeName)},input:function(a){return W.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:lb(function(){return[0]}),last:lb(function(a,b){return[b-1]}),eq:lb(function(a,b,c){return[0>c?c+b:c]}),even:lb(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:lb(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:lb(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:lb(function(a,b,c){for(var d=0>c?c+b:c;++db;b++)d+=a[b].value;return d}function qb(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=v++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j=[u,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(i=b[s]||(b[s]={}),(h=i[d])&&h[0]===u&&h[1]===f)return j[2]=h[2];if(i[d]=j,j[2]=a(b,c,g))return!0}}}function rb(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function sb(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function tb(a,b,c,d,e,f){return d&&!d[s]&&(d=tb(d)),e&&!e[s]&&(e=tb(e,f)),fb(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||wb(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:sb(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=sb(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?I.call(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=sb(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):G.apply(g,r)})}function ub(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],i=g||d.relative[" "],j=g?1:0,k=qb(function(a){return a===b},i,!0),l=qb(function(a){return I.call(b,a)>-1},i,!0),m=[function(a,c,d){return!g&&(d||c!==h)||((b=c).nodeType?k(a,c,d):l(a,c,d))}];f>j;j++)if(c=d.relative[a[j].type])m=[qb(rb(m),c)];else{if(c=d.filter[a[j].type].apply(null,a[j].matches),c[s]){for(e=++j;f>e;e++)if(d.relative[a[e].type])break;return tb(j>1&&rb(m),j>1&&pb(a.slice(0,j-1).concat({value:" "===a[j-2].type?"*":""})).replace(P,"$1"),c,e>j&&ub(a.slice(j,e)),f>e&&ub(a=a.slice(e)),f>e&&pb(a))}m.push(c)}return rb(m)}function vb(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,i,j,k){var m,n,o,p=0,q="0",r=f&&[],s=[],t=h,v=f||e&&d.find.TAG("*",k),w=u+=null==t?1:Math.random()||.1,x=v.length;for(k&&(h=g!==l&&g);q!==x&&null!=(m=v[q]);q++){if(e&&m){n=0;while(o=a[n++])if(o(m,g,i)){j.push(m);break}k&&(u=w)}c&&((m=!o&&m)&&p--,f&&r.push(m))}if(p+=q,c&&q!==p){n=0;while(o=b[n++])o(r,s,g,i);if(f){if(p>0)while(q--)r[q]||s[q]||(s[q]=E.call(j));s=sb(s)}G.apply(j,s),k&&!f&&s.length>0&&p+b.length>1&&db.uniqueSort(j)}return k&&(u=w,h=t),r};return c?fb(f):f}g=db.compile=function(a,b){var c,d=[],e=[],f=y[a+" "];if(!f){b||(b=ob(a)),c=b.length;while(c--)f=ub(b[c]),f[s]?d.push(f):e.push(f);f=y(a,vb(e,d))}return f};function wb(a,b,c){for(var d=0,e=b.length;e>d;d++)db(a,b[d],c);return c}function xb(a,b,e,f){var h,i,j,k,l,m=ob(a);if(!f&&1===m.length){if(i=m[0]=m[0].slice(0),i.length>2&&"ID"===(j=i[0]).type&&c.getById&&9===b.nodeType&&n&&d.relative[i[1].type]){if(b=(d.find.ID(j.matches[0].replace(ab,bb),b)||[])[0],!b)return e;a=a.slice(i.shift().value.length)}h=V.needsContext.test(a)?0:i.length;while(h--){if(j=i[h],d.relative[k=j.type])break;if((l=d.find[k])&&(f=l(j.matches[0].replace(ab,bb),$.test(i[0].type)&&mb(b.parentNode)||b))){if(i.splice(h,1),a=f.length&&pb(i),!a)return G.apply(e,f),e;break}}}return g(a,m)(f,b,!n,e,$.test(a)&&mb(b.parentNode)||b),e}return c.sortStable=s.split("").sort(z).join("")===s,c.detectDuplicates=!!j,k(),c.sortDetached=gb(function(a){return 1&a.compareDocumentPosition(l.createElement("div"))}),gb(function(a){return a.innerHTML="","#"===a.firstChild.getAttribute("href")})||hb("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&gb(function(a){return a.innerHTML="",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||hb("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),gb(function(a){return null==a.getAttribute("disabled")})||hb(J,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),db}(a);n.find=t,n.expr=t.selectors,n.expr[":"]=n.expr.pseudos,n.unique=t.uniqueSort,n.text=t.getText,n.isXMLDoc=t.isXML,n.contains=t.contains;var u=n.expr.match.needsContext,v=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,w=/^.[^:#\[\.,]*$/;function x(a,b,c){if(n.isFunction(b))return n.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return n.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(w.test(b))return n.filter(b,a,c);b=n.filter(b,a)}return n.grep(a,function(a){return n.inArray(a,b)>=0!==c})}n.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?n.find.matchesSelector(d,a)?[d]:[]:n.find.matches(a,n.grep(b,function(a){return 1===a.nodeType}))},n.fn.extend({find:function(a){var b,c=[],d=this,e=d.length;if("string"!=typeof a)return this.pushStack(n(a).filter(function(){for(b=0;e>b;b++)if(n.contains(d[b],this))return!0}));for(b=0;e>b;b++)n.find(a,d[b],c);return c=this.pushStack(e>1?n.unique(c):c),c.selector=this.selector?this.selector+" "+a:a,c},filter:function(a){return this.pushStack(x(this,a||[],!1))},not:function(a){return this.pushStack(x(this,a||[],!0))},is:function(a){return!!x(this,"string"==typeof a&&u.test(a)?n(a):a||[],!1).length}});var y,z=a.document,A=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,B=n.fn.init=function(a,b){var c,d;if(!a)return this;if("string"==typeof a){if(c="<"===a.charAt(0)&&">"===a.charAt(a.length-1)&&a.length>=3?[null,a,null]:A.exec(a),!c||!c[1]&&b)return!b||b.jquery?(b||y).find(a):this.constructor(b).find(a);if(c[1]){if(b=b instanceof n?b[0]:b,n.merge(this,n.parseHTML(c[1],b&&b.nodeType?b.ownerDocument||b:z,!0)),v.test(c[1])&&n.isPlainObject(b))for(c in b)n.isFunction(this[c])?this[c](b[c]):this.attr(c,b[c]);return this}if(d=z.getElementById(c[2]),d&&d.parentNode){if(d.id!==c[2])return y.find(a);this.length=1,this[0]=d}return this.context=z,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):n.isFunction(a)?"undefined"!=typeof y.ready?y.ready(a):a(n):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),n.makeArray(a,this))};B.prototype=n.fn,y=n(z);var C=/^(?:parents|prev(?:Until|All))/,D={children:!0,contents:!0,next:!0,prev:!0};n.extend({dir:function(a,b,c){var d=[],e=a[b];while(e&&9!==e.nodeType&&(void 0===c||1!==e.nodeType||!n(e).is(c)))1===e.nodeType&&d.push(e),e=e[b];return d},sibling:function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c}}),n.fn.extend({has:function(a){var b,c=n(a,this),d=c.length;return this.filter(function(){for(b=0;d>b;b++)if(n.contains(this,c[b]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=u.test(a)||"string"!=typeof a?n(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&n.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?n.unique(f):f)},index:function(a){return a?"string"==typeof a?n.inArray(this[0],n(a)):n.inArray(a.jquery?a[0]:a,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(n.unique(n.merge(this.get(),n(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function E(a,b){do a=a[b];while(a&&1!==a.nodeType);return a}n.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return n.dir(a,"parentNode")},parentsUntil:function(a,b,c){return n.dir(a,"parentNode",c)},next:function(a){return E(a,"nextSibling")},prev:function(a){return E(a,"previousSibling")},nextAll:function(a){return n.dir(a,"nextSibling")},prevAll:function(a){return n.dir(a,"previousSibling")},nextUntil:function(a,b,c){return n.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return n.dir(a,"previousSibling",c)},siblings:function(a){return n.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return n.sibling(a.firstChild)},contents:function(a){return n.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:n.merge([],a.childNodes)}},function(a,b){n.fn[a]=function(c,d){var e=n.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=n.filter(d,e)),this.length>1&&(D[a]||(e=n.unique(e)),C.test(a)&&(e=e.reverse())),this.pushStack(e)}});var F=/\S+/g,G={};function H(a){var b=G[a]={};return n.each(a.match(F)||[],function(a,c){b[c]=!0}),b}n.Callbacks=function(a){a="string"==typeof a?G[a]||H(a):n.extend({},a);var b,c,d,e,f,g,h=[],i=!a.once&&[],j=function(l){for(c=a.memory&&l,d=!0,f=g||0,g=0,e=h.length,b=!0;h&&e>f;f++)if(h[f].apply(l[0],l[1])===!1&&a.stopOnFalse){c=!1;break}b=!1,h&&(i?i.length&&j(i.shift()):c?h=[]:k.disable())},k={add:function(){if(h){var d=h.length;!function f(b){n.each(b,function(b,c){var d=n.type(c);"function"===d?a.unique&&k.has(c)||h.push(c):c&&c.length&&"string"!==d&&f(c)})}(arguments),b?e=h.length:c&&(g=d,j(c))}return this},remove:function(){return h&&n.each(arguments,function(a,c){var d;while((d=n.inArray(c,h,d))>-1)h.splice(d,1),b&&(e>=d&&e--,f>=d&&f--)}),this},has:function(a){return a?n.inArray(a,h)>-1:!(!h||!h.length)},empty:function(){return h=[],e=0,this},disable:function(){return h=i=c=void 0,this},disabled:function(){return!h},lock:function(){return i=void 0,c||k.disable(),this},locked:function(){return!i},fireWith:function(a,c){return!h||d&&!i||(c=c||[],c=[a,c.slice?c.slice():c],b?i.push(c):j(c)),this},fire:function(){return k.fireWith(this,arguments),this},fired:function(){return!!d}};return k},n.extend({Deferred:function(a){var b=[["resolve","done",n.Callbacks("once memory"),"resolved"],["reject","fail",n.Callbacks("once memory"),"rejected"],["notify","progress",n.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return n.Deferred(function(c){n.each(b,function(b,f){var g=n.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&n.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?n.extend(a,d):d}},e={};return d.pipe=d.then,n.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=d.call(arguments),e=c.length,f=1!==e||a&&n.isFunction(a.promise)?e:0,g=1===f?a:n.Deferred(),h=function(a,b,c){return function(e){b[a]=this,c[a]=arguments.length>1?d.call(arguments):e,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(e>1)for(i=new Array(e),j=new Array(e),k=new Array(e);e>b;b++)c[b]&&n.isFunction(c[b].promise)?c[b].promise().done(h(b,k,c)).fail(g.reject).progress(h(b,j,i)):--f;return f||g.resolveWith(k,c),g.promise()}});var I;n.fn.ready=function(a){return n.ready.promise().done(a),this},n.extend({isReady:!1,readyWait:1,holdReady:function(a){a?n.readyWait++:n.ready(!0)},ready:function(a){if(a===!0?!--n.readyWait:!n.isReady){if(!z.body)return setTimeout(n.ready);n.isReady=!0,a!==!0&&--n.readyWait>0||(I.resolveWith(z,[n]),n.fn.trigger&&n(z).trigger("ready").off("ready"))}}});function J(){z.addEventListener?(z.removeEventListener("DOMContentLoaded",K,!1),a.removeEventListener("load",K,!1)):(z.detachEvent("onreadystatechange",K),a.detachEvent("onload",K))}function K(){(z.addEventListener||"load"===event.type||"complete"===z.readyState)&&(J(),n.ready())}n.ready.promise=function(b){if(!I)if(I=n.Deferred(),"complete"===z.readyState)setTimeout(n.ready);else if(z.addEventListener)z.addEventListener("DOMContentLoaded",K,!1),a.addEventListener("load",K,!1);else{z.attachEvent("onreadystatechange",K),a.attachEvent("onload",K);var c=!1;try{c=null==a.frameElement&&z.documentElement}catch(d){}c&&c.doScroll&&!function e(){if(!n.isReady){try{c.doScroll("left")}catch(a){return setTimeout(e,50)}J(),n.ready()}}()}return I.promise(b)};var L="undefined",M;for(M in n(l))break;l.ownLast="0"!==M,l.inlineBlockNeedsLayout=!1,n(function(){var a,b,c=z.getElementsByTagName("body")[0];c&&(a=z.createElement("div"),a.style.cssText="border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px",b=z.createElement("div"),c.appendChild(a).appendChild(b),typeof b.style.zoom!==L&&(b.style.cssText="border:0;margin:0;width:1px;padding:1px;display:inline;zoom:1",(l.inlineBlockNeedsLayout=3===b.offsetWidth)&&(c.style.zoom=1)),c.removeChild(a),a=b=null)}),function(){var a=z.createElement("div");if(null==l.deleteExpando){l.deleteExpando=!0;try{delete a.test}catch(b){l.deleteExpando=!1}}a=null}(),n.acceptData=function(a){var b=n.noData[(a.nodeName+" ").toLowerCase()],c=+a.nodeType||1;return 1!==c&&9!==c?!1:!b||b!==!0&&a.getAttribute("classid")===b};var N=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,O=/([A-Z])/g;function P(a,b,c){if(void 0===c&&1===a.nodeType){var d="data-"+b.replace(O,"-$1").toLowerCase();if(c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:N.test(c)?n.parseJSON(c):c}catch(e){}n.data(a,b,c)}else c=void 0}return c}function Q(a){var b;for(b in a)if(("data"!==b||!n.isEmptyObject(a[b]))&&"toJSON"!==b)return!1;return!0}function R(a,b,d,e){if(n.acceptData(a)){var f,g,h=n.expando,i=a.nodeType,j=i?n.cache:a,k=i?a[h]:a[h]&&h;if(k&&j[k]&&(e||j[k].data)||void 0!==d||"string"!=typeof b)return k||(k=i?a[h]=c.pop()||n.guid++:h),j[k]||(j[k]=i?{}:{toJSON:n.noop}),("object"==typeof b||"function"==typeof b)&&(e?j[k]=n.extend(j[k],b):j[k].data=n.extend(j[k].data,b)),g=j[k],e||(g.data||(g.data={}),g=g.data),void 0!==d&&(g[n.camelCase(b)]=d),"string"==typeof b?(f=g[b],null==f&&(f=g[n.camelCase(b)])):f=g,f -}}function S(a,b,c){if(n.acceptData(a)){var d,e,f=a.nodeType,g=f?n.cache:a,h=f?a[n.expando]:n.expando;if(g[h]){if(b&&(d=c?g[h]:g[h].data)){n.isArray(b)?b=b.concat(n.map(b,n.camelCase)):b in d?b=[b]:(b=n.camelCase(b),b=b in d?[b]:b.split(" ")),e=b.length;while(e--)delete d[b[e]];if(c?!Q(d):!n.isEmptyObject(d))return}(c||(delete g[h].data,Q(g[h])))&&(f?n.cleanData([a],!0):l.deleteExpando||g!=g.window?delete g[h]:g[h]=null)}}}n.extend({cache:{},noData:{"applet ":!0,"embed ":!0,"object ":"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(a){return a=a.nodeType?n.cache[a[n.expando]]:a[n.expando],!!a&&!Q(a)},data:function(a,b,c){return R(a,b,c)},removeData:function(a,b){return S(a,b)},_data:function(a,b,c){return R(a,b,c,!0)},_removeData:function(a,b){return S(a,b,!0)}}),n.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=n.data(f),1===f.nodeType&&!n._data(f,"parsedAttrs"))){c=g.length;while(c--)d=g[c].name,0===d.indexOf("data-")&&(d=n.camelCase(d.slice(5)),P(f,d,e[d]));n._data(f,"parsedAttrs",!0)}return e}return"object"==typeof a?this.each(function(){n.data(this,a)}):arguments.length>1?this.each(function(){n.data(this,a,b)}):f?P(f,a,n.data(f,a)):void 0},removeData:function(a){return this.each(function(){n.removeData(this,a)})}}),n.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=n._data(a,b),c&&(!d||n.isArray(c)?d=n._data(a,b,n.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=n.queue(a,b),d=c.length,e=c.shift(),f=n._queueHooks(a,b),g=function(){n.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return n._data(a,c)||n._data(a,c,{empty:n.Callbacks("once memory").add(function(){n._removeData(a,b+"queue"),n._removeData(a,c)})})}}),n.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.lengthh;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f},X=/^(?:checkbox|radio)$/i;!function(){var a=z.createDocumentFragment(),b=z.createElement("div"),c=z.createElement("input");if(b.setAttribute("className","t"),b.innerHTML="
a",l.leadingWhitespace=3===b.firstChild.nodeType,l.tbody=!b.getElementsByTagName("tbody").length,l.htmlSerialize=!!b.getElementsByTagName("link").length,l.html5Clone="<:nav>"!==z.createElement("nav").cloneNode(!0).outerHTML,c.type="checkbox",c.checked=!0,a.appendChild(c),l.appendChecked=c.checked,b.innerHTML="",l.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue,a.appendChild(b),b.innerHTML="",l.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,l.noCloneEvent=!0,b.attachEvent&&(b.attachEvent("onclick",function(){l.noCloneEvent=!1}),b.cloneNode(!0).click()),null==l.deleteExpando){l.deleteExpando=!0;try{delete b.test}catch(d){l.deleteExpando=!1}}a=b=c=null}(),function(){var b,c,d=z.createElement("div");for(b in{submit:!0,change:!0,focusin:!0})c="on"+b,(l[b+"Bubbles"]=c in a)||(d.setAttribute(c,"t"),l[b+"Bubbles"]=d.attributes[c].expando===!1);d=null}();var Y=/^(?:input|select|textarea)$/i,Z=/^key/,$=/^(?:mouse|contextmenu)|click/,_=/^(?:focusinfocus|focusoutblur)$/,ab=/^([^.]*)(?:\.(.+)|)$/;function bb(){return!0}function cb(){return!1}function db(){try{return z.activeElement}catch(a){}}n.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=n._data(a);if(r){c.handler&&(i=c,c=i.handler,e=i.selector),c.guid||(c.guid=n.guid++),(g=r.events)||(g=r.events={}),(k=r.handle)||(k=r.handle=function(a){return typeof n===L||a&&n.event.triggered===a.type?void 0:n.event.dispatch.apply(k.elem,arguments)},k.elem=a),b=(b||"").match(F)||[""],h=b.length;while(h--)f=ab.exec(b[h])||[],o=q=f[1],p=(f[2]||"").split(".").sort(),o&&(j=n.event.special[o]||{},o=(e?j.delegateType:j.bindType)||o,j=n.event.special[o]||{},l=n.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&n.expr.match.needsContext.test(e),namespace:p.join(".")},i),(m=g[o])||(m=g[o]=[],m.delegateCount=0,j.setup&&j.setup.call(a,d,p,k)!==!1||(a.addEventListener?a.addEventListener(o,k,!1):a.attachEvent&&a.attachEvent("on"+o,k))),j.add&&(j.add.call(a,l),l.handler.guid||(l.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,l):m.push(l),n.event.global[o]=!0);a=null}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=n.hasData(a)&&n._data(a);if(r&&(k=r.events)){b=(b||"").match(F)||[""],j=b.length;while(j--)if(h=ab.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=n.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,m=k[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),i=f=m.length;while(f--)g=m[f],!e&&q!==g.origType||c&&c.guid!==g.guid||h&&!h.test(g.namespace)||d&&d!==g.selector&&("**"!==d||!g.selector)||(m.splice(f,1),g.selector&&m.delegateCount--,l.remove&&l.remove.call(a,g));i&&!m.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||n.removeEvent(a,o,r.handle),delete k[o])}else for(o in k)n.event.remove(a,o+b[j],c,d,!0);n.isEmptyObject(k)&&(delete r.handle,n._removeData(a,"events"))}},trigger:function(b,c,d,e){var f,g,h,i,k,l,m,o=[d||z],p=j.call(b,"type")?b.type:b,q=j.call(b,"namespace")?b.namespace.split("."):[];if(h=l=d=d||z,3!==d.nodeType&&8!==d.nodeType&&!_.test(p+n.event.triggered)&&(p.indexOf(".")>=0&&(q=p.split("."),p=q.shift(),q.sort()),g=p.indexOf(":")<0&&"on"+p,b=b[n.expando]?b:new n.Event(p,"object"==typeof b&&b),b.isTrigger=e?2:3,b.namespace=q.join("."),b.namespace_re=b.namespace?new RegExp("(^|\\.)"+q.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=d),c=null==c?[b]:n.makeArray(c,[b]),k=n.event.special[p]||{},e||!k.trigger||k.trigger.apply(d,c)!==!1)){if(!e&&!k.noBubble&&!n.isWindow(d)){for(i=k.delegateType||p,_.test(i+p)||(h=h.parentNode);h;h=h.parentNode)o.push(h),l=h;l===(d.ownerDocument||z)&&o.push(l.defaultView||l.parentWindow||a)}m=0;while((h=o[m++])&&!b.isPropagationStopped())b.type=m>1?i:k.bindType||p,f=(n._data(h,"events")||{})[b.type]&&n._data(h,"handle"),f&&f.apply(h,c),f=g&&h[g],f&&f.apply&&n.acceptData(h)&&(b.result=f.apply(h,c),b.result===!1&&b.preventDefault());if(b.type=p,!e&&!b.isDefaultPrevented()&&(!k._default||k._default.apply(o.pop(),c)===!1)&&n.acceptData(d)&&g&&d[p]&&!n.isWindow(d)){l=d[g],l&&(d[g]=null),n.event.triggered=p;try{d[p]()}catch(r){}n.event.triggered=void 0,l&&(d[g]=l)}return b.result}},dispatch:function(a){a=n.event.fix(a);var b,c,e,f,g,h=[],i=d.call(arguments),j=(n._data(this,"events")||{})[a.type]||[],k=n.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=n.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,g=0;while((e=f.handlers[g++])&&!a.isImmediatePropagationStopped())(!a.namespace_re||a.namespace_re.test(e.namespace))&&(a.handleObj=e,a.data=e.data,c=((n.event.special[e.origType]||{}).handle||e.handler).apply(f.elem,i),void 0!==c&&(a.result=c)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&(!a.button||"click"!==a.type))for(;i!=this;i=i.parentNode||this)if(1===i.nodeType&&(i.disabled!==!0||"click"!==a.type)){for(e=[],f=0;h>f;f++)d=b[f],c=d.selector+" ",void 0===e[c]&&(e[c]=d.needsContext?n(c,this).index(i)>=0:n.find(c,this,null,[i]).length),e[c]&&e.push(d);e.length&&g.push({elem:i,handlers:e})}return h]","i"),ib=/^\s+/,jb=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,kb=/<([\w:]+)/,lb=/\s*$/g,sb={option:[1,""],legend:[1,"
","
"],area:[1,"",""],param:[1,"",""],thead:[1,"","
"],tr:[2,"","
"],col:[2,"","
"],td:[3,"","
"],_default:l.htmlSerialize?[0,"",""]:[1,"X
","
"]},tb=eb(z),ub=tb.appendChild(z.createElement("div"));sb.optgroup=sb.option,sb.tbody=sb.tfoot=sb.colgroup=sb.caption=sb.thead,sb.th=sb.td;function vb(a,b){var c,d,e=0,f=typeof a.getElementsByTagName!==L?a.getElementsByTagName(b||"*"):typeof a.querySelectorAll!==L?a.querySelectorAll(b||"*"):void 0;if(!f)for(f=[],c=a.childNodes||a;null!=(d=c[e]);e++)!b||n.nodeName(d,b)?f.push(d):n.merge(f,vb(d,b));return void 0===b||b&&n.nodeName(a,b)?n.merge([a],f):f}function wb(a){X.test(a.type)&&(a.defaultChecked=a.checked)}function xb(a,b){return n.nodeName(a,"table")&&n.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function yb(a){return a.type=(null!==n.find.attr(a,"type"))+"/"+a.type,a}function zb(a){var b=qb.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function Ab(a,b){for(var c,d=0;null!=(c=a[d]);d++)n._data(c,"globalEval",!b||n._data(b[d],"globalEval"))}function Bb(a,b){if(1===b.nodeType&&n.hasData(a)){var c,d,e,f=n._data(a),g=n._data(b,f),h=f.events;if(h){delete g.handle,g.events={};for(c in h)for(d=0,e=h[c].length;e>d;d++)n.event.add(b,c,h[c][d])}g.data&&(g.data=n.extend({},g.data))}}function Cb(a,b){var c,d,e;if(1===b.nodeType){if(c=b.nodeName.toLowerCase(),!l.noCloneEvent&&b[n.expando]){e=n._data(b);for(d in e.events)n.removeEvent(b,d,e.handle);b.removeAttribute(n.expando)}"script"===c&&b.text!==a.text?(yb(b).text=a.text,zb(b)):"object"===c?(b.parentNode&&(b.outerHTML=a.outerHTML),l.html5Clone&&a.innerHTML&&!n.trim(b.innerHTML)&&(b.innerHTML=a.innerHTML)):"input"===c&&X.test(a.type)?(b.defaultChecked=b.checked=a.checked,b.value!==a.value&&(b.value=a.value)):"option"===c?b.defaultSelected=b.selected=a.defaultSelected:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}}n.extend({clone:function(a,b,c){var d,e,f,g,h,i=n.contains(a.ownerDocument,a);if(l.html5Clone||n.isXMLDoc(a)||!hb.test("<"+a.nodeName+">")?f=a.cloneNode(!0):(ub.innerHTML=a.outerHTML,ub.removeChild(f=ub.firstChild)),!(l.noCloneEvent&&l.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||n.isXMLDoc(a)))for(d=vb(f),h=vb(a),g=0;null!=(e=h[g]);++g)d[g]&&Cb(e,d[g]);if(b)if(c)for(h=h||vb(a),d=d||vb(f),g=0;null!=(e=h[g]);g++)Bb(e,d[g]);else Bb(a,f);return d=vb(f,"script"),d.length>0&&Ab(d,!i&&vb(a,"script")),d=h=e=null,f},buildFragment:function(a,b,c,d){for(var e,f,g,h,i,j,k,m=a.length,o=eb(b),p=[],q=0;m>q;q++)if(f=a[q],f||0===f)if("object"===n.type(f))n.merge(p,f.nodeType?[f]:f);else if(mb.test(f)){h=h||o.appendChild(b.createElement("div")),i=(kb.exec(f)||["",""])[1].toLowerCase(),k=sb[i]||sb._default,h.innerHTML=k[1]+f.replace(jb,"<$1>")+k[2],e=k[0];while(e--)h=h.lastChild;if(!l.leadingWhitespace&&ib.test(f)&&p.push(b.createTextNode(ib.exec(f)[0])),!l.tbody){f="table"!==i||lb.test(f)?""!==k[1]||lb.test(f)?0:h:h.firstChild,e=f&&f.childNodes.length;while(e--)n.nodeName(j=f.childNodes[e],"tbody")&&!j.childNodes.length&&f.removeChild(j)}n.merge(p,h.childNodes),h.textContent="";while(h.firstChild)h.removeChild(h.firstChild);h=o.lastChild}else p.push(b.createTextNode(f));h&&o.removeChild(h),l.appendChecked||n.grep(vb(p,"input"),wb),q=0;while(f=p[q++])if((!d||-1===n.inArray(f,d))&&(g=n.contains(f.ownerDocument,f),h=vb(o.appendChild(f),"script"),g&&Ab(h),c)){e=0;while(f=h[e++])pb.test(f.type||"")&&c.push(f)}return h=null,o},cleanData:function(a,b){for(var d,e,f,g,h=0,i=n.expando,j=n.cache,k=l.deleteExpando,m=n.event.special;null!=(d=a[h]);h++)if((b||n.acceptData(d))&&(f=d[i],g=f&&j[f])){if(g.events)for(e in g.events)m[e]?n.event.remove(d,e):n.removeEvent(d,e,g.handle);j[f]&&(delete j[f],k?delete d[i]:typeof d.removeAttribute!==L?d.removeAttribute(i):d[i]=null,c.push(f))}}}),n.fn.extend({text:function(a){return W(this,function(a){return void 0===a?n.text(this):this.empty().append((this[0]&&this[0].ownerDocument||z).createTextNode(a))},null,a,arguments.length)},append:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=xb(this,a);b.appendChild(a)}})},prepend:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=xb(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},remove:function(a,b){for(var c,d=a?n.filter(a,this):this,e=0;null!=(c=d[e]);e++)b||1!==c.nodeType||n.cleanData(vb(c)),c.parentNode&&(b&&n.contains(c.ownerDocument,c)&&Ab(vb(c,"script")),c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++){1===a.nodeType&&n.cleanData(vb(a,!1));while(a.firstChild)a.removeChild(a.firstChild);a.options&&n.nodeName(a,"select")&&(a.options.length=0)}return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return n.clone(this,a,b)})},html:function(a){return W(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a)return 1===b.nodeType?b.innerHTML.replace(gb,""):void 0;if(!("string"!=typeof a||nb.test(a)||!l.htmlSerialize&&hb.test(a)||!l.leadingWhitespace&&ib.test(a)||sb[(kb.exec(a)||["",""])[1].toLowerCase()])){a=a.replace(jb,"<$1>");try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(n.cleanData(vb(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=arguments[0];return this.domManip(arguments,function(b){a=this.parentNode,n.cleanData(vb(this)),a&&a.replaceChild(b,this)}),a&&(a.length||a.nodeType)?this:this.remove()},detach:function(a){return this.remove(a,!0)},domManip:function(a,b){a=e.apply([],a);var c,d,f,g,h,i,j=0,k=this.length,m=this,o=k-1,p=a[0],q=n.isFunction(p);if(q||k>1&&"string"==typeof p&&!l.checkClone&&ob.test(p))return this.each(function(c){var d=m.eq(c);q&&(a[0]=p.call(this,c,d.html())),d.domManip(a,b)});if(k&&(i=n.buildFragment(a,this[0].ownerDocument,!1,this),c=i.firstChild,1===i.childNodes.length&&(i=c),c)){for(g=n.map(vb(i,"script"),yb),f=g.length;k>j;j++)d=i,j!==o&&(d=n.clone(d,!0,!0),f&&n.merge(g,vb(d,"script"))),b.call(this[j],d,j);if(f)for(h=g[g.length-1].ownerDocument,n.map(g,zb),j=0;f>j;j++)d=g[j],pb.test(d.type||"")&&!n._data(d,"globalEval")&&n.contains(h,d)&&(d.src?n._evalUrl&&n._evalUrl(d.src):n.globalEval((d.text||d.textContent||d.innerHTML||"").replace(rb,"")));i=c=null}return this}}),n.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){n.fn[a]=function(a){for(var c,d=0,e=[],g=n(a),h=g.length-1;h>=d;d++)c=d===h?this:this.clone(!0),n(g[d])[b](c),f.apply(e,c.get());return this.pushStack(e)}});var Db,Eb={};function Fb(b,c){var d=n(c.createElement(b)).appendTo(c.body),e=a.getDefaultComputedStyle?a.getDefaultComputedStyle(d[0]).display:n.css(d[0],"display");return d.detach(),e}function Gb(a){var b=z,c=Eb[a];return c||(c=Fb(a,b),"none"!==c&&c||(Db=(Db||n("