0
0
Fork 0
mirror of https://github.com/liabru/matter-js.git synced 2024-12-24 13:29:01 -05:00

Merge branch 'master' into timing-improve

* master: (123 commits)
  release 0.18.0
  prevent source map in demo builds
  updated test scripts
  added note about webpack performance to readme
  added benchmark test command
  increase iterations on Example.stress3
  add triangles to mixed bodies example
  added example for Composite.remove
  updated examples
  deprecated Matter.Grid
  added broadphase to Matter.Detector
  replaced Matter.SAT with Matter.Collision
  use force exit in tests
  added cache checks to Matter.Composite
  change raycasting example events to enable use in tests
  optimised collisions
  added Matter.Collision
  use Matter.Runner in test worker
  optimised Matter.Pairs
  optimised Resolver.solvePosition
  ...

# Conflicts:
#	examples/car.js
#	examples/manipulation.js
#	examples/ragdoll.js
#	examples/slingshot.js
#	examples/timescale.js
#	src/collision/Detector.js
#	src/collision/Resolver.js
#	src/collision/SAT.js
#	src/core/Engine.js
#	src/core/Runner.js
This commit is contained in:
liabru 2021-12-20 18:52:58 +00:00
commit 7fce5d861c
107 changed files with 26980 additions and 18446 deletions

View file

@ -29,7 +29,6 @@
"process": false,
"HTMLElement": false,
"require": false,
"PIXI": false,
"$": false,
"Image": false,
"navigator": false,
@ -59,14 +58,13 @@
"Vector": false,
"Vertices": false,
"Render": false,
"RenderPixi": false,
"Events": false,
"Query": false,
"Runner": false,
"Svg": false,
"Metrics": false,
"Example": false,
"__MATTER_VERSION__": false,
"__MATTER_IS_DEV__": false,
"jest": false,
"test": false,
"expect": false,

3
.gitignore vendored
View file

@ -1,10 +1,13 @@
.idea
*.map
node_modules
npm-debug.log
docs
matter-doc-theme
build/matter-dev.js
build/matter-dev.min.js
build/matter.dev.js
build/matter.dev.min.js
demo/js/lib/matter-dev.js
demo/js/Examples.min.js
examples/build

View file

@ -3,8 +3,10 @@ sudo: false
node_js:
- "node"
install:
- npm install
- npm ci
script:
- npm run lint
- npm run benchmark
- npm run test
- npm run build
- npm run build-demo

View file

@ -1,3 +1,127 @@
## 0.18.0 (2021-12-15)
* added test capture sort to improve comparison ([ea3c11b](https://github.com/liabru/matter-js/commit/ea3c11b))
* added triangles to mixed bodies example ([b116f64](https://github.com/liabru/matter-js/commit/b116f64))
* added behaviour metric to tests and refactor tests ([8125966](https://github.com/liabru/matter-js/commit/8125966))
* added benchmark test command ([7f34c45](https://github.com/liabru/matter-js/commit/7f34c45))
* added broadphase to Matter.Detector ([a6b5e7d](https://github.com/liabru/matter-js/commit/a6b5e7d))
* added cache checks to Matter.Composite ([32fd285](https://github.com/liabru/matter-js/commit/32fd285))
* added example for Composite.remove ([bc07f56](https://github.com/liabru/matter-js/commit/bc07f56))
* added example stress 3 ([d0ee246](https://github.com/liabru/matter-js/commit/d0ee246))
* added filesize to test comparison report ([b3a8aa3](https://github.com/liabru/matter-js/commit/b3a8aa3))
* added Matter.Collision ([9037f36](https://github.com/liabru/matter-js/commit/9037f36))
* added memory comparison to tests ([bedf84c](https://github.com/liabru/matter-js/commit/bedf84c))
* added note about webpack performance to readme ([80cf76b](https://github.com/liabru/matter-js/commit/80cf76b))
* added stable sorting to test worker and refactor ([81dd2fb](https://github.com/liabru/matter-js/commit/81dd2fb))
* added support for build metadata in Plugin.versionParse ([8bfaff0](https://github.com/liabru/matter-js/commit/8bfaff0))
* changed raycasting example events to enable use in tests ([10afaea](https://github.com/liabru/matter-js/commit/10afaea))
* changed build config to 'source-map' devtool ([e909b04](https://github.com/liabru/matter-js/commit/e909b04))
* changed tests to use a production build rather than source ([55feb89](https://github.com/liabru/matter-js/commit/55feb89))
* deprecated Matter.Grid ([e366d0e](https://github.com/liabru/matter-js/commit/e366d0e))
* fixed sync issues on demo compare tool ([826ed46](https://github.com/liabru/matter-js/commit/826ed46))
* improved performance measurement accuracy in tests ([cd289ec](https://github.com/liabru/matter-js/commit/cd289ec))
* improved test comparison report ([de04c00](https://github.com/liabru/matter-js/commit/de04c00))
* optimised Matter.Detector ([c7cec16](https://github.com/liabru/matter-js/commit/c7cec16)), ([fd1a70e](https://github.com/liabru/matter-js/commit/fd1a70e)), ([caeb07e](https://github.com/liabru/matter-js/commit/caeb07e)), ([efede6e](https://github.com/liabru/matter-js/commit/efede6e))
* optimised Matter.Composite ([52e7977](https://github.com/liabru/matter-js/commit/52e7977))
* optimised Matter.Pair ([d8a6380](https://github.com/liabru/matter-js/commit/d8a6380)), ([48673db](https://github.com/liabru/matter-js/commit/48673db)), ([1073dde](https://github.com/liabru/matter-js/commit/1073dde))
* optimised Matter.Pairs ([a30707f](https://github.com/liabru/matter-js/commit/a30707f)), ([a882a74](https://github.com/liabru/matter-js/commit/a882a74))
* optimised Matter.Resolver ([fceb0ca](https://github.com/liabru/matter-js/commit/fceb0ca)), ([49fbfba](https://github.com/liabru/matter-js/commit/49fbfba)), ([0b07a31](https://github.com/liabru/matter-js/commit/0b07a31)), ([f847f4c](https://github.com/liabru/matter-js/commit/f847f4c)), ([3cf65e8](https://github.com/liabru/matter-js/commit/3cf65e8)), ([30b899c](https://github.com/liabru/matter-js/commit/30b899c)), ([e4b35d3](https://github.com/liabru/matter-js/commit/e4b35d3))
* optimised Matter.SAT ([0d90a17](https://github.com/liabru/matter-js/commit/0d90a17)), ([2096961](https://github.com/liabru/matter-js/commit/2096961)), ([0af144c](https://github.com/liabru/matter-js/commit/0af144c))
* optimised Matter.Vertices ([c198878](https://github.com/liabru/matter-js/commit/c198878)), ([6883d0d](https://github.com/liabru/matter-js/commit/6883d0d)), ([792ae2e](https://github.com/liabru/matter-js/commit/792ae2e))
* refactor test worker and prevent test cache ([ca2fe75](https://github.com/liabru/matter-js/commit/ca2fe75)), ([bcc3168](https://github.com/liabru/matter-js/commit/bcc3168))
* replaced Matter.SAT with Matter.Collision ([b9e7d9d](https://github.com/liabru/matter-js/commit/b9e7d9d))
* show debug stats in dev demo ([2f14ec5](https://github.com/liabru/matter-js/commit/2f14ec5))
* updated dev dependencies ([c5028d5](https://github.com/liabru/matter-js/commit/c5028d5))
* updated examples ([c80ed5c](https://github.com/liabru/matter-js/commit/c80ed5c))
* updated test scripts ([afa467a](https://github.com/liabru/matter-js/commit/afa467a))
* use force exit in tests ([8adf810](https://github.com/liabru/matter-js/commit/8adf810))
* use Matter.Runner in test worker ([2581595](https://github.com/liabru/matter-js/commit/2581595))
## <small>0.17.1 (2021-04-14)</small>
* deprecate Engine.run alias replaced by Runner.run ([5817046](https://github.com/liabru/matter-js/commit/5817046))
## 0.17.0 (2021-04-11)
* add Common.setDecomp and Common.getDecomp ([313c150](https://github.com/liabru/matter-js/commit/313c150))
* add demo build config and refactor demo ([653a647](https://github.com/liabru/matter-js/commit/653a647))
* add docs for all Matter.Render options ([ec3eecc](https://github.com/liabru/matter-js/commit/ec3eecc))
* add title to all examples ([f4d72ba](https://github.com/liabru/matter-js/commit/f4d72ba))
* added Common.deprecated ([ffa3193](https://github.com/liabru/matter-js/commit/ffa3193))
* added Common.warnOnce ([6957dbf](https://github.com/liabru/matter-js/commit/6957dbf))
* added Date.now fallback to Common.now, closes #739 ([c06c107](https://github.com/liabru/matter-js/commit/c06c107)), closes [#739](https://github.com/liabru/matter-js/issues/739)
* added debug stats and performance monitoring to Matter.Render ([119881b](https://github.com/liabru/matter-js/commit/119881b))
* added doc watch script ([164456b](https://github.com/liabru/matter-js/commit/164456b))
* added docs for additional engine timing and render properties ([8017bdb](https://github.com/liabru/matter-js/commit/8017bdb))
* added Example.stats ([9915007](https://github.com/liabru/matter-js/commit/9915007))
* added lastDelta and lastElapsed to engine.timing ([6dc703f](https://github.com/liabru/matter-js/commit/6dc703f))
* build demo ([0816454](https://github.com/liabru/matter-js/commit/0816454))
* change all examples to use Composite.add instead of the alias World.add ([a3f298f](https://github.com/liabru/matter-js/commit/a3f298f))
* changed engine.broadphase to engine.grid ([b74e400](https://github.com/liabru/matter-js/commit/b74e400))
* changed Example.views to use render events ([3ac3498](https://github.com/liabru/matter-js/commit/3ac3498))
* changed world.gravity to engine.gravity ([6abb3b7](https://github.com/liabru/matter-js/commit/6abb3b7))
* deprecated Composites.car and added to car example ([cd9c5d4](https://github.com/liabru/matter-js/commit/cd9c5d4))
* deprecated Composites.newtonsCradle and added to newtonsCradle example ([9ad980b](https://github.com/liabru/matter-js/commit/9ad980b))
* deprecated Composites.softBody and added to softBody and cloth examples ([818f354](https://github.com/liabru/matter-js/commit/818f354))
* improve Render.debug ([1753bf0](https://github.com/liabru/matter-js/commit/1753bf0))
* migrate Matter.World to the equivalent Matter.Composite ([5dbec9b](https://github.com/liabru/matter-js/commit/5dbec9b))
* remove deprecated backwards compatibility engine events from Matter.Runner ([76bf80e](https://github.com/liabru/matter-js/commit/76bf80e))
* remove deprecated backwards compatibility render integration from Matter.Engine ([1aa8ed0](https://github.com/liabru/matter-js/commit/1aa8ed0))
* remove deprecated backwards compatibility render integration from Matter.Runner ([6805f85](https://github.com/liabru/matter-js/commit/6805f85))
* remove deprecated Matter.Metrics ([63a9e98](https://github.com/liabru/matter-js/commit/63a9e98))
* remove deprecated Matter.RenderPixi ([08a515b](https://github.com/liabru/matter-js/commit/08a515b))
* remove unused render shadow function ([e49834d](https://github.com/liabru/matter-js/commit/e49834d))
* run all examples in browser tests ([5734bfd](https://github.com/liabru/matter-js/commit/5734bfd))
* set render showDebug option on examples stress and stress2 ([f2ef3aa](https://github.com/liabru/matter-js/commit/f2ef3aa))
* update matter-tools ([f8d366a](https://github.com/liabru/matter-js/commit/f8d366a))
## <small>0.16.1 (2021-01-31)</small>
* add log capture and reporting in tests ([7bfd3c2](https://github.com/liabru/matter-js/commit/7bfd3c2))
* add matter-wrap as dev dependency ([ef7c4c6](https://github.com/liabru/matter-js/commit/ef7c4c6))
* catch missing plugin require in examples ([1ba1255](https://github.com/liabru/matter-js/commit/1ba1255))
* change example matter-wrap require precedence ([aa1e4e7](https://github.com/liabru/matter-js/commit/aa1e4e7))
* change perf threshold in test ([7b00354](https://github.com/liabru/matter-js/commit/7b00354))
* change test worker decomp require ([5e746b0](https://github.com/liabru/matter-js/commit/5e746b0))
* disable jest cache ([8ee0ebb](https://github.com/liabru/matter-js/commit/8ee0ebb))
* enable useful dev server features ([839f7d9](https://github.com/liabru/matter-js/commit/839f7d9))
* fix decomp require and improve warning message ([e87f64a](https://github.com/liabru/matter-js/commit/e87f64a))
* fix dev server externals ([1f2f9fe](https://github.com/liabru/matter-js/commit/1f2f9fe))
* fix named require in test ([92080ff](https://github.com/liabru/matter-js/commit/92080ff))
* improve CI speed ([1af64eb](https://github.com/liabru/matter-js/commit/1af64eb))
* improve docs for Bodies.fromVertices ([2ade78f](https://github.com/liabru/matter-js/commit/2ade78f))
* improve stack examples with exact contact ([522f4e8](https://github.com/liabru/matter-js/commit/522f4e8))
* improve test report log ([b5326f8](https://github.com/liabru/matter-js/commit/b5326f8))
## 0.16.0 (2021-01-17)
* added removeDuplicatePoints option from poly-decomp 0.3.0 to Bodies.fromVertices ([#639](https://github.com/liabru/matter-js/issues/639), [947cb97](https://github.com/liabru/matter-js/commit/947cb97), [a9694e6](https://github.com/liabru/matter-js/commit/a9694e6))
* added support for > and >= operators in plugin version ranges ([0792716](https://github.com/liabru/matter-js/commit/0792716))
* added support for example versioning in tests ([31d0ace](https://github.com/liabru/matter-js/commit/31d0ace))
* added version targets for examples ([142b7de](https://github.com/liabru/matter-js/commit/142b7de))
* added warning check on browser tests ([12377cc](https://github.com/liabru/matter-js/commit/12377cc))
* changed svg and terrain example to use fetch ([5551cd5](https://github.com/liabru/matter-js/commit/5551cd5))
* changed deprecated comments to avoid confusion ([1e73cab](https://github.com/liabru/matter-js/commit/1e73cab))
* fixed poly-decomp external require ([882e07c](https://github.com/liabru/matter-js/commit/882e07c))
* removed bower.json ([f71d4c0](https://github.com/liabru/matter-js/commit/f71d4c0))
* removed unused dev dependency run-sequence ([be592fd](https://github.com/liabru/matter-js/commit/be592fd))
* updated dev dependencies ([151eb30](https://github.com/liabru/matter-js/commit/151eb30))
* updated matter-tools ([5c66458](https://github.com/liabru/matter-js/commit/5c66458))
* updated matter-tools ([33e8fe8](https://github.com/liabru/matter-js/commit/33e8fe8))
* updated demo matter-tools ([a694ae5](https://github.com/liabru/matter-js/commit/a694ae5))
* updated demo pathseg ([9c5325b](https://github.com/liabru/matter-js/commit/9c5325b))
* updated readme ([3089b41](https://github.com/liabru/matter-js/commit/3089b41))
## 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))

View file

@ -18,7 +18,7 @@ To build you must first install [node.js](http://nodejs.org), then run
which will install the required build dependencies, then run
npm run dev
npm start
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.
@ -36,10 +36,12 @@ The output of `npm run test` also includes a [comparison report](https://github.
The following development commands can be run at the terminal
- **npm run dev**
runs development server
- **npm start**
runs development server and opens demo page
- **npm run build**
creates a release build
- **npm run build-demo**
builds the demo
- **npm run lint**
runs the linter
- **npm run test**

View file

@ -58,7 +58,6 @@
<li><a href="https://brm.io/matter-js/demo/#airFriction">Air Friction</a></li>
<li><a href="https://brm.io/matter-js/demo/#staticFriction">Static Friction</a></li>
<li><a href="https://brm.io/matter-js/demo/#sleeping">Sleeping</a></li>
<li><a href="https://brm.io/matter-js/demo/#broadphase">Grid Broadphase</a></li>
<li><a href="https://brm.io/matter-js/demo/#beachBalls">Beach Balls</a></li>
<li><a href="https://brm.io/matter-js/demo/#stress">Stress 1</a></li>
<li><a href="https://brm.io/matter-js/demo/#stress2">Stress 2</a></li>
@ -125,6 +124,10 @@ Alternatively you can download a [stable release](https://github.com/liabru/matt
<script src="matter.js" type="text/javascript"></script>
### Webpack
Some [webpack](https://webpack.js.org/) configs including the default may impact your project's performance during development, for a solution see [issue](https://github.com/liabru/matter-js/issues/1001).
### Usage
Visit the [Getting started](https://github.com/liabru/matter-js/wiki/Getting-started) wiki page for a minimal usage example which should work in both browsers and Node.js.

View file

@ -1,3 +1,158 @@
## ▲.●matter.js`0.18.0`
Release notes for `0.18.0`. See the release [readme](https://github.com/liabru/matter-js/blob/0.18.0/README.md) for further information.
### Highlights
- **Up to ~40% performance improvement (on average measured over all examples, in Node on a Mac Air M1)**
- Replaces `Matter.Grid` with a faster and more efficient broadphase in `Matter.Detector`
- Reduced memory usage and garbage collection
- Resolves issues in `Matter.SAT` related to collision reuse
- Removes performance issues from `Matter.Grid`
- Improved collision accuracy
- Improved API and docs for collision modules
- Improved [documentation](https://brm.io/matter-js/docs/) pages
- Added note about avoiding Webpack [performance problems](https://github.com/liabru/matter-js/blob/master/README.md#install)
### Changes
See the release [compare page](https://github.com/liabru/matter-js/compare/0.17.1...0.18.0) and the [changelog](https://github.com/liabru/matter-js/blob/0.18.0/CHANGELOG.md) for a detailed list of changes.
### Migration ⌲
- Behaviour and similarity is in practice the same (a fractional difference from improved accuracy)
- API is the same other than:
- [Matter.Detector](https://brm.io/matter-js/docs/classes/Detector.html) replaces [Matter.Grid](https://brm.io/matter-js/docs/classes/Grid.html) (which is now deprecated but will remain for a short term)
- [render.options.showBroadphase](https://brm.io/matter-js/docs/classes/Render.html#property_options.showBroadphase) is deprecated (no longer implemented)
- [Matter.SAT](https://brm.io/matter-js/docs/classes/SAT.html) is renamed [Matter.Collision](https://brm.io/matter-js/docs/classes/Collision.html)
- [Matter.SAT.collides](https://brm.io/matter-js/docs/classes/SAT.html#method_collides) is now [Matter.Collision.collides](https://brm.io/matter-js/docs/classes/Collision.html#method_collides) with a slightly different set of arguments
### Comparison
Differences in behaviour, quality and performance against the previous release `0.17.1`. For more information see [comparison method](https://github.com/liabru/matter-js/pull/794).
```ocaml
Output comparison of 43 examples against previous release matter-js@0.17.1
Behaviour 99.99% Similarity 99.98% Overlap -0.00%
Performance +40.62% Memory -6.18% Filesize -0.16% 77.73 KB
airFriction · · avalanche ● · ballPool · · bridge · · car · · catapult · ·
chains · · circleStack · · cloth · · collisionFiltering · · compositeManipulation ● ·
compound · · compoundStack · · concave · · constraints ● · doublePendulum · ·
events · · friction · · gravity · · gyro · · manipulation · ◆
mixed · · newtonsCradle · · pyramid · · ragdoll · · raycasting · ·
remove · · restitution · · rounded · · sensors · · sleeping · ◆
slingshot · · softBody · · sprites · · stack · · staticFriction · ·
stats · · stress · · stress2 · · stress3 · · timescale · ·
views · · wreckingBall · ·
where · no change ● extrinsics changed ◆ intrinsics changed
```
### Contributors
Many thanks to the [contributors](https://github.com/liabru/matter-js/compare/0.17.1...0.18.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.
---
## ▲.●matter.js`0.17.0`
Release notes for `0.17.0`. See the release [readme](https://github.com/liabru/matter-js/blob/0.17.0/README.md) for further information.
### Highlights
- Added performance and stats monitoring overlays to `Matter.Render`
- See the [stats demo](https://brm.io/matter-js/demo/#stats) or enable [render.options.showPerformance](https://brm.io/matter-js/docs/classes/Render.html#property_options.showPerformance) and [render.options.showStats](https://brm.io/matter-js/docs/classes/Render.html#property_options.showStats)
- Stats shown include
- render frequency (e.g. `60 fps`)
- engine delta time (e.g. `16.66ms`)
- engine execution duration (e.g. `5.00ms`)
- render execution duration (e.g.` 0.40ms`)
- effective play speed (e.g. `1.00x` is real-time)
- various other engine internal stats for debugging
- Improved [documentation](https://brm.io/matter-js/docs/) pages
- Added [Common.setDecomp](https://brm.io/matter-js/docs/classes/Common.html#method_setDecomp) and [Common.getDecomp](https://brm.io/matter-js/docs/classes/Common.html#method_getDecomp) to fix [bundler issues](https://github.com/liabru/matter-js/issues/981)
- Added docs for all [Matter.Render options](https://brm.io/matter-js/docs/classes/Render.html#properties)
- Migrated usage of `Matter.World` over to `Matter.Composite` (more info in [docs](https://brm.io/matter-js/docs/classes/World.html))
- Migrated, deprecated and removed various old functionality (see the [changelog](https://github.com/liabru/matter-js/blob/0.17.0/CHANGELOG.md) for details)
### Changes
See the release [compare page](https://github.com/liabru/matter-js/compare/0.16.1...0.17.0) and the [changelog](https://github.com/liabru/matter-js/blob/0.17.0/CHANGELOG.md) for a detailed list of changes.
### Comparison
Differences in behaviour, quality and performance against the previous release `0.16.1`. For more information see [comparison method](https://github.com/liabru/matter-js/pull/794).
```ocaml
Output comparison of 37 examples against previous release matter-js@0.16.1
Similarity 100% Performance +0.00% Overlap +0.00%
airFriction · · avalanche · · ballPool · · bridge · · broadphase · · car · ·
catapult · · chains · · circleStack · · cloth · · collisionFiltering · ·
compound · · compoundStack · · constraints · · events · · friction · ·
gyro · · manipulation · · mixed · · newtonsCradle · · pyramid · ·
ragdoll · · restitution · · rounded · · sensors · · sleeping · ·
slingshot · · softBody · · sprites · · stack · · staticFriction · ·
stats · · 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.16.1...0.17.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.
---
## ▲.●matter.js`0.16.0`
Release notes for `0.16.0`. See the release [readme](https://github.com/liabru/matter-js/blob/0.16.0/README.md) for further information.
### Highlights
- Changed external require method for `poly-decomp` ([882e07c](https://github.com/liabru/matter-js/commit/882e07c))
- Improved `Bodies.fromVertices` decomposition quality using `removeDuplicatePoints` ([#639](https://github.com/liabru/matter-js/pull/639))
- Added support for `>x.x.x` and `>=x.x.x` semver ranges in plugins ([0792716](https://github.com/liabru/matter-js/commit/0792716))
- Changed demo example select background colour for Windows ([matter-tools #5](https://github.com/liabru/matter-tools/pull/5))
- Updated demo to use latest [matter-tools](https://github.com/liabru/matter-tools) ([#33e8fe8](https://github.com/liabru/matter-js/commit/33e8fe8))
- Updated SVG and terrain examples to use `fetch` ([5551cd5](https://github.com/liabru/matter-js/commit/5551cd5))
### Changes
See the release [compare page](https://github.com/liabru/matter-js/compare/0.15.0...0.16.0) and the [changelog](https://github.com/liabru/matter-js/blob/0.16.0/CHANGELOG.md) for a detailed list of changes.
### Comparison
Differences in behaviour, quality and performance against the previous release `0.15.0`. For more information see [comparison method](https://github.com/liabru/matter-js/pull/794).
```ocaml
Output comparison of 41 examples against matter-js@0.15.0 build on last run
Similarity 100% Performance +0.00% 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.15.0...0.16.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.
---
## ▲.●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.

File diff suppressed because it is too large Load diff

4
build/matter.min.js vendored

File diff suppressed because one or more lines are too long

View file

@ -9,28 +9,8 @@
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="robots" content="noindex">
<title>Matter.js Demo</title>
<!-- Libs -->
<script type="text/javascript" src="./lib/decomp.js"></script>
<script type="text/javascript" src="./lib/pathseg.js"></script>
<!-- Examples -->
<script src="./js/Examples.js"></script>
<!-- Matter -->
<script src="../build/matter.js"></script>
<!-- MatterTools -->
<script src="https://code.jquery.com/jquery-3.1.1.js"></script>
<script src="./lib/matter-tools.gui.js"></script>
<script src="./lib/matter-tools.inspector.js"></script>
<script src="./lib/matter-tools.demo.js"></script>
<!-- Plugins -->
<script src="./lib/matter-wrap.js"></script>
<style type="text/css">
* {
box-sizing: border-box;
@ -41,7 +21,13 @@
padding: 0;
}
.matter-js-compare-build {
.matter-btn-compare.matter-btn {
font-size: 18px;
text-align: center;
line-height: 32px;
}
.matter-js-compare-build.matter-demo {
position: absolute;
background: none;
top: 0;
@ -53,21 +39,22 @@
pointer-events: none;
}
.matter-js-compare-build .matter-header-outer {
.matter-js-compare-build.matter-demo .matter-header-outer {
display: none;
}
.matter-js-compare-build canvas {
.matter-js-compare-build.matter-demo canvas {
opacity: 0.5;
background: transparent !important;
}
.matter-demo canvas {
border: 1px solid rgba(255, 255, 255, 0.07);
}
</style>
</head>
<body>
<script src="./js/Demo.js"></script>
<script src="./js/matter-demo.main.5754e1.min.js"></script>
<script src="./js/matter-demo.matter-tools.97f38a.min.js"></script>
<script src="./js/matter-demo.matter-wrap.dbda1f.min.js"></script>
<script src="./js/matter-demo.pathseg.cf21c2.min.js"></script>
<script src="./js/matter-demo.poly-decomp.c3d015.min.js"></script>
<script src="./js/matter-demo.a280d3.min.js"></script>
</body>
</html>

View file

@ -1,179 +0,0 @@
/**
* A Matter.js build comparison testbed.
*
* Tool for Matter.js maintainers to compare results of
* the current source build with the release build in the browser.
*
* USAGE: open http://localhost:8000/?compare=120#mixed
*
* NOTE: For the actual example code, refer to the source files in `/examples/`.
*
* @class Compare
*/
(function() {
// maintain reference to dev version of Matter already loaded
var MatterDev = window.Matter;
// load the build version of Matter
var matterBuildScript = document.createElement('script');
matterBuildScript.src = '../build/matter.min.js';
// wait for load
matterBuildScript.addEventListener('load', function() {
var examples = window.MatterDemo.examples;
// maintain reference of build version and set dev version as main
var MatterBuild = window.Matter;
window.Matter = MatterDev;
var demo = MatterTools.Demo.create({
toolbar: {
title: 'matter-js',
url: 'https://github.com/liabru/matter-js',
reset: true,
source: true,
inspector: true,
tools: true,
fullscreen: true,
exampleSelect: true
},
tools: {
inspector: true,
gui: true
},
inline: false,
preventZoom: true,
resetOnOrientation: true,
routing: true,
startExample: 'mixed',
examples: examples
});
var demoBuild = MatterTools.Demo.create({
toolbar: {
title: 'matter-js-compare-build',
reset: false,
source: false,
inspector: false,
tools: false,
fullscreen: false,
exampleSelect: false
},
tools: {
inspector: false,
gui: false
},
inline: false,
preventZoom: true,
resetOnOrientation: true,
routing: false,
startExample: 'mixed',
examples: examples.map(function(example) {
return Matter.Common.extend({}, example);
})
});
/**
* NOTE: For the actual example code, refer to the source files in `/examples/`.
* The code below is tooling for Matter.js maintainers to compare versions of Matter.
*/
// build version should not run itself
MatterBuild.Runner.run = function() {};
MatterBuild.Render.run = function() {};
// maintain original references to patched methods
MatterDev.Runner._tick = MatterDev.Runner.tick;
MatterDev.Render._world = MatterDev.Render.world;
MatterBuild.Mouse._setElement = MatterBuild.Mouse.setElement;
// patch MatterTools to control both demo versions simultaneously
MatterTools.Demo._setExample = MatterTools.Demo.setExample;
MatterTools.Demo.setExample = function(_demo, example) {
MatterBuild.Common._nextId = MatterBuild.Common._seed = 0;
MatterDev.Common._nextId = MatterDev.Common._seed = 0;
MatterBuild.Plugin._registry = MatterDev.Plugin._registry;
MatterBuild.use.apply(null, MatterDev.used);
window.Matter = MatterDev;
MatterTools.Demo._setExample(
demo, demo.examples.find(function(e) { return e.name === example.name; })
);
var maxTicks = parseFloat(window.location.search.split('=')[1]);
var ticks = 0;
MatterDev.Runner.tick = function(runner, engine, time) {
if (ticks === -1) {
return;
}
if (ticks >= maxTicks) {
console.info(
'Demo.Compare: ran ' + ticks + ' ticks, timestamp is now '
+ engine.timing.timestamp.toFixed(2)
);
ticks = -1;
return;
}
ticks += 1;
var demoBuildInstance = demoBuild.example.instance;
runner.isFixed = demoBuildInstance.runner.isFixed = true;
runner.delta = demoBuildInstance.runner.delta = 1000 / 60;
window.Matter = MatterBuild;
MatterBuild.Runner.tick(demoBuildInstance.runner, demoBuildInstance.engine, time);
window.Matter = MatterDev;
return MatterDev.Runner._tick(runner, engine, time);
};
MatterDev.Render.world = function(render) {
window.Matter = MatterBuild;
MatterBuild.Render.world(demoBuild.example.instance.render);
window.Matter = MatterDev;
return MatterDev.Render._world(render);
};
MatterBuild.Mouse.setElement = function(mouse) {
return MatterBuild.Mouse._setElement(mouse, demo.example.instance.render.canvas);
};
window.Matter = MatterBuild;
MatterTools.Demo._setExample(
demoBuild, demoBuild.examples.find(function(e) { return e.name === example.name; })
);
window.Matter = MatterDev;
};
// reset both engine versions simultaneously
MatterTools.Demo._reset = MatterTools.Demo.reset;
MatterTools.Demo.reset = function(_demo) {
MatterBuild.Common._nextId = MatterBuild.Common._seed = 0;
MatterDev.Common._nextId = MatterDev.Common._seed = 0;
window.Matter = MatterBuild;
MatterTools.Demo._reset(demoBuild);
window.Matter = MatterDev;
MatterTools.Demo._reset(demo);
};
document.body.appendChild(demo.dom.root);
document.body.appendChild(demoBuild.dom.root);
MatterTools.Demo.start(demo);
console.info(
'Demo.Compare: comparing matter-js@' + MatterDev.version + ' with matter-js@' + MatterBuild.version
);
});
document.body.append(matterBuildScript);
})();

View file

@ -1,107 +0,0 @@
/**
* The Matter.js development demo and testing tool.
*
* This demo uses MatterTools, you can see the wiki for a simple example instead:
* https://github.com/liabru/matter-js/wiki/Getting-started
*
* NOTE: For the actual example code, refer to the source files in `/examples/`.
*
* @class Demo
*/
(function() {
var examples = [
{ name: 'Air Friction', id: 'airFriction' },
{ name: 'Avalanche', id: 'avalanche' },
{ name: 'Ball Pool', id: 'ballPool' },
{ name: 'Bridge', id: 'bridge' },
{ name: 'Broadphase', id: 'broadphase' },
{ name: 'Car', id: 'car' },
{ name: 'Catapult', id: 'catapult' },
{ name: 'Chains', id: 'chains' },
{ name: 'Circle Stack', id: 'circleStack' },
{ name: 'Cloth', id: 'cloth' },
{ name: 'Collision Filtering', id: 'collisionFiltering' },
{ name: 'Composite Manipulation', id: 'compositeManipulation' },
{ name: 'Compound Bodies', id: 'compound' },
{ name: 'Compound Stack', id: 'compoundStack' },
{ name: 'Concave', id: 'concave' },
{ name: 'Constraints', id: 'constraints' },
{ name: 'Double Pendulum', id: 'doublePendulum' },
{ name: 'Events', id: 'events' },
{ name: 'Friction', id: 'friction' },
{ name: 'Reverse Gravity', id: 'gravity' },
{ name: 'Gyroscope', id: 'gyro' },
{ name: 'Manipulation', id: 'manipulation' },
{ name: 'Mixed Shapes', id: 'mixed' },
{ name: 'Newton\'s Cradle', id: 'newtonsCradle' },
{ name: 'Ragdoll', id: 'ragdoll' },
{ name: 'Pyramid', id: 'pyramid' },
{ name: 'Raycasting', id: 'raycasting' },
{ name: 'Restitution', id: 'restitution' },
{ name: 'Rounded Corners (Chamfering)', id: 'rounded' },
{ name: 'Sensors', id: 'sensors' },
{ name: 'Sleeping', id: 'sleeping' },
{ name: 'Slingshot', id: 'slingshot' },
{ name: 'Soft Body', id: 'softBody' },
{ name: 'Sprites', id: 'sprites' },
{ name: 'Stack', id: 'stack' },
{ name: 'Static Friction', id: 'staticFriction' },
{ name: 'Stress', id: 'stress' },
{ name: 'Stress 2', id: 'stress2' },
{ name: 'Concave SVG Paths', id: 'svg' },
{ name: 'Terrain', id: 'terrain' },
{ name: 'Time Scaling', id: 'timescale' },
{ name: 'Views', id: 'views' },
{ name: 'Wrecking Ball', id: 'wreckingBall' }
];
var sourceLinkRoot = 'https://github.com/liabru/matter-js/blob/master/examples';
for (var i = 0; i < examples.length; i += 1) {
var example = examples[i];
example.sourceLink = sourceLinkRoot + '/' + example.id + '.js';
example.init = window.Example[example.id];
if (!example.init) {
console.warn('Example not loaded:', example.id);
}
}
if (window.location.search.indexOf('compare') >= 0) {
var compareScript = document.createElement('script');
compareScript.src = '../js/Compare.js';
window.MatterDemo = { examples: examples };
document.body.append(compareScript);
return;
}
var demo = MatterTools.Demo.create({
toolbar: {
title: 'matter-js',
url: 'https://github.com/liabru/matter-js',
reset: true,
source: true,
inspector: true,
tools: true,
fullscreen: true,
exampleSelect: true
},
tools: {
inspector: true,
gui: true
},
inline: false,
preventZoom: true,
resetOnOrientation: true,
routing: true,
startExample: 'mixed',
examples: examples
});
window.MatterDemo = demo;
document.body.appendChild(demo.dom.root);
MatterTools.Demo.start(demo);
})();

File diff suppressed because it is too large Load diff

View file

@ -1,3 +0,0 @@
// bundle entry point for the development server
Example = require('../../examples/index.js');
module.exports = require('../../src/module/main.js');

6
demo/js/matter-demo.a280d3.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,5 @@
/*!
* matter-demo bundle 0.18.0 by @liabru
* http://brm.io/matter-js/
* License MIT
*/!function(e){function t(t){for(var n,l,a=t[0],f=t[1],i=t[2],c=0,s=[];c<a.length;c++)l=a[c],Object.prototype.hasOwnProperty.call(o,l)&&o[l]&&s.push(o[l][0]),o[l]=0;for(n in f)Object.prototype.hasOwnProperty.call(f,n)&&(e[n]=f[n]);for(p&&p(t);s.length;)s.shift()();return u.push.apply(u,i||[]),r()}function r(){for(var e,t=0;t<u.length;t++){for(var r=u[t],n=!0,a=1;a<r.length;a++){var f=r[a];0!==o[f]&&(n=!1)}n&&(u.splice(t--,1),e=l(l.s=r[0]))}return e}var n={},o={1:0},u=[];function l(t){if(n[t])return n[t].exports;var r=n[t]={i:t,l:!1,exports:{}};return e[t].call(r.exports,r,r.exports,l),r.l=!0,r.exports}l.m=e,l.c=n,l.d=function(e,t,r){l.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},l.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},l.t=function(e,t){if(1&t&&(e=l(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(l.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var n in e)l.d(r,n,function(t){return e[t]}.bind(null,n));return r},l.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return l.d(t,"a",t),t},l.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},l.p="./js";var a=this.webpackJsonpMatterDemo=this.webpackJsonpMatterDemo||[],f=a.push.bind(a);a.push=t,a=a.slice();for(var i=0;i<a.length;i++)t(a[i]);var p=f;r()}([]);

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,12 @@
/*!
* matter-demo bundle 0.18.0 by @liabru
* http://brm.io/matter-js/
* License MIT
*/
(this.webpackJsonpMatterDemo=this.webpackJsonpMatterDemo||[]).push([[3],{OPlj:function(n,r,t){
/*!
* matter-wrap 0.2.0 by Liam Brummitt 2017-07-04
* https://github.com/liabru/matter-wrap
* License MIT
*/
var o;o=function(n){return function(n){var r={};function t(o){if(r[o])return r[o].exports;var e=r[o]={i:o,l:!1,exports:{}};return n[o].call(e.exports,e,e.exports,t),e.l=!0,e.exports}return t.m=n,t.c=r,t.i=function(n){return n},t.d=function(n,r,o){t.o(n,r)||Object.defineProperty(n,r,{configurable:!1,enumerable:!0,get:o})},t.n=function(n){var r=n&&n.__esModule?function(){return n.default}:function(){return n};return t.d(r,"a",r),r},t.o=function(n,r){return Object.prototype.hasOwnProperty.call(n,r)},t.p="/libs",t(t.s=1)}([function(r,t){r.exports=n},function(n,r,t){"use strict";var o=t(0),e={name:"matter-wrap",version:"0.1.3",for:"matter-js@^0.12.0",install:function(n){n.after("Engine.update",(function(){e.Engine.update(this)}))},Engine:{update:function(n){for(var r=n.world,t=o.Composite.allBodies(r),i=o.Composite.allComposites(r),a=0;a<t.length;a+=1){var u=t[a];u.plugin.wrap&&e.Body.wrap(u,u.plugin.wrap)}for(a=0;a<i.length;a+=1){var s=i[a];s.plugin.wrap&&e.Composite.wrap(s,s.plugin.wrap)}}},Bounds:{wrap:function(n,r){var t=null,o=null;if(void 0!==r.min.x&&void 0!==r.max.x&&(n.min.x>r.max.x?t=r.min.x-n.max.x:n.max.x<r.min.x&&(t=r.max.x-n.min.x)),void 0!==r.min.y&&void 0!==r.max.y&&(n.min.y>r.max.y?o=r.min.y-n.max.y:n.max.y<r.min.y&&(o=r.max.y-n.min.y)),null!==t||null!==o)return{x:t||0,y:o||0}}},Body:{wrap:function(n,r){var t=e.Bounds.wrap(n.bounds,r);return t&&o.Body.translate(n,t),t}},Composite:{bounds:function(n){for(var r=o.Composite.allBodies(n),t=[],e=0;e<r.length;e+=1){var i=r[e];t.push(i.bounds.min,i.bounds.max)}return o.Bounds.create(t)},wrap:function(n,r){var t=e.Bounds.wrap(e.Composite.bounds(n),r);return t&&o.Composite.translate(n,t),t}}};o.Plugin.register(e),n.exports=e}])},n.exports=o(t("lniP"))}}]);

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,6 @@
/*!
* matter-demo bundle 0.18.0 by @liabru
* http://brm.io/matter-js/
* License MIT
*/
(this.webpackJsonpMatterDemo=this.webpackJsonpMatterDemo||[]).push([[5],{Dded:function(n,r){function t(n,r,t){t=t||0;var e,u,f,o,i,h,a,l=[0,0];return e=n[1][1]-n[0][1],u=n[0][0]-n[1][0],f=e*n[0][0]+u*n[0][1],o=r[1][1]-r[0][1],i=r[0][0]-r[1][0],h=o*r[0][0]+i*r[0][1],x(a=e*i-o*u,0,t)||(l[0]=(i*f-u*h)/a,l[1]=(e*h-o*f)/a),l}function e(n,r,t,e){var u=r[0]-n[0],f=r[1]-n[1],o=e[0]-t[0],i=e[1]-t[1];if(o*f-i*u==0)return!1;var h=(u*(t[1]-n[1])+f*(n[0]-t[0]))/(o*f-i*u),a=(o*(n[1]-t[1])+i*(t[0]-n[0]))/(i*u-o*f);return h>=0&&h<=1&&a>=0&&a<=1}function u(n,r,t){return(r[0]-n[0])*(t[1]-n[1])-(t[0]-n[0])*(r[1]-n[1])}function f(n,r,t){return u(n,r,t)>0}function o(n,r,t){return u(n,r,t)>=0}function i(n,r,t){return u(n,r,t)<0}function h(n,r,t){return u(n,r,t)<=0}n.exports={decomp:function(n){var r=k(n);return r.length>0?D(n,r):[n]},quickDecomp:function n(r,t,e,u,a,l,c){l=l||100,c=c||0,a=a||25,t=void 0!==t?t:[],e=e||[],u=u||[];var m=[0,0],A=[0,0],M=[0,0],d=0,k=0,D=0,x=0,w=0,y=0,C=0,E=[],L=[],N=r,U=r;if(U.length<3)return t;if(++c>l)return console.warn("quickDecomp: max level ("+l+") reached."),t;for(var V=0;V<r.length;++V)if(p(N,V)){e.push(N[V]),d=k=Number.MAX_VALUE;for(var X=0;X<r.length;++X)f(s(N,V-1),s(N,V),s(N,X))&&h(s(N,V-1),s(N,V),s(N,X-1))&&(M=q(s(N,V-1),s(N,V),s(N,X),s(N,X-1)),i(s(N,V+1),s(N,V),M)&&(D=g(N[V],M))<k&&(k=D,A=M,y=X)),f(s(N,V+1),s(N,V),s(N,X+1))&&h(s(N,V+1),s(N,V),s(N,X))&&(M=q(s(N,V+1),s(N,V),s(N,X),s(N,X+1)),f(s(N,V-1),s(N,V),M)&&(D=g(N[V],M))<d&&(d=D,m=M,w=X));if(y===(w+1)%r.length)M[0]=(A[0]+m[0])/2,M[1]=(A[1]+m[1])/2,u.push(M),V<w?(v(E,N,V,w+1),E.push(M),L.push(M),0!==y&&v(L,N,y,N.length),v(L,N,0,V+1)):(0!==V&&v(E,N,V,N.length),v(E,N,0,w+1),E.push(M),L.push(M),v(L,N,y,V+1));else{if(y>w&&(w+=r.length),x=Number.MAX_VALUE,w<y)return t;for(X=y;X<=w;++X)o(s(N,V-1),s(N,V),s(N,X))&&h(s(N,V+1),s(N,V),s(N,X))&&(D=g(s(N,V),s(N,X)))<x&&b(N,V,X)&&(x=D,C=X%r.length);V<C?(v(E,N,V,C+1),0!==C&&v(L,N,C,U.length),v(L,N,0,V+1)):(0!==V&&v(E,N,V,U.length),v(E,N,0,C+1),v(L,N,C,V+1))}return E.length<L.length?(n(E,t,e,u,a,l,c),n(L,t,e,u,a,l,c)):(n(L,t,e,u,a,l,c),n(E,t,e,u,a,l,c)),t}return t.push(r),t},isSimple:function(n){var r,t=n;for(r=0;r<t.length-1;r++)for(var u=0;u<r-1;u++)if(e(t[r],t[r+1],t[u],t[u+1]))return!1;for(r=1;r<t.length-2;r++)if(e(t[0],t[t.length-1],t[r],t[r+1]))return!1;return!0},removeCollinearPoints:function(n,r){for(var t=0,e=n.length-1;n.length>3&&e>=0;--e)c(s(n,e-1),s(n,e),s(n,e+1),r)&&(n.splice(e%n.length,1),t++);return t},removeDuplicatePoints:function(n,r){for(var t=n.length-1;t>=1;--t)for(var e=n[t],u=t-1;u>=0;--u)w(e,n[u],r)&&n.splice(t,1)},makeCCW:function(n){for(var r=0,t=n,e=1;e<n.length;++e)(t[e][1]<t[r][1]||t[e][1]===t[r][1]&&t[e][0]>t[r][0])&&(r=e);return!f(s(n,r-1),s(n,r),s(n,r+1))&&(function(n){for(var r=[],t=n.length,e=0;e!==t;e++)r.push(n.pop());for(e=0;e!==t;e++)n[e]=r[e]}(n),!0)}};var a=[],l=[];function c(n,r,t,e){if(e){var f=a,o=l;f[0]=r[0]-n[0],f[1]=r[1]-n[1],o[0]=t[0]-r[0],o[1]=t[1]-r[1];var i=f[0]*o[0]+f[1]*o[1],h=Math.sqrt(f[0]*f[0]+f[1]*f[1]),c=Math.sqrt(o[0]*o[0]+o[1]*o[1]);return Math.acos(i/(h*c))<e}return 0===u(n,r,t)}function g(n,r){var t=r[0]-n[0],e=r[1]-n[1];return t*t+e*e}function s(n,r){var t=n.length;return n[r<0?r%t+t:r%t]}function v(n,r,t,e){for(var u=t;u<e;u++)n.push(r[u])}function p(n,r){return i(s(n,r-1),s(n,r),s(n,r+1))}var m=[],A=[];function M(n,r,e){var u,f,i=m,a=A;if(o(s(n,r+1),s(n,r),s(n,e))&&h(s(n,r-1),s(n,r),s(n,e)))return!1;f=g(s(n,r),s(n,e));for(var l=0;l!==n.length;++l)if((l+1)%n.length!==r&&l!==r&&o(s(n,r),s(n,e),s(n,l+1))&&h(s(n,r),s(n,e),s(n,l))&&(i[0]=s(n,r),i[1]=s(n,e),a[0]=s(n,l),a[1]=s(n,l+1),u=t(i,a),g(s(n,r),u)<f))return!1;return!0}function b(n,r,t){for(var u=0;u!==n.length;++u)if(u!==r&&u!==t&&(u+1)%n.length!==r&&(u+1)%n.length!==t&&e(s(n,r),s(n,t),s(n,u),s(n,u+1)))return!1;return!0}function d(n,r,t,e){var u=e||[];if(function(n){n.length=0}(u),r<t)for(var f=r;f<=t;f++)u.push(n[f]);else{for(f=0;f<=t;f++)u.push(n[f]);for(f=r;f<n.length;f++)u.push(n[f])}return u}function k(n){for(var r=[],t=[],e=[],u=[],f=Number.MAX_VALUE,o=0;o<n.length;++o)if(p(n,o))for(var i=0;i<n.length;++i)if(M(n,o,i)){t=k(d(n,o,i,u)),e=k(d(n,i,o,u));for(var h=0;h<e.length;h++)t.push(e[h]);t.length<f&&(r=t,f=t.length,r.push([s(n,o),s(n,i)]))}return r}function D(n,r){if(0===r.length)return[n];if(r instanceof Array&&r.length&&r[0]instanceof Array&&2===r[0].length&&r[0][0]instanceof Array){for(var t=[n],e=0;e<r.length;e++)for(var u=r[e],f=0;f<t.length;f++){var o=D(t[f],u);if(o){t.splice(f,1),t.push(o[0],o[1]);break}}return t}u=r,e=n.indexOf(u[0]),f=n.indexOf(u[1]);return-1!==e&&-1!==f&&[d(n,e,f),d(n,f,e)]}function q(n,r,t,e,u){u=u||0;var f=r[1]-n[1],o=n[0]-r[0],i=f*n[0]+o*n[1],h=e[1]-t[1],a=t[0]-e[0],l=h*t[0]+a*t[1],c=f*a-h*o;return x(c,0,u)?[0,0]:[(a*i-o*l)/c,(f*l-h*i)/c]}function x(n,r,t){return t=t||0,Math.abs(n-r)<=t}function w(n,r,t){return x(n[0],r[0],t)&&x(n[1],r[1],t)}}}]);

View file

@ -1,604 +0,0 @@
!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.decomp=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){
module.exports = {
decomp: polygonDecomp,
quickDecomp: polygonQuickDecomp,
isSimple: polygonIsSimple,
removeCollinearPoints: polygonRemoveCollinearPoints,
makeCCW: polygonMakeCCW
};
/**
* Compute the intersection between two lines.
* @static
* @method lineInt
* @param {Array} l1 Line vector 1
* @param {Array} l2 Line vector 2
* @param {Number} precision Precision to use when checking if the lines are parallel
* @return {Array} The intersection point.
*/
function lineInt(l1,l2,precision){
precision = precision || 0;
var i = [0,0]; // point
var a1, b1, c1, a2, b2, c2, det; // scalars
a1 = l1[1][1] - l1[0][1];
b1 = l1[0][0] - l1[1][0];
c1 = a1 * l1[0][0] + b1 * l1[0][1];
a2 = l2[1][1] - l2[0][1];
b2 = l2[0][0] - l2[1][0];
c2 = a2 * l2[0][0] + b2 * l2[0][1];
det = a1 * b2 - a2*b1;
if (!scalar_eq(det, 0, precision)) { // lines are not parallel
i[0] = (b2 * c1 - b1 * c2) / det;
i[1] = (a1 * c2 - a2 * c1) / det;
}
return i;
}
/**
* Checks if two line segments intersects.
* @method segmentsIntersect
* @param {Array} p1 The start vertex of the first line segment.
* @param {Array} p2 The end vertex of the first line segment.
* @param {Array} q1 The start vertex of the second line segment.
* @param {Array} q2 The end vertex of the second line segment.
* @return {Boolean} True if the two line segments intersect
*/
function lineSegmentsIntersect(p1, p2, q1, q2){
var dx = p2[0] - p1[0];
var dy = p2[1] - p1[1];
var da = q2[0] - q1[0];
var db = q2[1] - q1[1];
// segments are parallel
if((da*dy - db*dx) === 0){
return false;
}
var s = (dx * (q1[1] - p1[1]) + dy * (p1[0] - q1[0])) / (da * dy - db * dx);
var t = (da * (p1[1] - q1[1]) + db * (q1[0] - p1[0])) / (db * dx - da * dy);
return (s>=0 && s<=1 && t>=0 && t<=1);
}
/**
* Get the area of a triangle spanned by the three given points. Note that the area will be negative if the points are not given in counter-clockwise order.
* @static
* @method area
* @param {Array} a
* @param {Array} b
* @param {Array} c
* @return {Number}
*/
function triangleArea(a,b,c){
return (((b[0] - a[0])*(c[1] - a[1]))-((c[0] - a[0])*(b[1] - a[1])));
}
function isLeft(a,b,c){
return triangleArea(a,b,c) > 0;
}
function isLeftOn(a,b,c) {
return triangleArea(a, b, c) >= 0;
}
function isRight(a,b,c) {
return triangleArea(a, b, c) < 0;
}
function isRightOn(a,b,c) {
return triangleArea(a, b, c) <= 0;
}
var tmpPoint1 = [],
tmpPoint2 = [];
/**
* Check if three points are collinear
* @method collinear
* @param {Array} a
* @param {Array} b
* @param {Array} c
* @param {Number} [thresholdAngle=0] Threshold angle to use when comparing the vectors. The function will return true if the angle between the resulting vectors is less than this value. Use zero for max precision.
* @return {Boolean}
*/
function collinear(a,b,c,thresholdAngle) {
if(!thresholdAngle){
return triangleArea(a, b, c) === 0;
} else {
var ab = tmpPoint1,
bc = tmpPoint2;
ab[0] = b[0]-a[0];
ab[1] = b[1]-a[1];
bc[0] = c[0]-b[0];
bc[1] = c[1]-b[1];
var dot = ab[0]*bc[0] + ab[1]*bc[1],
magA = Math.sqrt(ab[0]*ab[0] + ab[1]*ab[1]),
magB = Math.sqrt(bc[0]*bc[0] + bc[1]*bc[1]),
angle = Math.acos(dot/(magA*magB));
return angle < thresholdAngle;
}
}
function sqdist(a,b){
var dx = b[0] - a[0];
var dy = b[1] - a[1];
return dx * dx + dy * dy;
}
/**
* Get a vertex at position i. It does not matter if i is out of bounds, this function will just cycle.
* @method at
* @param {Number} i
* @return {Array}
*/
function polygonAt(polygon, i){
var s = polygon.length;
return polygon[i < 0 ? i % s + s : i % s];
}
/**
* Clear the polygon data
* @method clear
* @return {Array}
*/
function polygonClear(polygon){
polygon.length = 0;
}
/**
* Append points "from" to "to"-1 from an other polygon "poly" onto this one.
* @method append
* @param {Polygon} poly The polygon to get points from.
* @param {Number} from The vertex index in "poly".
* @param {Number} to The end vertex index in "poly". Note that this vertex is NOT included when appending.
* @return {Array}
*/
function polygonAppend(polygon, poly, from, to){
for(var i=from; i<to; i++){
polygon.push(poly[i]);
}
}
/**
* Make sure that the polygon vertices are ordered counter-clockwise.
* @method makeCCW
*/
function polygonMakeCCW(polygon){
var br = 0,
v = polygon;
// find bottom right point
for (var i = 1; i < polygon.length; ++i) {
if (v[i][1] < v[br][1] || (v[i][1] === v[br][1] && v[i][0] > v[br][0])) {
br = i;
}
}
// reverse poly if clockwise
if (!isLeft(polygonAt(polygon, br - 1), polygonAt(polygon, br), polygonAt(polygon, br + 1))) {
polygonReverse(polygon);
}
}
/**
* Reverse the vertices in the polygon
* @method reverse
*/
function polygonReverse(polygon){
var tmp = [];
var N = polygon.length;
for(var i=0; i!==N; i++){
tmp.push(polygon.pop());
}
for(var i=0; i!==N; i++){
polygon[i] = tmp[i];
}
}
/**
* Check if a point in the polygon is a reflex point
* @method isReflex
* @param {Number} i
* @return {Boolean}
*/
function polygonIsReflex(polygon, i){
return isRight(polygonAt(polygon, i - 1), polygonAt(polygon, i), polygonAt(polygon, i + 1));
}
var tmpLine1=[],
tmpLine2=[];
/**
* Check if two vertices in the polygon can see each other
* @method canSee
* @param {Number} a Vertex index 1
* @param {Number} b Vertex index 2
* @return {Boolean}
*/
function polygonCanSee(polygon, a,b) {
var p, dist, l1=tmpLine1, l2=tmpLine2;
if (isLeftOn(polygonAt(polygon, a + 1), polygonAt(polygon, a), polygonAt(polygon, b)) && isRightOn(polygonAt(polygon, a - 1), polygonAt(polygon, a), polygonAt(polygon, b))) {
return false;
}
dist = sqdist(polygonAt(polygon, a), polygonAt(polygon, b));
for (var i = 0; i !== polygon.length; ++i) { // for each edge
if ((i + 1) % polygon.length === a || i === a){ // ignore incident edges
continue;
}
if (isLeftOn(polygonAt(polygon, a), polygonAt(polygon, b), polygonAt(polygon, i + 1)) && isRightOn(polygonAt(polygon, a), polygonAt(polygon, b), polygonAt(polygon, i))) { // if diag intersects an edge
l1[0] = polygonAt(polygon, a);
l1[1] = polygonAt(polygon, b);
l2[0] = polygonAt(polygon, i);
l2[1] = polygonAt(polygon, i + 1);
p = lineInt(l1,l2);
if (sqdist(polygonAt(polygon, a), p) < dist) { // if edge is blocking visibility to b
return false;
}
}
}
return true;
}
/**
* Copy the polygon from vertex i to vertex j.
* @method copy
* @param {Number} i
* @param {Number} j
* @param {Polygon} [targetPoly] Optional target polygon to save in.
* @return {Polygon} The resulting copy.
*/
function polygonCopy(polygon, i,j,targetPoly){
var p = targetPoly || [];
polygonClear(p);
if (i < j) {
// Insert all vertices from i to j
for(var k=i; k<=j; k++){
p.push(polygon[k]);
}
} else {
// Insert vertices 0 to j
for(var k=0; k<=j; k++){
p.push(polygon[k]);
}
// Insert vertices i to end
for(var k=i; k<polygon.length; k++){
p.push(polygon[k]);
}
}
return p;
}
/**
* Decomposes the polygon into convex pieces. Returns a list of edges [[p1,p2],[p2,p3],...] that cuts the polygon.
* Note that this algorithm has complexity O(N^4) and will be very slow for polygons with many vertices.
* @method getCutEdges
* @return {Array}
*/
function polygonGetCutEdges(polygon) {
var min=[], tmp1=[], tmp2=[], tmpPoly = [];
var nDiags = Number.MAX_VALUE;
for (var i = 0; i < polygon.length; ++i) {
if (polygonIsReflex(polygon, i)) {
for (var j = 0; j < polygon.length; ++j) {
if (polygonCanSee(polygon, i, j)) {
tmp1 = polygonGetCutEdges(polygonCopy(polygon, i, j, tmpPoly));
tmp2 = polygonGetCutEdges(polygonCopy(polygon, j, i, tmpPoly));
for(var k=0; k<tmp2.length; k++){
tmp1.push(tmp2[k]);
}
if (tmp1.length < nDiags) {
min = tmp1;
nDiags = tmp1.length;
min.push([polygonAt(polygon, i), polygonAt(polygon, j)]);
}
}
}
}
}
return min;
}
/**
* Decomposes the polygon into one or more convex sub-Polygons.
* @method decomp
* @return {Array} An array or Polygon objects.
*/
function polygonDecomp(polygon){
var edges = polygonGetCutEdges(polygon);
if(edges.length > 0){
return polygonSlice(polygon, edges);
} else {
return [polygon];
}
}
/**
* Slices the polygon given one or more cut edges. If given one, this function will return two polygons (false on failure). If many, an array of polygons.
* @method slice
* @param {Array} cutEdges A list of edges, as returned by .getCutEdges()
* @return {Array}
*/
function polygonSlice(polygon, cutEdges){
if(cutEdges.length === 0){
return [polygon];
}
if(cutEdges instanceof Array && cutEdges.length && cutEdges[0] instanceof Array && cutEdges[0].length===2 && cutEdges[0][0] instanceof Array){
var polys = [polygon];
for(var i=0; i<cutEdges.length; i++){
var cutEdge = cutEdges[i];
// Cut all polys
for(var j=0; j<polys.length; j++){
var poly = polys[j];
var result = polygonSlice(poly, cutEdge);
if(result){
// Found poly! Cut and quit
polys.splice(j,1);
polys.push(result[0],result[1]);
break;
}
}
}
return polys;
} else {
// Was given one edge
var cutEdge = cutEdges;
var i = polygon.indexOf(cutEdge[0]);
var j = polygon.indexOf(cutEdge[1]);
if(i !== -1 && j !== -1){
return [polygonCopy(polygon, i,j),
polygonCopy(polygon, j,i)];
} else {
return false;
}
}
}
/**
* Checks that the line segments of this polygon do not intersect each other.
* @method isSimple
* @param {Array} path An array of vertices e.g. [[0,0],[0,1],...]
* @return {Boolean}
* @todo Should it check all segments with all others?
*/
function polygonIsSimple(polygon){
var path = polygon, i;
// Check
for(i=0; i<path.length-1; i++){
for(var j=0; j<i-1; j++){
if(lineSegmentsIntersect(path[i], path[i+1], path[j], path[j+1] )){
return false;
}
}
}
// Check the segment between the last and the first point to all others
for(i=1; i<path.length-2; i++){
if(lineSegmentsIntersect(path[0], path[path.length-1], path[i], path[i+1] )){
return false;
}
}
return true;
}
function getIntersectionPoint(p1, p2, q1, q2, delta){
delta = delta || 0;
var a1 = p2[1] - p1[1];
var b1 = p1[0] - p2[0];
var c1 = (a1 * p1[0]) + (b1 * p1[1]);
var a2 = q2[1] - q1[1];
var b2 = q1[0] - q2[0];
var c2 = (a2 * q1[0]) + (b2 * q1[1]);
var det = (a1 * b2) - (a2 * b1);
if(!scalar_eq(det,0,delta)){
return [((b2 * c1) - (b1 * c2)) / det, ((a1 * c2) - (a2 * c1)) / det];
} else {
return [0,0];
}
}
/**
* Quickly decompose the Polygon into convex sub-polygons.
* @method quickDecomp
* @param {Array} result
* @param {Array} [reflexVertices]
* @param {Array} [steinerPoints]
* @param {Number} [delta]
* @param {Number} [maxlevel]
* @param {Number} [level]
* @return {Array}
*/
function polygonQuickDecomp(polygon, result,reflexVertices,steinerPoints,delta,maxlevel,level){
maxlevel = maxlevel || 100;
level = level || 0;
delta = delta || 25;
result = typeof(result)!=="undefined" ? result : [];
reflexVertices = reflexVertices || [];
steinerPoints = steinerPoints || [];
var upperInt=[0,0], lowerInt=[0,0], p=[0,0]; // Points
var upperDist=0, lowerDist=0, d=0, closestDist=0; // scalars
var upperIndex=0, lowerIndex=0, closestIndex=0; // Integers
var lowerPoly=[], upperPoly=[]; // polygons
var poly = polygon,
v = polygon;
if(v.length < 3){
return result;
}
level++;
if(level > maxlevel){
console.warn("quickDecomp: max level ("+maxlevel+") reached.");
return result;
}
for (var i = 0; i < polygon.length; ++i) {
if (polygonIsReflex(poly, i)) {
reflexVertices.push(poly[i]);
upperDist = lowerDist = Number.MAX_VALUE;
for (var j = 0; j < polygon.length; ++j) {
if (isLeft(polygonAt(poly, i - 1), polygonAt(poly, i), polygonAt(poly, j)) && isRightOn(polygonAt(poly, i - 1), polygonAt(poly, i), polygonAt(poly, j - 1))) { // if line intersects with an edge
p = getIntersectionPoint(polygonAt(poly, i - 1), polygonAt(poly, i), polygonAt(poly, j), polygonAt(poly, j - 1)); // find the point of intersection
if (isRight(polygonAt(poly, i + 1), polygonAt(poly, i), p)) { // make sure it's inside the poly
d = sqdist(poly[i], p);
if (d < lowerDist) { // keep only the closest intersection
lowerDist = d;
lowerInt = p;
lowerIndex = j;
}
}
}
if (isLeft(polygonAt(poly, i + 1), polygonAt(poly, i), polygonAt(poly, j + 1)) && isRightOn(polygonAt(poly, i + 1), polygonAt(poly, i), polygonAt(poly, j))) {
p = getIntersectionPoint(polygonAt(poly, i + 1), polygonAt(poly, i), polygonAt(poly, j), polygonAt(poly, j + 1));
if (isLeft(polygonAt(poly, i - 1), polygonAt(poly, i), p)) {
d = sqdist(poly[i], p);
if (d < upperDist) {
upperDist = d;
upperInt = p;
upperIndex = j;
}
}
}
}
// if there are no vertices to connect to, choose a point in the middle
if (lowerIndex === (upperIndex + 1) % polygon.length) {
//console.log("Case 1: Vertex("+i+"), lowerIndex("+lowerIndex+"), upperIndex("+upperIndex+"), poly.size("+polygon.length+")");
p[0] = (lowerInt[0] + upperInt[0]) / 2;
p[1] = (lowerInt[1] + upperInt[1]) / 2;
steinerPoints.push(p);
if (i < upperIndex) {
//lowerPoly.insert(lowerPoly.end(), poly.begin() + i, poly.begin() + upperIndex + 1);
polygonAppend(lowerPoly, poly, i, upperIndex+1);
lowerPoly.push(p);
upperPoly.push(p);
if (lowerIndex !== 0){
//upperPoly.insert(upperPoly.end(), poly.begin() + lowerIndex, poly.end());
polygonAppend(upperPoly, poly,lowerIndex,poly.length);
}
//upperPoly.insert(upperPoly.end(), poly.begin(), poly.begin() + i + 1);
polygonAppend(upperPoly, poly,0,i+1);
} else {
if (i !== 0){
//lowerPoly.insert(lowerPoly.end(), poly.begin() + i, poly.end());
polygonAppend(lowerPoly, poly,i,poly.length);
}
//lowerPoly.insert(lowerPoly.end(), poly.begin(), poly.begin() + upperIndex + 1);
polygonAppend(lowerPoly, poly,0,upperIndex+1);
lowerPoly.push(p);
upperPoly.push(p);
//upperPoly.insert(upperPoly.end(), poly.begin() + lowerIndex, poly.begin() + i + 1);
polygonAppend(upperPoly, poly,lowerIndex,i+1);
}
} else {
// connect to the closest point within the triangle
//console.log("Case 2: Vertex("+i+"), closestIndex("+closestIndex+"), poly.size("+polygon.length+")\n");
if (lowerIndex > upperIndex) {
upperIndex += polygon.length;
}
closestDist = Number.MAX_VALUE;
if(upperIndex < lowerIndex){
return result;
}
for (var j = lowerIndex; j <= upperIndex; ++j) {
if (isLeftOn(polygonAt(poly, i - 1), polygonAt(poly, i), polygonAt(poly, j)) && isRightOn(polygonAt(poly, i + 1), polygonAt(poly, i), polygonAt(poly, j))) {
d = sqdist(polygonAt(poly, i), polygonAt(poly, j));
if (d < closestDist) {
closestDist = d;
closestIndex = j % polygon.length;
}
}
}
if (i < closestIndex) {
polygonAppend(lowerPoly, poly,i,closestIndex+1);
if (closestIndex !== 0){
polygonAppend(upperPoly, poly,closestIndex,v.length);
}
polygonAppend(upperPoly, poly,0,i+1);
} else {
if (i !== 0){
polygonAppend(lowerPoly, poly,i,v.length);
}
polygonAppend(lowerPoly, poly,0,closestIndex+1);
polygonAppend(upperPoly, poly,closestIndex,i+1);
}
}
// solve smallest poly first
if (lowerPoly.length < upperPoly.length) {
polygonQuickDecomp(lowerPoly,result,reflexVertices,steinerPoints,delta,maxlevel,level);
polygonQuickDecomp(upperPoly,result,reflexVertices,steinerPoints,delta,maxlevel,level);
} else {
polygonQuickDecomp(upperPoly,result,reflexVertices,steinerPoints,delta,maxlevel,level);
polygonQuickDecomp(lowerPoly,result,reflexVertices,steinerPoints,delta,maxlevel,level);
}
return result;
}
}
result.push(polygon);
return result;
}
/**
* Remove collinear points in the polygon.
* @method removeCollinearPoints
* @param {Number} [precision] The threshold angle to use when determining whether two edges are collinear. Use zero for finest precision.
* @return {Number} The number of points removed
*/
function polygonRemoveCollinearPoints(polygon, precision){
var num = 0;
for(var i=polygon.length-1; polygon.length>3 && i>=0; --i){
if(collinear(polygonAt(polygon, i-1),polygonAt(polygon, i),polygonAt(polygon, i+1),precision)){
// Remove the middle point
polygon.splice(i%polygon.length,1);
num++;
}
}
return num;
}
/**
* Check if two scalars are equal
* @static
* @method eq
* @param {Number} a
* @param {Number} b
* @param {Number} [precision]
* @return {Boolean}
*/
function scalar_eq(a,b,precision){
precision = precision || 0;
return Math.abs(a-b) < precision;
}
},{}]},{},[1])
(1)
});

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1,275 +0,0 @@
/*!
* matter-wrap 0.2.0 by Liam Brummitt 2017-07-04
* https://github.com/liabru/matter-wrap
* License MIT
*/
(function webpackUniversalModuleDefinition(root, factory) {
if(typeof exports === 'object' && typeof module === 'object')
module.exports = factory(require("matter-js"));
else if(typeof define === 'function' && define.amd)
define(["matter-js"], factory);
else if(typeof exports === 'object')
exports["MatterWrap"] = factory(require("matter-js"));
else
root["MatterWrap"] = factory(root["Matter"]);
})(this, function(__WEBPACK_EXTERNAL_MODULE_0__) {
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;
/******/ // identity function for calling harmony imports with the correct context
/******/ __webpack_require__.i = function(value) { return value; };
/******/ // define getter function for harmony exports
/******/ __webpack_require__.d = function(exports, name, getter) {
/******/ if(!__webpack_require__.o(exports, name)) {
/******/ Object.defineProperty(exports, name, {
/******/ configurable: false,
/******/ enumerable: true,
/******/ get: getter
/******/ });
/******/ }
/******/ };
/******/ // 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 = "/libs";
/******/ // Load entry module and return exports
/******/ return __webpack_require__(__webpack_require__.s = 1);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, exports) {
module.exports = __WEBPACK_EXTERNAL_MODULE_0__;
/***/ }),
/* 1 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
var Matter = __webpack_require__(0);
/**
* A coordinate wrapping plugin for matter.js.
* See the readme for usage and examples.
* @module MatterWrap
*/
var MatterWrap = {
// plugin meta
name: 'matter-wrap', // PLUGIN_NAME
version: '0.1.3', // PLUGIN_VERSION
for: 'matter-js@^0.12.0',
// installs the plugin where `base` is `Matter`
// you should not need to call this directly.
install: function install(base) {
base.after('Engine.update', function () {
MatterWrap.Engine.update(this);
});
},
Engine: {
/**
* Updates the engine by wrapping bodies and composites inside `engine.world`.
* This is called automatically by the plugin.
* @function MatterWrap.Engine.update
* @param {Matter.Engine} engine The engine to update.
* @returns {void} No return value.
*/
update: function update(engine) {
var world = engine.world,
bodies = Matter.Composite.allBodies(world),
composites = Matter.Composite.allComposites(world);
for (var i = 0; i < bodies.length; i += 1) {
var body = bodies[i];
if (body.plugin.wrap) {
MatterWrap.Body.wrap(body, body.plugin.wrap);
}
}
for (i = 0; i < composites.length; i += 1) {
var composite = composites[i];
if (composite.plugin.wrap) {
MatterWrap.Composite.wrap(composite, composite.plugin.wrap);
}
}
}
},
Bounds: {
/**
* Returns a translation vector that wraps the `objectBounds` inside the `bounds`.
* @function MatterWrap.Bounds.wrap
* @param {Matter.Bounds} objectBounds The bounds of the object to wrap inside the bounds.
* @param {Matter.Bounds} bounds The bounds to wrap the body inside.
* @returns {?Matter.Vector} A translation vector (only if wrapping is required).
*/
wrap: function wrap(objectBounds, bounds) {
var x = null,
y = null;
if (typeof bounds.min.x !== 'undefined' && typeof bounds.max.x !== 'undefined') {
if (objectBounds.min.x > bounds.max.x) {
x = bounds.min.x - objectBounds.max.x;
} else if (objectBounds.max.x < bounds.min.x) {
x = bounds.max.x - objectBounds.min.x;
}
}
if (typeof bounds.min.y !== 'undefined' && typeof bounds.max.y !== 'undefined') {
if (objectBounds.min.y > bounds.max.y) {
y = bounds.min.y - objectBounds.max.y;
} else if (objectBounds.max.y < bounds.min.y) {
y = bounds.max.y - objectBounds.min.y;
}
}
if (x !== null || y !== null) {
return {
x: x || 0,
y: y || 0
};
}
}
},
Body: {
/**
* Wraps the `body` position such that it always stays within the given bounds.
* Upon crossing a boundary the body will appear on the opposite side of the bounds,
* while maintaining its velocity.
* This is called automatically by the plugin.
* @function MatterWrap.Body.wrap
* @param {Matter.Body} body The body to wrap.
* @param {Matter.Bounds} bounds The bounds to wrap the body inside.
* @returns {?Matter.Vector} The translation vector that was applied (only if wrapping was required).
*/
wrap: function wrap(body, bounds) {
var translation = MatterWrap.Bounds.wrap(body.bounds, bounds);
if (translation) {
Matter.Body.translate(body, translation);
}
return translation;
}
},
Composite: {
/**
* Returns the union of the bounds of all of the composite's bodies
* (not accounting for constraints).
* @function MatterWrap.Composite.bounds
* @param {Matter.Composite} composite The composite.
* @returns {Matter.Bounds} The composite bounds.
*/
bounds: function bounds(composite) {
var bodies = Matter.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 Matter.Bounds.create(vertices);
},
/**
* Wraps the `composite` position such that it always stays within the given bounds.
* Upon crossing a boundary the composite will appear on the opposite side of the bounds,
* while maintaining its velocity.
* This is called automatically by the plugin.
* @function MatterWrap.Composite.wrap
* @param {Matter.Composite} composite The composite to wrap.
* @param {Matter.Bounds} bounds The bounds to wrap the composite inside.
* @returns {?Matter.Vector} The translation vector that was applied (only if wrapping was required).
*/
wrap: function wrap(composite, bounds) {
var translation = MatterWrap.Bounds.wrap(MatterWrap.Composite.bounds(composite), bounds);
if (translation) {
Matter.Composite.translate(composite, translation);
}
return translation;
}
}
};
Matter.Plugin.register(MatterWrap);
module.exports = MatterWrap;
/**
* @namespace Matter.Body
* @see http://brm.io/matter-js/docs/classes/Body.html
*/
/**
* This plugin adds a new property `body.plugin.wrap` to instances of `Matter.Body`.
* This is a `Matter.Bounds` instance that specifies the wrapping region.
* @property {Matter.Bounds} body.plugin.wrap
* @memberof Matter.Body
*/
/**
* This plugin adds a new property `composite.plugin.wrap` to instances of `Matter.Composite`.
* This is a `Matter.Bounds` instance that specifies the wrapping region.
* @property {Matter.Bounds} composite.plugin.wrap
* @memberof Matter.Composite
*/
/***/ })
/******/ ]);
});

View file

@ -1,849 +0,0 @@
// SVGPathSeg API polyfill
// https://github.com/progers/pathseg
//
// This is a drop-in replacement for the SVGPathSeg and SVGPathSegList APIs that were removed from
// SVG2 (https://lists.w3.org/Archives/Public/www-svg/2015Jun/0044.html), including the latest spec
// changes which were implemented in Firefox 43 and Chrome 46.
(function() { "use strict";
if (!("SVGPathSeg" in window)) {
// Spec: http://www.w3.org/TR/SVG11/single-page.html#paths-InterfaceSVGPathSeg
window.SVGPathSeg = function(type, typeAsLetter, owningPathSegList) {
this.pathSegType = type;
this.pathSegTypeAsLetter = typeAsLetter;
this._owningPathSegList = owningPathSegList;
}
window.SVGPathSeg.prototype.classname = "SVGPathSeg";
window.SVGPathSeg.PATHSEG_UNKNOWN = 0;
window.SVGPathSeg.PATHSEG_CLOSEPATH = 1;
window.SVGPathSeg.PATHSEG_MOVETO_ABS = 2;
window.SVGPathSeg.PATHSEG_MOVETO_REL = 3;
window.SVGPathSeg.PATHSEG_LINETO_ABS = 4;
window.SVGPathSeg.PATHSEG_LINETO_REL = 5;
window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_ABS = 6;
window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_REL = 7;
window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_ABS = 8;
window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_REL = 9;
window.SVGPathSeg.PATHSEG_ARC_ABS = 10;
window.SVGPathSeg.PATHSEG_ARC_REL = 11;
window.SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_ABS = 12;
window.SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_REL = 13;
window.SVGPathSeg.PATHSEG_LINETO_VERTICAL_ABS = 14;
window.SVGPathSeg.PATHSEG_LINETO_VERTICAL_REL = 15;
window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_ABS = 16;
window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_REL = 17;
window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS = 18;
window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL = 19;
// Notify owning PathSegList on any changes so they can be synchronized back to the path element.
window.SVGPathSeg.prototype._segmentChanged = function() {
if (this._owningPathSegList)
this._owningPathSegList.segmentChanged(this);
}
window.SVGPathSegClosePath = function(owningPathSegList) {
window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_CLOSEPATH, "z", owningPathSegList);
}
window.SVGPathSegClosePath.prototype = Object.create(window.SVGPathSeg.prototype);
window.SVGPathSegClosePath.prototype.toString = function() { return "[object SVGPathSegClosePath]"; }
window.SVGPathSegClosePath.prototype._asPathString = function() { return this.pathSegTypeAsLetter; }
window.SVGPathSegClosePath.prototype.clone = function() { return new window.SVGPathSegClosePath(undefined); }
window.SVGPathSegMovetoAbs = function(owningPathSegList, x, y) {
window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_MOVETO_ABS, "M", owningPathSegList);
this._x = x;
this._y = y;
}
window.SVGPathSegMovetoAbs.prototype = Object.create(window.SVGPathSeg.prototype);
window.SVGPathSegMovetoAbs.prototype.toString = function() { return "[object SVGPathSegMovetoAbs]"; }
window.SVGPathSegMovetoAbs.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._x + " " + this._y; }
window.SVGPathSegMovetoAbs.prototype.clone = function() { return new window.SVGPathSegMovetoAbs(undefined, this._x, this._y); }
Object.defineProperty(window.SVGPathSegMovetoAbs.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true });
Object.defineProperty(window.SVGPathSegMovetoAbs.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true });
window.SVGPathSegMovetoRel = function(owningPathSegList, x, y) {
window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_MOVETO_REL, "m", owningPathSegList);
this._x = x;
this._y = y;
}
window.SVGPathSegMovetoRel.prototype = Object.create(window.SVGPathSeg.prototype);
window.SVGPathSegMovetoRel.prototype.toString = function() { return "[object SVGPathSegMovetoRel]"; }
window.SVGPathSegMovetoRel.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._x + " " + this._y; }
window.SVGPathSegMovetoRel.prototype.clone = function() { return new window.SVGPathSegMovetoRel(undefined, this._x, this._y); }
Object.defineProperty(window.SVGPathSegMovetoRel.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true });
Object.defineProperty(window.SVGPathSegMovetoRel.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true });
window.SVGPathSegLinetoAbs = function(owningPathSegList, x, y) {
window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_LINETO_ABS, "L", owningPathSegList);
this._x = x;
this._y = y;
}
window.SVGPathSegLinetoAbs.prototype = Object.create(window.SVGPathSeg.prototype);
window.SVGPathSegLinetoAbs.prototype.toString = function() { return "[object SVGPathSegLinetoAbs]"; }
window.SVGPathSegLinetoAbs.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._x + " " + this._y; }
window.SVGPathSegLinetoAbs.prototype.clone = function() { return new window.SVGPathSegLinetoAbs(undefined, this._x, this._y); }
Object.defineProperty(window.SVGPathSegLinetoAbs.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true });
Object.defineProperty(window.SVGPathSegLinetoAbs.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true });
window.SVGPathSegLinetoRel = function(owningPathSegList, x, y) {
window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_LINETO_REL, "l", owningPathSegList);
this._x = x;
this._y = y;
}
window.SVGPathSegLinetoRel.prototype = Object.create(window.SVGPathSeg.prototype);
window.SVGPathSegLinetoRel.prototype.toString = function() { return "[object SVGPathSegLinetoRel]"; }
window.SVGPathSegLinetoRel.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._x + " " + this._y; }
window.SVGPathSegLinetoRel.prototype.clone = function() { return new window.SVGPathSegLinetoRel(undefined, this._x, this._y); }
Object.defineProperty(window.SVGPathSegLinetoRel.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true });
Object.defineProperty(window.SVGPathSegLinetoRel.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true });
window.SVGPathSegCurvetoCubicAbs = function(owningPathSegList, x, y, x1, y1, x2, y2) {
window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_ABS, "C", owningPathSegList);
this._x = x;
this._y = y;
this._x1 = x1;
this._y1 = y1;
this._x2 = x2;
this._y2 = y2;
}
window.SVGPathSegCurvetoCubicAbs.prototype = Object.create(window.SVGPathSeg.prototype);
window.SVGPathSegCurvetoCubicAbs.prototype.toString = function() { return "[object SVGPathSegCurvetoCubicAbs]"; }
window.SVGPathSegCurvetoCubicAbs.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._x1 + " " + this._y1 + " " + this._x2 + " " + this._y2 + " " + this._x + " " + this._y; }
window.SVGPathSegCurvetoCubicAbs.prototype.clone = function() { return new window.SVGPathSegCurvetoCubicAbs(undefined, this._x, this._y, this._x1, this._y1, this._x2, this._y2); }
Object.defineProperty(window.SVGPathSegCurvetoCubicAbs.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true });
Object.defineProperty(window.SVGPathSegCurvetoCubicAbs.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true });
Object.defineProperty(window.SVGPathSegCurvetoCubicAbs.prototype, "x1", { get: function() { return this._x1; }, set: function(x1) { this._x1 = x1; this._segmentChanged(); }, enumerable: true });
Object.defineProperty(window.SVGPathSegCurvetoCubicAbs.prototype, "y1", { get: function() { return this._y1; }, set: function(y1) { this._y1 = y1; this._segmentChanged(); }, enumerable: true });
Object.defineProperty(window.SVGPathSegCurvetoCubicAbs.prototype, "x2", { get: function() { return this._x2; }, set: function(x2) { this._x2 = x2; this._segmentChanged(); }, enumerable: true });
Object.defineProperty(window.SVGPathSegCurvetoCubicAbs.prototype, "y2", { get: function() { return this._y2; }, set: function(y2) { this._y2 = y2; this._segmentChanged(); }, enumerable: true });
window.SVGPathSegCurvetoCubicRel = function(owningPathSegList, x, y, x1, y1, x2, y2) {
window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_REL, "c", owningPathSegList);
this._x = x;
this._y = y;
this._x1 = x1;
this._y1 = y1;
this._x2 = x2;
this._y2 = y2;
}
window.SVGPathSegCurvetoCubicRel.prototype = Object.create(window.SVGPathSeg.prototype);
window.SVGPathSegCurvetoCubicRel.prototype.toString = function() { return "[object SVGPathSegCurvetoCubicRel]"; }
window.SVGPathSegCurvetoCubicRel.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._x1 + " " + this._y1 + " " + this._x2 + " " + this._y2 + " " + this._x + " " + this._y; }
window.SVGPathSegCurvetoCubicRel.prototype.clone = function() { return new window.SVGPathSegCurvetoCubicRel(undefined, this._x, this._y, this._x1, this._y1, this._x2, this._y2); }
Object.defineProperty(window.SVGPathSegCurvetoCubicRel.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true });
Object.defineProperty(window.SVGPathSegCurvetoCubicRel.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true });
Object.defineProperty(window.SVGPathSegCurvetoCubicRel.prototype, "x1", { get: function() { return this._x1; }, set: function(x1) { this._x1 = x1; this._segmentChanged(); }, enumerable: true });
Object.defineProperty(window.SVGPathSegCurvetoCubicRel.prototype, "y1", { get: function() { return this._y1; }, set: function(y1) { this._y1 = y1; this._segmentChanged(); }, enumerable: true });
Object.defineProperty(window.SVGPathSegCurvetoCubicRel.prototype, "x2", { get: function() { return this._x2; }, set: function(x2) { this._x2 = x2; this._segmentChanged(); }, enumerable: true });
Object.defineProperty(window.SVGPathSegCurvetoCubicRel.prototype, "y2", { get: function() { return this._y2; }, set: function(y2) { this._y2 = y2; this._segmentChanged(); }, enumerable: true });
window.SVGPathSegCurvetoQuadraticAbs = function(owningPathSegList, x, y, x1, y1) {
window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_ABS, "Q", owningPathSegList);
this._x = x;
this._y = y;
this._x1 = x1;
this._y1 = y1;
}
window.SVGPathSegCurvetoQuadraticAbs.prototype = Object.create(window.SVGPathSeg.prototype);
window.SVGPathSegCurvetoQuadraticAbs.prototype.toString = function() { return "[object SVGPathSegCurvetoQuadraticAbs]"; }
window.SVGPathSegCurvetoQuadraticAbs.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._x1 + " " + this._y1 + " " + this._x + " " + this._y; }
window.SVGPathSegCurvetoQuadraticAbs.prototype.clone = function() { return new window.SVGPathSegCurvetoQuadraticAbs(undefined, this._x, this._y, this._x1, this._y1); }
Object.defineProperty(window.SVGPathSegCurvetoQuadraticAbs.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true });
Object.defineProperty(window.SVGPathSegCurvetoQuadraticAbs.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true });
Object.defineProperty(window.SVGPathSegCurvetoQuadraticAbs.prototype, "x1", { get: function() { return this._x1; }, set: function(x1) { this._x1 = x1; this._segmentChanged(); }, enumerable: true });
Object.defineProperty(window.SVGPathSegCurvetoQuadraticAbs.prototype, "y1", { get: function() { return this._y1; }, set: function(y1) { this._y1 = y1; this._segmentChanged(); }, enumerable: true });
window.SVGPathSegCurvetoQuadraticRel = function(owningPathSegList, x, y, x1, y1) {
window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_REL, "q", owningPathSegList);
this._x = x;
this._y = y;
this._x1 = x1;
this._y1 = y1;
}
window.SVGPathSegCurvetoQuadraticRel.prototype = Object.create(window.SVGPathSeg.prototype);
window.SVGPathSegCurvetoQuadraticRel.prototype.toString = function() { return "[object SVGPathSegCurvetoQuadraticRel]"; }
window.SVGPathSegCurvetoQuadraticRel.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._x1 + " " + this._y1 + " " + this._x + " " + this._y; }
window.SVGPathSegCurvetoQuadraticRel.prototype.clone = function() { return new window.SVGPathSegCurvetoQuadraticRel(undefined, this._x, this._y, this._x1, this._y1); }
Object.defineProperty(window.SVGPathSegCurvetoQuadraticRel.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true });
Object.defineProperty(window.SVGPathSegCurvetoQuadraticRel.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true });
Object.defineProperty(window.SVGPathSegCurvetoQuadraticRel.prototype, "x1", { get: function() { return this._x1; }, set: function(x1) { this._x1 = x1; this._segmentChanged(); }, enumerable: true });
Object.defineProperty(window.SVGPathSegCurvetoQuadraticRel.prototype, "y1", { get: function() { return this._y1; }, set: function(y1) { this._y1 = y1; this._segmentChanged(); }, enumerable: true });
window.SVGPathSegArcAbs = function(owningPathSegList, x, y, r1, r2, angle, largeArcFlag, sweepFlag) {
window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_ARC_ABS, "A", owningPathSegList);
this._x = x;
this._y = y;
this._r1 = r1;
this._r2 = r2;
this._angle = angle;
this._largeArcFlag = largeArcFlag;
this._sweepFlag = sweepFlag;
}
window.SVGPathSegArcAbs.prototype = Object.create(window.SVGPathSeg.prototype);
window.SVGPathSegArcAbs.prototype.toString = function() { return "[object SVGPathSegArcAbs]"; }
window.SVGPathSegArcAbs.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._r1 + " " + this._r2 + " " + this._angle + " " + (this._largeArcFlag ? "1" : "0") + " " + (this._sweepFlag ? "1" : "0") + " " + this._x + " " + this._y; }
window.SVGPathSegArcAbs.prototype.clone = function() { return new window.SVGPathSegArcAbs(undefined, this._x, this._y, this._r1, this._r2, this._angle, this._largeArcFlag, this._sweepFlag); }
Object.defineProperty(window.SVGPathSegArcAbs.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true });
Object.defineProperty(window.SVGPathSegArcAbs.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true });
Object.defineProperty(window.SVGPathSegArcAbs.prototype, "r1", { get: function() { return this._r1; }, set: function(r1) { this._r1 = r1; this._segmentChanged(); }, enumerable: true });
Object.defineProperty(window.SVGPathSegArcAbs.prototype, "r2", { get: function() { return this._r2; }, set: function(r2) { this._r2 = r2; this._segmentChanged(); }, enumerable: true });
Object.defineProperty(window.SVGPathSegArcAbs.prototype, "angle", { get: function() { return this._angle; }, set: function(angle) { this._angle = angle; this._segmentChanged(); }, enumerable: true });
Object.defineProperty(window.SVGPathSegArcAbs.prototype, "largeArcFlag", { get: function() { return this._largeArcFlag; }, set: function(largeArcFlag) { this._largeArcFlag = largeArcFlag; this._segmentChanged(); }, enumerable: true });
Object.defineProperty(window.SVGPathSegArcAbs.prototype, "sweepFlag", { get: function() { return this._sweepFlag; }, set: function(sweepFlag) { this._sweepFlag = sweepFlag; this._segmentChanged(); }, enumerable: true });
window.SVGPathSegArcRel = function(owningPathSegList, x, y, r1, r2, angle, largeArcFlag, sweepFlag) {
window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_ARC_REL, "a", owningPathSegList);
this._x = x;
this._y = y;
this._r1 = r1;
this._r2 = r2;
this._angle = angle;
this._largeArcFlag = largeArcFlag;
this._sweepFlag = sweepFlag;
}
window.SVGPathSegArcRel.prototype = Object.create(window.SVGPathSeg.prototype);
window.SVGPathSegArcRel.prototype.toString = function() { return "[object SVGPathSegArcRel]"; }
window.SVGPathSegArcRel.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._r1 + " " + this._r2 + " " + this._angle + " " + (this._largeArcFlag ? "1" : "0") + " " + (this._sweepFlag ? "1" : "0") + " " + this._x + " " + this._y; }
window.SVGPathSegArcRel.prototype.clone = function() { return new window.SVGPathSegArcRel(undefined, this._x, this._y, this._r1, this._r2, this._angle, this._largeArcFlag, this._sweepFlag); }
Object.defineProperty(window.SVGPathSegArcRel.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true });
Object.defineProperty(window.SVGPathSegArcRel.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true });
Object.defineProperty(window.SVGPathSegArcRel.prototype, "r1", { get: function() { return this._r1; }, set: function(r1) { this._r1 = r1; this._segmentChanged(); }, enumerable: true });
Object.defineProperty(window.SVGPathSegArcRel.prototype, "r2", { get: function() { return this._r2; }, set: function(r2) { this._r2 = r2; this._segmentChanged(); }, enumerable: true });
Object.defineProperty(window.SVGPathSegArcRel.prototype, "angle", { get: function() { return this._angle; }, set: function(angle) { this._angle = angle; this._segmentChanged(); }, enumerable: true });
Object.defineProperty(window.SVGPathSegArcRel.prototype, "largeArcFlag", { get: function() { return this._largeArcFlag; }, set: function(largeArcFlag) { this._largeArcFlag = largeArcFlag; this._segmentChanged(); }, enumerable: true });
Object.defineProperty(window.SVGPathSegArcRel.prototype, "sweepFlag", { get: function() { return this._sweepFlag; }, set: function(sweepFlag) { this._sweepFlag = sweepFlag; this._segmentChanged(); }, enumerable: true });
window.SVGPathSegLinetoHorizontalAbs = function(owningPathSegList, x) {
window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_ABS, "H", owningPathSegList);
this._x = x;
}
window.SVGPathSegLinetoHorizontalAbs.prototype = Object.create(window.SVGPathSeg.prototype);
window.SVGPathSegLinetoHorizontalAbs.prototype.toString = function() { return "[object SVGPathSegLinetoHorizontalAbs]"; }
window.SVGPathSegLinetoHorizontalAbs.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._x; }
window.SVGPathSegLinetoHorizontalAbs.prototype.clone = function() { return new window.SVGPathSegLinetoHorizontalAbs(undefined, this._x); }
Object.defineProperty(window.SVGPathSegLinetoHorizontalAbs.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true });
window.SVGPathSegLinetoHorizontalRel = function(owningPathSegList, x) {
window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_REL, "h", owningPathSegList);
this._x = x;
}
window.SVGPathSegLinetoHorizontalRel.prototype = Object.create(window.SVGPathSeg.prototype);
window.SVGPathSegLinetoHorizontalRel.prototype.toString = function() { return "[object SVGPathSegLinetoHorizontalRel]"; }
window.SVGPathSegLinetoHorizontalRel.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._x; }
window.SVGPathSegLinetoHorizontalRel.prototype.clone = function() { return new window.SVGPathSegLinetoHorizontalRel(undefined, this._x); }
Object.defineProperty(window.SVGPathSegLinetoHorizontalRel.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true });
window.SVGPathSegLinetoVerticalAbs = function(owningPathSegList, y) {
window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_LINETO_VERTICAL_ABS, "V", owningPathSegList);
this._y = y;
}
window.SVGPathSegLinetoVerticalAbs.prototype = Object.create(window.SVGPathSeg.prototype);
window.SVGPathSegLinetoVerticalAbs.prototype.toString = function() { return "[object SVGPathSegLinetoVerticalAbs]"; }
window.SVGPathSegLinetoVerticalAbs.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._y; }
window.SVGPathSegLinetoVerticalAbs.prototype.clone = function() { return new window.SVGPathSegLinetoVerticalAbs(undefined, this._y); }
Object.defineProperty(window.SVGPathSegLinetoVerticalAbs.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true });
window.SVGPathSegLinetoVerticalRel = function(owningPathSegList, y) {
window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_LINETO_VERTICAL_REL, "v", owningPathSegList);
this._y = y;
}
window.SVGPathSegLinetoVerticalRel.prototype = Object.create(window.SVGPathSeg.prototype);
window.SVGPathSegLinetoVerticalRel.prototype.toString = function() { return "[object SVGPathSegLinetoVerticalRel]"; }
window.SVGPathSegLinetoVerticalRel.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._y; }
window.SVGPathSegLinetoVerticalRel.prototype.clone = function() { return new window.SVGPathSegLinetoVerticalRel(undefined, this._y); }
Object.defineProperty(window.SVGPathSegLinetoVerticalRel.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true });
window.SVGPathSegCurvetoCubicSmoothAbs = function(owningPathSegList, x, y, x2, y2) {
window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_ABS, "S", owningPathSegList);
this._x = x;
this._y = y;
this._x2 = x2;
this._y2 = y2;
}
window.SVGPathSegCurvetoCubicSmoothAbs.prototype = Object.create(window.SVGPathSeg.prototype);
window.SVGPathSegCurvetoCubicSmoothAbs.prototype.toString = function() { return "[object SVGPathSegCurvetoCubicSmoothAbs]"; }
window.SVGPathSegCurvetoCubicSmoothAbs.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._x2 + " " + this._y2 + " " + this._x + " " + this._y; }
window.SVGPathSegCurvetoCubicSmoothAbs.prototype.clone = function() { return new window.SVGPathSegCurvetoCubicSmoothAbs(undefined, this._x, this._y, this._x2, this._y2); }
Object.defineProperty(window.SVGPathSegCurvetoCubicSmoothAbs.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true });
Object.defineProperty(window.SVGPathSegCurvetoCubicSmoothAbs.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true });
Object.defineProperty(window.SVGPathSegCurvetoCubicSmoothAbs.prototype, "x2", { get: function() { return this._x2; }, set: function(x2) { this._x2 = x2; this._segmentChanged(); }, enumerable: true });
Object.defineProperty(window.SVGPathSegCurvetoCubicSmoothAbs.prototype, "y2", { get: function() { return this._y2; }, set: function(y2) { this._y2 = y2; this._segmentChanged(); }, enumerable: true });
window.SVGPathSegCurvetoCubicSmoothRel = function(owningPathSegList, x, y, x2, y2) {
window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_REL, "s", owningPathSegList);
this._x = x;
this._y = y;
this._x2 = x2;
this._y2 = y2;
}
window.SVGPathSegCurvetoCubicSmoothRel.prototype = Object.create(window.SVGPathSeg.prototype);
window.SVGPathSegCurvetoCubicSmoothRel.prototype.toString = function() { return "[object SVGPathSegCurvetoCubicSmoothRel]"; }
window.SVGPathSegCurvetoCubicSmoothRel.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._x2 + " " + this._y2 + " " + this._x + " " + this._y; }
window.SVGPathSegCurvetoCubicSmoothRel.prototype.clone = function() { return new window.SVGPathSegCurvetoCubicSmoothRel(undefined, this._x, this._y, this._x2, this._y2); }
Object.defineProperty(window.SVGPathSegCurvetoCubicSmoothRel.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true });
Object.defineProperty(window.SVGPathSegCurvetoCubicSmoothRel.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true });
Object.defineProperty(window.SVGPathSegCurvetoCubicSmoothRel.prototype, "x2", { get: function() { return this._x2; }, set: function(x2) { this._x2 = x2; this._segmentChanged(); }, enumerable: true });
Object.defineProperty(window.SVGPathSegCurvetoCubicSmoothRel.prototype, "y2", { get: function() { return this._y2; }, set: function(y2) { this._y2 = y2; this._segmentChanged(); }, enumerable: true });
window.SVGPathSegCurvetoQuadraticSmoothAbs = function(owningPathSegList, x, y) {
window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS, "T", owningPathSegList);
this._x = x;
this._y = y;
}
window.SVGPathSegCurvetoQuadraticSmoothAbs.prototype = Object.create(window.SVGPathSeg.prototype);
window.SVGPathSegCurvetoQuadraticSmoothAbs.prototype.toString = function() { return "[object SVGPathSegCurvetoQuadraticSmoothAbs]"; }
window.SVGPathSegCurvetoQuadraticSmoothAbs.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._x + " " + this._y; }
window.SVGPathSegCurvetoQuadraticSmoothAbs.prototype.clone = function() { return new window.SVGPathSegCurvetoQuadraticSmoothAbs(undefined, this._x, this._y); }
Object.defineProperty(window.SVGPathSegCurvetoQuadraticSmoothAbs.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true });
Object.defineProperty(window.SVGPathSegCurvetoQuadraticSmoothAbs.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true });
window.SVGPathSegCurvetoQuadraticSmoothRel = function(owningPathSegList, x, y) {
window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL, "t", owningPathSegList);
this._x = x;
this._y = y;
}
window.SVGPathSegCurvetoQuadraticSmoothRel.prototype = Object.create(window.SVGPathSeg.prototype);
window.SVGPathSegCurvetoQuadraticSmoothRel.prototype.toString = function() { return "[object SVGPathSegCurvetoQuadraticSmoothRel]"; }
window.SVGPathSegCurvetoQuadraticSmoothRel.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._x + " " + this._y; }
window.SVGPathSegCurvetoQuadraticSmoothRel.prototype.clone = function() { return new window.SVGPathSegCurvetoQuadraticSmoothRel(undefined, this._x, this._y); }
Object.defineProperty(window.SVGPathSegCurvetoQuadraticSmoothRel.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true });
Object.defineProperty(window.SVGPathSegCurvetoQuadraticSmoothRel.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true });
// Add createSVGPathSeg* functions to window.SVGPathElement.
// Spec: http://www.w3.org/TR/SVG11/single-page.html#paths-Interfacewindow.SVGPathElement.
window.SVGPathElement.prototype.createSVGPathSegClosePath = function() { return new window.SVGPathSegClosePath(undefined); }
window.SVGPathElement.prototype.createSVGPathSegMovetoAbs = function(x, y) { return new window.SVGPathSegMovetoAbs(undefined, x, y); }
window.SVGPathElement.prototype.createSVGPathSegMovetoRel = function(x, y) { return new window.SVGPathSegMovetoRel(undefined, x, y); }
window.SVGPathElement.prototype.createSVGPathSegLinetoAbs = function(x, y) { return new window.SVGPathSegLinetoAbs(undefined, x, y); }
window.SVGPathElement.prototype.createSVGPathSegLinetoRel = function(x, y) { return new window.SVGPathSegLinetoRel(undefined, x, y); }
window.SVGPathElement.prototype.createSVGPathSegCurvetoCubicAbs = function(x, y, x1, y1, x2, y2) { return new window.SVGPathSegCurvetoCubicAbs(undefined, x, y, x1, y1, x2, y2); }
window.SVGPathElement.prototype.createSVGPathSegCurvetoCubicRel = function(x, y, x1, y1, x2, y2) { return new window.SVGPathSegCurvetoCubicRel(undefined, x, y, x1, y1, x2, y2); }
window.SVGPathElement.prototype.createSVGPathSegCurvetoQuadraticAbs = function(x, y, x1, y1) { return new window.SVGPathSegCurvetoQuadraticAbs(undefined, x, y, x1, y1); }
window.SVGPathElement.prototype.createSVGPathSegCurvetoQuadraticRel = function(x, y, x1, y1) { return new window.SVGPathSegCurvetoQuadraticRel(undefined, x, y, x1, y1); }
window.SVGPathElement.prototype.createSVGPathSegArcAbs = function(x, y, r1, r2, angle, largeArcFlag, sweepFlag) { return new window.SVGPathSegArcAbs(undefined, x, y, r1, r2, angle, largeArcFlag, sweepFlag); }
window.SVGPathElement.prototype.createSVGPathSegArcRel = function(x, y, r1, r2, angle, largeArcFlag, sweepFlag) { return new window.SVGPathSegArcRel(undefined, x, y, r1, r2, angle, largeArcFlag, sweepFlag); }
window.SVGPathElement.prototype.createSVGPathSegLinetoHorizontalAbs = function(x) { return new window.SVGPathSegLinetoHorizontalAbs(undefined, x); }
window.SVGPathElement.prototype.createSVGPathSegLinetoHorizontalRel = function(x) { return new window.SVGPathSegLinetoHorizontalRel(undefined, x); }
window.SVGPathElement.prototype.createSVGPathSegLinetoVerticalAbs = function(y) { return new window.SVGPathSegLinetoVerticalAbs(undefined, y); }
window.SVGPathElement.prototype.createSVGPathSegLinetoVerticalRel = function(y) { return new window.SVGPathSegLinetoVerticalRel(undefined, y); }
window.SVGPathElement.prototype.createSVGPathSegCurvetoCubicSmoothAbs = function(x, y, x2, y2) { return new window.SVGPathSegCurvetoCubicSmoothAbs(undefined, x, y, x2, y2); }
window.SVGPathElement.prototype.createSVGPathSegCurvetoCubicSmoothRel = function(x, y, x2, y2) { return new window.SVGPathSegCurvetoCubicSmoothRel(undefined, x, y, x2, y2); }
window.SVGPathElement.prototype.createSVGPathSegCurvetoQuadraticSmoothAbs = function(x, y) { return new window.SVGPathSegCurvetoQuadraticSmoothAbs(undefined, x, y); }
window.SVGPathElement.prototype.createSVGPathSegCurvetoQuadraticSmoothRel = function(x, y) { return new window.SVGPathSegCurvetoQuadraticSmoothRel(undefined, x, y); }
if (!("getPathSegAtLength" in window.SVGPathElement.prototype)) {
// Add getPathSegAtLength to SVGPathElement.
// Spec: https://www.w3.org/TR/SVG11/single-page.html#paths-__svg__SVGPathElement__getPathSegAtLength
// This polyfill requires SVGPathElement.getTotalLength to implement the distance-along-a-path algorithm.
window.SVGPathElement.prototype.getPathSegAtLength = function(distance) {
if (distance === undefined || !isFinite(distance))
throw "Invalid arguments.";
var measurementElement = document.createElementNS("http://www.w3.org/2000/svg", "path");
measurementElement.setAttribute("d", this.getAttribute("d"));
var lastPathSegment = measurementElement.pathSegList.numberOfItems - 1;
// If the path is empty, return 0.
if (lastPathSegment <= 0)
return 0;
do {
measurementElement.pathSegList.removeItem(lastPathSegment);
if (distance > measurementElement.getTotalLength())
break;
lastPathSegment--;
} while (lastPathSegment > 0);
return lastPathSegment;
}
}
}
// Checking for SVGPathSegList in window checks for the case of an implementation without the
// SVGPathSegList API.
// The second check for appendItem is specific to Firefox 59+ which removed only parts of the
// SVGPathSegList API (e.g., appendItem). In this case we need to re-implement the entire API
// so the polyfill data (i.e., _list) is used throughout.
if (!("SVGPathSegList" in window) || !("appendItem" in window.SVGPathSegList.prototype)) {
// Spec: http://www.w3.org/TR/SVG11/single-page.html#paths-InterfaceSVGPathSegList
window.SVGPathSegList = function(pathElement) {
this._pathElement = pathElement;
this._list = this._parsePath(this._pathElement.getAttribute("d"));
// Use a MutationObserver to catch changes to the path's "d" attribute.
this._mutationObserverConfig = { "attributes": true, "attributeFilter": ["d"] };
this._pathElementMutationObserver = new MutationObserver(this._updateListFromPathMutations.bind(this));
this._pathElementMutationObserver.observe(this._pathElement, this._mutationObserverConfig);
}
window.SVGPathSegList.prototype.classname = "SVGPathSegList";
Object.defineProperty(window.SVGPathSegList.prototype, "numberOfItems", {
get: function() {
this._checkPathSynchronizedToList();
return this._list.length;
},
enumerable: true
});
// Add the pathSegList accessors to window.SVGPathElement.
// Spec: http://www.w3.org/TR/SVG11/single-page.html#paths-InterfaceSVGAnimatedPathData
Object.defineProperty(window.SVGPathElement.prototype, "pathSegList", {
get: function() {
if (!this._pathSegList)
this._pathSegList = new window.SVGPathSegList(this);
return this._pathSegList;
},
enumerable: true
});
// FIXME: The following are not implemented and simply return window.SVGPathElement.pathSegList.
Object.defineProperty(window.SVGPathElement.prototype, "normalizedPathSegList", { get: function() { return this.pathSegList; }, enumerable: true });
Object.defineProperty(window.SVGPathElement.prototype, "animatedPathSegList", { get: function() { return this.pathSegList; }, enumerable: true });
Object.defineProperty(window.SVGPathElement.prototype, "animatedNormalizedPathSegList", { get: function() { return this.pathSegList; }, enumerable: true });
// Process any pending mutations to the path element and update the list as needed.
// This should be the first call of all public functions and is needed because
// MutationObservers are not synchronous so we can have pending asynchronous mutations.
window.SVGPathSegList.prototype._checkPathSynchronizedToList = function() {
this._updateListFromPathMutations(this._pathElementMutationObserver.takeRecords());
}
window.SVGPathSegList.prototype._updateListFromPathMutations = function(mutationRecords) {
if (!this._pathElement)
return;
var hasPathMutations = false;
mutationRecords.forEach(function(record) {
if (record.attributeName == "d")
hasPathMutations = true;
});
if (hasPathMutations)
this._list = this._parsePath(this._pathElement.getAttribute("d"));
}
// Serialize the list and update the path's 'd' attribute.
window.SVGPathSegList.prototype._writeListToPath = function() {
this._pathElementMutationObserver.disconnect();
this._pathElement.setAttribute("d", window.SVGPathSegList._pathSegArrayAsString(this._list));
this._pathElementMutationObserver.observe(this._pathElement, this._mutationObserverConfig);
}
// When a path segment changes the list needs to be synchronized back to the path element.
window.SVGPathSegList.prototype.segmentChanged = function(pathSeg) {
this._writeListToPath();
}
window.SVGPathSegList.prototype.clear = function() {
this._checkPathSynchronizedToList();
this._list.forEach(function(pathSeg) {
pathSeg._owningPathSegList = null;
});
this._list = [];
this._writeListToPath();
}
window.SVGPathSegList.prototype.initialize = function(newItem) {
this._checkPathSynchronizedToList();
this._list = [newItem];
newItem._owningPathSegList = this;
this._writeListToPath();
return newItem;
}
window.SVGPathSegList.prototype._checkValidIndex = function(index) {
if (isNaN(index) || index < 0 || index >= this.numberOfItems)
throw "INDEX_SIZE_ERR";
}
window.SVGPathSegList.prototype.getItem = function(index) {
this._checkPathSynchronizedToList();
this._checkValidIndex(index);
return this._list[index];
}
window.SVGPathSegList.prototype.insertItemBefore = function(newItem, index) {
this._checkPathSynchronizedToList();
// Spec: If the index is greater than or equal to numberOfItems, then the new item is appended to the end of the list.
if (index > this.numberOfItems)
index = this.numberOfItems;
if (newItem._owningPathSegList) {
// SVG2 spec says to make a copy.
newItem = newItem.clone();
}
this._list.splice(index, 0, newItem);
newItem._owningPathSegList = this;
this._writeListToPath();
return newItem;
}
window.SVGPathSegList.prototype.replaceItem = function(newItem, index) {
this._checkPathSynchronizedToList();
if (newItem._owningPathSegList) {
// SVG2 spec says to make a copy.
newItem = newItem.clone();
}
this._checkValidIndex(index);
this._list[index] = newItem;
newItem._owningPathSegList = this;
this._writeListToPath();
return newItem;
}
window.SVGPathSegList.prototype.removeItem = function(index) {
this._checkPathSynchronizedToList();
this._checkValidIndex(index);
var item = this._list[index];
this._list.splice(index, 1);
this._writeListToPath();
return item;
}
window.SVGPathSegList.prototype.appendItem = function(newItem) {
this._checkPathSynchronizedToList();
if (newItem._owningPathSegList) {
// SVG2 spec says to make a copy.
newItem = newItem.clone();
}
this._list.push(newItem);
newItem._owningPathSegList = this;
// TODO: Optimize this to just append to the existing attribute.
this._writeListToPath();
return newItem;
}
window.SVGPathSegList._pathSegArrayAsString = function(pathSegArray) {
var string = "";
var first = true;
pathSegArray.forEach(function(pathSeg) {
if (first) {
first = false;
string += pathSeg._asPathString();
} else {
string += " " + pathSeg._asPathString();
}
});
return string;
}
// This closely follows SVGPathParser::parsePath from Source/core/svg/SVGPathParser.cpp.
window.SVGPathSegList.prototype._parsePath = function(string) {
if (!string || string.length == 0)
return [];
var owningPathSegList = this;
var Builder = function() {
this.pathSegList = [];
}
Builder.prototype.appendSegment = function(pathSeg) {
this.pathSegList.push(pathSeg);
}
var Source = function(string) {
this._string = string;
this._currentIndex = 0;
this._endIndex = this._string.length;
this._previousCommand = window.SVGPathSeg.PATHSEG_UNKNOWN;
this._skipOptionalSpaces();
}
Source.prototype._isCurrentSpace = function() {
var character = this._string[this._currentIndex];
return character <= " " && (character == " " || character == "\n" || character == "\t" || character == "\r" || character == "\f");
}
Source.prototype._skipOptionalSpaces = function() {
while (this._currentIndex < this._endIndex && this._isCurrentSpace())
this._currentIndex++;
return this._currentIndex < this._endIndex;
}
Source.prototype._skipOptionalSpacesOrDelimiter = function() {
if (this._currentIndex < this._endIndex && !this._isCurrentSpace() && this._string.charAt(this._currentIndex) != ",")
return false;
if (this._skipOptionalSpaces()) {
if (this._currentIndex < this._endIndex && this._string.charAt(this._currentIndex) == ",") {
this._currentIndex++;
this._skipOptionalSpaces();
}
}
return this._currentIndex < this._endIndex;
}
Source.prototype.hasMoreData = function() {
return this._currentIndex < this._endIndex;
}
Source.prototype.peekSegmentType = function() {
var lookahead = this._string[this._currentIndex];
return this._pathSegTypeFromChar(lookahead);
}
Source.prototype._pathSegTypeFromChar = function(lookahead) {
switch (lookahead) {
case "Z":
case "z":
return window.SVGPathSeg.PATHSEG_CLOSEPATH;
case "M":
return window.SVGPathSeg.PATHSEG_MOVETO_ABS;
case "m":
return window.SVGPathSeg.PATHSEG_MOVETO_REL;
case "L":
return window.SVGPathSeg.PATHSEG_LINETO_ABS;
case "l":
return window.SVGPathSeg.PATHSEG_LINETO_REL;
case "C":
return window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_ABS;
case "c":
return window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_REL;
case "Q":
return window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_ABS;
case "q":
return window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_REL;
case "A":
return window.SVGPathSeg.PATHSEG_ARC_ABS;
case "a":
return window.SVGPathSeg.PATHSEG_ARC_REL;
case "H":
return window.SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_ABS;
case "h":
return window.SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_REL;
case "V":
return window.SVGPathSeg.PATHSEG_LINETO_VERTICAL_ABS;
case "v":
return window.SVGPathSeg.PATHSEG_LINETO_VERTICAL_REL;
case "S":
return window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_ABS;
case "s":
return window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_REL;
case "T":
return window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS;
case "t":
return window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL;
default:
return window.SVGPathSeg.PATHSEG_UNKNOWN;
}
}
Source.prototype._nextCommandHelper = function(lookahead, previousCommand) {
// Check for remaining coordinates in the current command.
if ((lookahead == "+" || lookahead == "-" || lookahead == "." || (lookahead >= "0" && lookahead <= "9")) && previousCommand != window.SVGPathSeg.PATHSEG_CLOSEPATH) {
if (previousCommand == window.SVGPathSeg.PATHSEG_MOVETO_ABS)
return window.SVGPathSeg.PATHSEG_LINETO_ABS;
if (previousCommand == window.SVGPathSeg.PATHSEG_MOVETO_REL)
return window.SVGPathSeg.PATHSEG_LINETO_REL;
return previousCommand;
}
return window.SVGPathSeg.PATHSEG_UNKNOWN;
}
Source.prototype.initialCommandIsMoveTo = function() {
// If the path is empty it is still valid, so return true.
if (!this.hasMoreData())
return true;
var command = this.peekSegmentType();
// Path must start with moveTo.
return command == window.SVGPathSeg.PATHSEG_MOVETO_ABS || command == window.SVGPathSeg.PATHSEG_MOVETO_REL;
}
// Parse a number from an SVG path. This very closely follows genericParseNumber(...) from Source/core/svg/SVGParserUtilities.cpp.
// Spec: http://www.w3.org/TR/SVG11/single-page.html#paths-PathDataBNF
Source.prototype._parseNumber = function() {
var exponent = 0;
var integer = 0;
var frac = 1;
var decimal = 0;
var sign = 1;
var expsign = 1;
var startIndex = this._currentIndex;
this._skipOptionalSpaces();
// Read the sign.
if (this._currentIndex < this._endIndex && this._string.charAt(this._currentIndex) == "+")
this._currentIndex++;
else if (this._currentIndex < this._endIndex && this._string.charAt(this._currentIndex) == "-") {
this._currentIndex++;
sign = -1;
}
if (this._currentIndex == this._endIndex || ((this._string.charAt(this._currentIndex) < "0" || this._string.charAt(this._currentIndex) > "9") && this._string.charAt(this._currentIndex) != "."))
// The first character of a number must be one of [0-9+-.].
return undefined;
// Read the integer part, build right-to-left.
var startIntPartIndex = this._currentIndex;
while (this._currentIndex < this._endIndex && this._string.charAt(this._currentIndex) >= "0" && this._string.charAt(this._currentIndex) <= "9")
this._currentIndex++; // Advance to first non-digit.
if (this._currentIndex != startIntPartIndex) {
var scanIntPartIndex = this._currentIndex - 1;
var multiplier = 1;
while (scanIntPartIndex >= startIntPartIndex) {
integer += multiplier * (this._string.charAt(scanIntPartIndex--) - "0");
multiplier *= 10;
}
}
// Read the decimals.
if (this._currentIndex < this._endIndex && this._string.charAt(this._currentIndex) == ".") {
this._currentIndex++;
// There must be a least one digit following the .
if (this._currentIndex >= this._endIndex || this._string.charAt(this._currentIndex) < "0" || this._string.charAt(this._currentIndex) > "9")
return undefined;
while (this._currentIndex < this._endIndex && this._string.charAt(this._currentIndex) >= "0" && this._string.charAt(this._currentIndex) <= "9") {
frac *= 10;
decimal += (this._string.charAt(this._currentIndex) - "0") / frac;
this._currentIndex += 1;
}
}
// Read the exponent part.
if (this._currentIndex != startIndex && this._currentIndex + 1 < this._endIndex && (this._string.charAt(this._currentIndex) == "e" || this._string.charAt(this._currentIndex) == "E") && (this._string.charAt(this._currentIndex + 1) != "x" && this._string.charAt(this._currentIndex + 1) != "m")) {
this._currentIndex++;
// Read the sign of the exponent.
if (this._string.charAt(this._currentIndex) == "+") {
this._currentIndex++;
} else if (this._string.charAt(this._currentIndex) == "-") {
this._currentIndex++;
expsign = -1;
}
// There must be an exponent.
if (this._currentIndex >= this._endIndex || this._string.charAt(this._currentIndex) < "0" || this._string.charAt(this._currentIndex) > "9")
return undefined;
while (this._currentIndex < this._endIndex && this._string.charAt(this._currentIndex) >= "0" && this._string.charAt(this._currentIndex) <= "9") {
exponent *= 10;
exponent += (this._string.charAt(this._currentIndex) - "0");
this._currentIndex++;
}
}
var number = integer + decimal;
number *= sign;
if (exponent)
number *= Math.pow(10, expsign * exponent);
if (startIndex == this._currentIndex)
return undefined;
this._skipOptionalSpacesOrDelimiter();
return number;
}
Source.prototype._parseArcFlag = function() {
if (this._currentIndex >= this._endIndex)
return undefined;
var flag = false;
var flagChar = this._string.charAt(this._currentIndex++);
if (flagChar == "0")
flag = false;
else if (flagChar == "1")
flag = true;
else
return undefined;
this._skipOptionalSpacesOrDelimiter();
return flag;
}
Source.prototype.parseSegment = function() {
var lookahead = this._string[this._currentIndex];
var command = this._pathSegTypeFromChar(lookahead);
if (command == window.SVGPathSeg.PATHSEG_UNKNOWN) {
// Possibly an implicit command. Not allowed if this is the first command.
if (this._previousCommand == window.SVGPathSeg.PATHSEG_UNKNOWN)
return null;
command = this._nextCommandHelper(lookahead, this._previousCommand);
if (command == window.SVGPathSeg.PATHSEG_UNKNOWN)
return null;
} else {
this._currentIndex++;
}
this._previousCommand = command;
switch (command) {
case window.SVGPathSeg.PATHSEG_MOVETO_REL:
return new window.SVGPathSegMovetoRel(owningPathSegList, this._parseNumber(), this._parseNumber());
case window.SVGPathSeg.PATHSEG_MOVETO_ABS:
return new window.SVGPathSegMovetoAbs(owningPathSegList, this._parseNumber(), this._parseNumber());
case window.SVGPathSeg.PATHSEG_LINETO_REL:
return new window.SVGPathSegLinetoRel(owningPathSegList, this._parseNumber(), this._parseNumber());
case window.SVGPathSeg.PATHSEG_LINETO_ABS:
return new window.SVGPathSegLinetoAbs(owningPathSegList, this._parseNumber(), this._parseNumber());
case window.SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_REL:
return new window.SVGPathSegLinetoHorizontalRel(owningPathSegList, this._parseNumber());
case window.SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_ABS:
return new window.SVGPathSegLinetoHorizontalAbs(owningPathSegList, this._parseNumber());
case window.SVGPathSeg.PATHSEG_LINETO_VERTICAL_REL:
return new window.SVGPathSegLinetoVerticalRel(owningPathSegList, this._parseNumber());
case window.SVGPathSeg.PATHSEG_LINETO_VERTICAL_ABS:
return new window.SVGPathSegLinetoVerticalAbs(owningPathSegList, this._parseNumber());
case window.SVGPathSeg.PATHSEG_CLOSEPATH:
this._skipOptionalSpaces();
return new window.SVGPathSegClosePath(owningPathSegList);
case window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_REL:
var points = {x1: this._parseNumber(), y1: this._parseNumber(), x2: this._parseNumber(), y2: this._parseNumber(), x: this._parseNumber(), y: this._parseNumber()};
return new window.SVGPathSegCurvetoCubicRel(owningPathSegList, points.x, points.y, points.x1, points.y1, points.x2, points.y2);
case window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_ABS:
var points = {x1: this._parseNumber(), y1: this._parseNumber(), x2: this._parseNumber(), y2: this._parseNumber(), x: this._parseNumber(), y: this._parseNumber()};
return new window.SVGPathSegCurvetoCubicAbs(owningPathSegList, points.x, points.y, points.x1, points.y1, points.x2, points.y2);
case window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_REL:
var points = {x2: this._parseNumber(), y2: this._parseNumber(), x: this._parseNumber(), y: this._parseNumber()};
return new window.SVGPathSegCurvetoCubicSmoothRel(owningPathSegList, points.x, points.y, points.x2, points.y2);
case window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_ABS:
var points = {x2: this._parseNumber(), y2: this._parseNumber(), x: this._parseNumber(), y: this._parseNumber()};
return new window.SVGPathSegCurvetoCubicSmoothAbs(owningPathSegList, points.x, points.y, points.x2, points.y2);
case window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_REL:
var points = {x1: this._parseNumber(), y1: this._parseNumber(), x: this._parseNumber(), y: this._parseNumber()};
return new window.SVGPathSegCurvetoQuadraticRel(owningPathSegList, points.x, points.y, points.x1, points.y1);
case window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_ABS:
var points = {x1: this._parseNumber(), y1: this._parseNumber(), x: this._parseNumber(), y: this._parseNumber()};
return new window.SVGPathSegCurvetoQuadraticAbs(owningPathSegList, points.x, points.y, points.x1, points.y1);
case window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL:
return new window.SVGPathSegCurvetoQuadraticSmoothRel(owningPathSegList, this._parseNumber(), this._parseNumber());
case window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS:
return new window.SVGPathSegCurvetoQuadraticSmoothAbs(owningPathSegList, this._parseNumber(), this._parseNumber());
case window.SVGPathSeg.PATHSEG_ARC_REL:
var points = {x1: this._parseNumber(), y1: this._parseNumber(), arcAngle: this._parseNumber(), arcLarge: this._parseArcFlag(), arcSweep: this._parseArcFlag(), x: this._parseNumber(), y: this._parseNumber()};
return new window.SVGPathSegArcRel(owningPathSegList, points.x, points.y, points.x1, points.y1, points.arcAngle, points.arcLarge, points.arcSweep);
case window.SVGPathSeg.PATHSEG_ARC_ABS:
var points = {x1: this._parseNumber(), y1: this._parseNumber(), arcAngle: this._parseNumber(), arcLarge: this._parseArcFlag(), arcSweep: this._parseArcFlag(), x: this._parseNumber(), y: this._parseNumber()};
return new window.SVGPathSegArcAbs(owningPathSegList, points.x, points.y, points.x1, points.y1, points.arcAngle, points.arcLarge, points.arcSweep);
default:
throw "Unknown path seg type."
}
}
var builder = new Builder();
var source = new Source(string);
if (!source.initialCommandIsMoveTo())
return [];
while (source.hasMoreData()) {
var pathSeg = source.parseSegment();
if (!pathSeg)
return [];
builder.appendSegment(pathSeg);
}
return builder.pathSegList;
}
}
}());

173
demo/src/Compare.js Normal file
View file

@ -0,0 +1,173 @@
/**
* A Matter.js version comparison testbed based on MatterTools.
*
* Tool to interactively compare engine results of
* development version against the previous release.
*
* USAGE: [host]?compare[=frames]#[example]
* e.g. http://localhost:8000/?compare=120#mixed
*
* @module Compare
*/
var MatterTools = require('matter-tools');
var MatterDev = require('MatterDev');
var MatterBuild = require('MatterBuild');
var compare = function(examples, isDev) {
// create primary demo for dev build
var demo = MatterTools.Demo.create({
toolbar: {
title: 'matter-js ・ ' + (isDev ? 'dev' : '') + ' ・ comparing to ' + MatterBuild.version,
url: 'https://github.com/liabru/matter-js',
reset: true,
source: true,
inspector: false,
tools: false,
fullscreen: true,
exampleSelect: true
},
// tools disabled to keep sync between instances
tools: {
inspector: false,
gui: false
},
inline: false,
preventZoom: true,
resetOnOrientation: true,
routing: true,
startExample: false,
examples: examples
});
// create secondary demo for release build
var demoBuild = MatterTools.Demo.create({
toolbar: {
title: 'matter-js-compare-build',
reset: false,
source: false,
inspector: false,
tools: false,
fullscreen: false,
exampleSelect: false
},
// tools disabled to keep sync between instances
tools: {
inspector: false,
gui: false
},
inline: false,
preventZoom: true,
resetOnOrientation: true,
routing: false,
startExample: false,
examples: examples.map(function(example) {
return Matter.Common.extend({}, example);
})
});
/**
* NOTE: For the actual example code, refer to the source files in `/examples/`.
* The code below is tooling for Matter.js maintainers to compare versions of Matter.
*/
// build version should not run itself
MatterBuild.Runner.run = function() {};
MatterBuild.Render.run = function() {};
// maintain original references to patched methods
MatterDev.Runner._tick = MatterDev.Runner.tick;
MatterDev.Render._world = MatterDev.Render.world;
MatterBuild.Mouse._setElement = MatterBuild.Mouse.setElement;
// patch MatterTools to control both demo versions simultaneously
MatterTools.Demo._setExample = MatterTools.Demo.setExample;
MatterTools.Demo.setExample = function(_demo, example) {
MatterBuild.Common._nextId = MatterBuild.Common._seed = 0;
MatterDev.Common._nextId = MatterDev.Common._seed = 0;
MatterBuild.Plugin._registry = MatterDev.Plugin._registry;
MatterBuild.use.apply(null, MatterDev.used);
window.Matter = MatterDev;
MatterTools.Demo._setExample(
demo, demo.examples.find(function(e) { return e.name === example.name; })
);
var maxTicks = parseFloat(window.location.search.split('=')[1]);
var ticks = 0;
MatterDev.Runner.tick = function(runner, engine, time) {
if (ticks === -1) {
return;
}
if (ticks >= maxTicks) {
console.info(
'Demo.Compare: ran ' + ticks + ' ticks, timestamp is now '
+ engine.timing.timestamp.toFixed(2)
);
ticks = -1;
return;
}
ticks += 1;
var demoBuildInstance = demoBuild.example.instance;
runner.isFixed = demoBuildInstance.runner.isFixed = true;
runner.delta = demoBuildInstance.runner.delta = 1000 / 60;
window.Matter = MatterBuild;
MatterBuild.Runner.tick(demoBuildInstance.runner, demoBuildInstance.engine, time);
window.Matter = MatterDev;
return MatterDev.Runner._tick(runner, engine, time);
};
MatterDev.Render.world = function(render) {
window.Matter = MatterBuild;
MatterBuild.Render.world(demoBuild.example.instance.render);
window.Matter = MatterDev;
return MatterDev.Render._world(render);
};
MatterBuild.Mouse.setElement = function(mouse) {
return MatterBuild.Mouse._setElement(mouse, demo.example.instance.render.canvas);
};
window.Matter = MatterBuild;
MatterTools.Demo._setExample(
demoBuild, demoBuild.examples.find(function(e) { return e.name === example.name; })
);
window.Matter = MatterDev;
};
// reset both engine versions simultaneously
MatterTools.Demo._reset = MatterTools.Demo.reset;
MatterTools.Demo.reset = function(_demo) {
MatterBuild.Common._nextId = MatterBuild.Common._seed = 0;
MatterDev.Common._nextId = MatterDev.Common._seed = 0;
window.Matter = MatterBuild;
MatterTools.Demo._reset(demoBuild);
window.Matter = MatterDev;
MatterTools.Demo._reset(demo);
};
document.body.appendChild(demo.dom.root);
document.body.appendChild(demoBuild.dom.root);
MatterTools.Demo.start(demo);
document.title = 'Matter.js Compare' + (isDev ? ' ・ Dev' : '');
console.info(
'Demo.Compare: matter-js@' + MatterDev.version +
' with matter-js@' + MatterBuild.version
);
};
module.exports = { compare: compare };

65
demo/src/Demo.js Normal file
View file

@ -0,0 +1,65 @@
/**
* A Matter.js demo and development testbed based on MatterTools.
*
* For a simpler, minimal Matter.js example see:
* https://github.com/liabru/matter-js/wiki/Getting-started
*
* The source for examples can be found at `/examples/`.
*
* @module Demo
*/
var MatterTools = require('matter-tools');
var demo = function(examples, isDev) {
var demo = MatterTools.Demo.create({
toolbar: {
title: 'matter-js' + (isDev ? ' ・ dev' : ''),
url: 'https://github.com/liabru/matter-js',
reset: true,
source: true,
inspector: true,
tools: true,
fullscreen: true,
exampleSelect: true
},
tools: {
inspector: true,
gui: true
},
inline: false,
preventZoom: true,
resetOnOrientation: true,
routing: true,
startExample: 'mixed',
examples: examples
});
window.MatterDemoInstance = demo;
document.body.appendChild(demo.dom.root);
document.title = 'Matter.js Demo' + (isDev ? ' ・ Dev' : '');
if (isDev) {
var buttonSource = demo.dom.buttonSource;
var buttonCompare = buttonSource.cloneNode(true);
buttonCompare.textContent = '⎄';
buttonCompare.title = 'Compare';
buttonCompare.href = '?compare';
buttonCompare.target = '';
buttonCompare.className = 'matter-btn matter-btn-compare';
buttonCompare.addEventListener('click', function(event) {
window.location = '?compare#' + demo.example.id;
event.preventDefault();
});
buttonSource.parentNode.insertBefore(buttonCompare, buttonSource.nextSibling);
Matter.before('Render.create', function(renderOptions) {
renderOptions.options.showDebug = true;
});
}
MatterTools.Demo.start(demo);
};
module.exports = { demo: demo };

55
demo/src/index.ejs Normal file
View file

@ -0,0 +1,55 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no,minimal-ui">
<meta name="theme-color" content="#000000">
<meta name="msapplication-navbutton-color" content="#000000">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="robots" content="noindex">
<title>Matter.js Demo</title>
<style type="text/css">
* {
box-sizing: border-box;
}
body {
margin: 0;
padding: 0;
}
.matter-btn-compare.matter-btn {
font-size: 18px;
text-align: center;
line-height: 32px;
}
.matter-js-compare-build.matter-demo {
position: absolute;
background: none;
top: 0;
left: 0;
width: 100%;
height: 100%;
border: 0;
z-index: 1;
pointer-events: none;
}
.matter-js-compare-build.matter-demo .matter-header-outer {
display: none;
}
.matter-js-compare-build.matter-demo canvas {
opacity: 0.5;
background: transparent !important;
}
</style>
</head>
<body><% for (var chunk in htmlWebpackPlugin.files.js) { %>
<script src="<%= htmlWebpackPlugin.files.js[chunk] %>"></script><% } %>
</body>
</html>

39
demo/src/index.js Normal file
View file

@ -0,0 +1,39 @@
/**
* Initialise and start the browser demo / compare tool.
*
* For a simpler, minimal Matter.js example see:
* https://github.com/liabru/matter-js/wiki/Getting-started
*
* The source for examples can be found at `/examples/`.
*
* @module Index
*/
var Matter = require('matter-js');
var Examples = require('../../examples/index');
var compare = require('./Compare').compare;
var demo = require('./Demo').demo;
// browser globals
window.pathseg = require('pathseg');
window.MatterTools = require('matter-tools');
window.Matter = Matter;
// prepare examples
var examples = Matter.Common.keys(Examples).map(function(id){
return {
id: id,
sourceLink: 'https://github.com/liabru/matter-js/blob/master/examples/' + id + '.js',
name: Examples[id].title,
init: Examples[id]
};
});
// start the requested tool
var isCompare = window.location.search.indexOf('compare') >= 0;
var isDev = __MATTER_IS_DEV__;
if (isCompare) {
compare(examples, isDev);
} else {
demo(examples, isDev);
}

View file

@ -6,7 +6,7 @@ Example.airFriction = function() {
Runner = Matter.Runner,
MouseConstraint = Matter.MouseConstraint,
Mouse = Matter.Mouse,
World = Matter.World,
Composite = Matter.Composite,
Bodies = Matter.Bodies;
// create engine
@ -31,7 +31,7 @@ Example.airFriction = function() {
Runner.run(runner, engine);
// add bodies
World.add(world, [
Composite.add(world, [
// falling blocks
Bodies.rectangle(200, 100, 60, 60, { frictionAir: 0.001 }),
Bodies.rectangle(400, 100, 60, 60, { frictionAir: 0.05 }),
@ -56,7 +56,7 @@ Example.airFriction = function() {
}
});
World.add(world, mouseConstraint);
Composite.add(world, mouseConstraint);
// keep the mouse in sync with rendering
render.mouse = mouse;
@ -80,6 +80,7 @@ Example.airFriction = function() {
};
};
Example.airFriction.title = 'Air Friction';
Example.airFriction.for = '>=0.14.2';
if (typeof module !== 'undefined') {

View file

@ -1,9 +1,17 @@
var Example = Example || {};
Example.avalanche = function() {
Matter.use(
'matter-wrap'
);
try {
if (typeof MatterWrap !== 'undefined') {
// either use by name from plugin registry (Browser global)
Matter.use('matter-wrap');
} else {
// or require and use the plugin directly (Node.js, Webpack etc.)
Matter.use(require('matter-wrap'));
}
} catch (e) {
// could not require the plugin or install needed
}
var Engine = Matter.Engine,
Render = Matter.Render,
@ -13,7 +21,6 @@ Example.avalanche = function() {
Common = Matter.Common,
MouseConstraint = Matter.MouseConstraint,
Mouse = Matter.Mouse,
World = Matter.World,
Bodies = Matter.Bodies;
// create engine
@ -42,9 +49,9 @@ Example.avalanche = function() {
return Bodies.circle(x, y, Common.random(10, 20), { friction: 0.00001, restitution: 0.5, density: 0.001 });
});
World.add(world, stack);
Composite.add(world, stack);
World.add(world, [
Composite.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' } })
@ -62,7 +69,7 @@ Example.avalanche = function() {
}
});
World.add(world, mouseConstraint);
Composite.add(world, mouseConstraint);
// keep the mouse in sync with rendering
render.mouse = mouse;
@ -91,6 +98,7 @@ Example.avalanche = function() {
};
};
Example.avalanche.title = 'Avalanche';
Example.avalanche.for = '>=0.14.2';
if (typeof module !== 'undefined') {

View file

@ -1,9 +1,17 @@
var Example = Example || {};
Example.ballPool = function() {
Matter.use(
'matter-wrap'
);
try {
if (typeof MatterWrap !== 'undefined') {
// either use by name from plugin registry (Browser global)
Matter.use('matter-wrap');
} else {
// or require and use the plugin directly (Node.js, Webpack etc.)
Matter.use(require('matter-wrap'));
}
} catch (e) {
// could not require the plugin or install needed
}
var Engine = Matter.Engine,
Render = Matter.Render,
@ -13,7 +21,6 @@ Example.ballPool = function() {
Common = Matter.Common,
MouseConstraint = Matter.MouseConstraint,
Mouse = Matter.Mouse,
World = Matter.World,
Bodies = Matter.Bodies;
// create engine
@ -38,7 +45,7 @@ Example.ballPool = function() {
Runner.run(runner, engine);
// add bodies
World.add(world, [
Composite.add(world, [
Bodies.rectangle(400, 600, 1200, 50.5, { isStatic: true, render: { fillStyle: '#060a19' } })
]);
@ -46,7 +53,7 @@ Example.ballPool = function() {
return Bodies.circle(x, y, Common.random(15, 30), { restitution: 0.6, friction: 0.1 });
});
World.add(world, [
Composite.add(world, [
stack,
Bodies.polygon(200, 460, 3, 60),
Bodies.polygon(400, 460, 5, 60),
@ -65,7 +72,7 @@ Example.ballPool = function() {
}
});
World.add(world, mouseConstraint);
Composite.add(world, mouseConstraint);
// keep the mouse in sync with rendering
render.mouse = mouse;
@ -99,6 +106,7 @@ Example.ballPool = function() {
};
};
Example.ballPool.title = 'Ball Pool';
Example.ballPool.for = '>=0.14.2';
if (typeof module !== 'undefined') {

View file

@ -10,7 +10,7 @@ Example.bridge = function() {
Constraint = Matter.Constraint,
MouseConstraint = Matter.MouseConstraint,
Mouse = Matter.Mouse,
World = Matter.World,
Composite = Matter.Composite,
Bodies = Matter.Bodies;
// create engine
@ -61,7 +61,7 @@ Example.bridge = function() {
return Bodies.rectangle(x, y, 50, 50, Common.random(20, 40));
});
World.add(world, [
Composite.add(world, [
bridge,
stack,
Bodies.rectangle(30, 490, 220, 380, {
@ -100,7 +100,7 @@ Example.bridge = function() {
}
});
World.add(world, mouseConstraint);
Composite.add(world, mouseConstraint);
// keep the mouse in sync with rendering
render.mouse = mouse;
@ -124,6 +124,7 @@ Example.bridge = function() {
};
};
Example.bridge.title = 'Bridge';
Example.bridge.for = '>=0.14.2';
if (typeof module !== 'undefined') {

View file

@ -7,7 +7,7 @@ Example.car = function() {
Composites = Matter.Composites,
MouseConstraint = Matter.MouseConstraint,
Mouse = Matter.Mouse,
World = Matter.World,
Composite = Matter.Composite,
Bodies = Matter.Bodies;
// create engine
@ -33,7 +33,7 @@ Example.car = function() {
Runner.run(runner, engine);
// add bodies
World.add(world, [
Composite.add(world, [
// walls
Bodies.rectangle(400, 0, 800, 50, { isStatic: true }),
Bodies.rectangle(400, 600, 800, 50, { isStatic: true }),
@ -41,13 +41,14 @@ Example.car = function() {
Bodies.rectangle(0, 300, 50, 600, { isStatic: true })
]);
// see car function defined later in this file
var scale = 0.9;
World.add(world, Composites.car(150, 80, 150 * scale, 30 * scale, 30 * scale));
Composite.add(world, Example.car.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));
Composite.add(world, Example.car.car(350, 300, 150 * scale, 30 * scale, 30 * scale));
World.add(world, [
Composite.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' }})
@ -65,7 +66,7 @@ Example.car = function() {
}
});
World.add(world, mouseConstraint);
Composite.add(world, mouseConstraint);
// keep the mouse in sync with rendering
render.mouse = mouse;
@ -89,8 +90,81 @@ Example.car = function() {
};
};
Example.car.title = 'Car';
Example.car.for = '>=0.14.2';
/**
* 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
*/
Example.car.car = function(xx, yy, width, height, wheelSize) {
var Body = Matter.Body,
Bodies = Matter.Bodies,
Composite = Matter.Composite,
Constraint = Matter.Constraint;
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;
};
if (typeof module !== 'undefined') {
module.exports = Example.car;
}

View file

@ -8,7 +8,7 @@ Example.catapult = function() {
Constraint = Matter.Constraint,
MouseConstraint = Matter.MouseConstraint,
Mouse = Matter.Mouse,
World = Matter.World,
Composite = Matter.Composite,
Bodies = Matter.Bodies,
Body = Matter.Body,
Vector = Matter.Vector;
@ -45,7 +45,7 @@ Example.catapult = function() {
var catapult = Bodies.rectangle(400, 520, 320, 20, { collisionFilter: { group: group } });
World.add(world, [
Composite.add(world, [
stack,
catapult,
Bodies.rectangle(400, 600, 800, 50.5, { isStatic: true, render: { fillStyle: '#060a19' } }),
@ -72,7 +72,7 @@ Example.catapult = function() {
}
});
World.add(world, mouseConstraint);
Composite.add(world, mouseConstraint);
// keep the mouse in sync with rendering
render.mouse = mouse;
@ -96,6 +96,7 @@ Example.catapult = function() {
};
};
Example.catapult.title = 'Catapult';
Example.catapult.for = '>=0.14.2';
if (typeof module !== 'undefined') {

View file

@ -10,7 +10,6 @@ Example.chains = function() {
Constraint = Matter.Constraint,
MouseConstraint = Matter.MouseConstraint,
Mouse = Matter.Mouse,
World = Matter.World,
Bodies = Matter.Bodies;
// create engine
@ -79,7 +78,7 @@ Example.chains = function() {
stiffness: 0.5
}));
World.add(world, [
Composite.add(world, [
ropeA,
ropeB,
ropeC,
@ -98,7 +97,7 @@ Example.chains = function() {
}
});
World.add(world, mouseConstraint);
Composite.add(world, mouseConstraint);
// keep the mouse in sync with rendering
render.mouse = mouse;
@ -122,6 +121,7 @@ Example.chains = function() {
};
};
Example.chains.title = 'Chains';
Example.chains.for = '>=0.14.2';
if (typeof module !== 'undefined') {

View file

@ -7,7 +7,7 @@ Example.circleStack = function() {
Composites = Matter.Composites,
MouseConstraint = Matter.MouseConstraint,
Mouse = Matter.Mouse,
World = Matter.World,
Composite = Matter.Composite,
Bodies = Matter.Bodies;
// create engine
@ -32,11 +32,11 @@ Example.circleStack = function() {
Runner.run(runner, engine);
// add bodies
var stack = Composites.stack(100, 185, 10, 10, 20, 0, function(x, y) {
var stack = Composites.stack(100, 600 - 21 - 20 * 20, 10, 10, 20, 0, function(x, y) {
return Bodies.circle(x, y, 20);
});
World.add(world, [
Composite.add(world, [
// walls
Bodies.rectangle(400, 0, 800, 50, { isStatic: true }),
Bodies.rectangle(400, 600, 800, 50, { isStatic: true }),
@ -57,7 +57,7 @@ Example.circleStack = function() {
}
});
World.add(world, mouseConstraint);
Composite.add(world, mouseConstraint);
// keep the mouse in sync with rendering
render.mouse = mouse;
@ -81,6 +81,7 @@ Example.circleStack = function() {
};
};
Example.circleStack.title = 'Circle Stack';
Example.circleStack.for = '>=0.14.2';
if (typeof module !== 'undefined') {

View file

@ -8,7 +8,7 @@ Example.cloth = function() {
Composites = Matter.Composites,
MouseConstraint = Matter.MouseConstraint,
Mouse = Matter.Mouse,
World = Matter.World,
Composite = Matter.Composite,
Bodies = Matter.Bodies;
// create engine
@ -31,17 +31,14 @@ Example.cloth = function() {
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);
// see cloth function defined later in this file
var cloth = Example.cloth.cloth(200, 200, 20, 12, 5, 5, false, 8);
for (var i = 0; i < 20; i++) {
cloth.bodies[i].isStatic = true;
}
World.add(world, [
Composite.add(world, [
cloth,
Bodies.circle(300, 500, 80, { isStatic: true, render: { fillStyle: '#060a19' }}),
Bodies.rectangle(500, 480, 80, 80, { isStatic: true, render: { fillStyle: '#060a19' }}),
@ -60,7 +57,7 @@ Example.cloth = function() {
}
});
World.add(world, mouseConstraint);
Composite.add(world, mouseConstraint);
// keep the mouse in sync with rendering
render.mouse = mouse;
@ -84,8 +81,45 @@ Example.cloth = function() {
};
};
Example.cloth.title = 'Cloth';
Example.cloth.for = '>=0.14.2';
/**
* Creates a simple cloth like object.
* @method cloth
* @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 cloth
*/
Example.cloth.cloth = function(xx, yy, columns, rows, columnGap, rowGap, crossBrace, particleRadius, particleOptions, constraintOptions) {
var Body = Matter.Body,
Bodies = Matter.Bodies,
Common = Matter.Common,
Composites = Matter.Composites;
var group = Body.nextGroup(true);
particleOptions = Common.extend({ inertia: Infinity, friction: 0.00001, collisionFilter: { group: group }, render: { visible: false }}, particleOptions);
constraintOptions = Common.extend({ stiffness: 0.06, render: { type: 'line', anchors: false } }, constraintOptions);
var cloth = Composites.stack(xx, yy, columns, rows, columnGap, rowGap, function(x, y) {
return Bodies.circle(x, y, particleRadius, particleOptions);
});
Composites.mesh(cloth, columns, rows, crossBrace, constraintOptions);
cloth.label = 'Cloth Body';
return cloth;
};
if (typeof module !== 'undefined') {
module.exports = Example.cloth;
}

View file

@ -9,7 +9,6 @@ Example.collisionFiltering = function() {
Common = Matter.Common,
MouseConstraint = Matter.MouseConstraint,
Mouse = Matter.Mouse,
World = Matter.World,
Bodies = Matter.Bodies;
// create engine
@ -44,7 +43,7 @@ Example.collisionFiltering = function() {
colorC = '#f5d259';
// add floor
World.add(world, Bodies.rectangle(400, 600, 900, 50, {
Composite.add(world, Bodies.rectangle(400, 600, 900, 50, {
isStatic: true,
render: {
fillStyle: 'transparent',
@ -53,7 +52,7 @@ Example.collisionFiltering = function() {
}));
// create a stack with varying body categories (but these bodies can all collide with each other)
World.add(world,
Composite.add(world,
Composites.stack(275, 100, 5, 9, 10, 10, function(x, y, column, row) {
var category = redCategory,
color = colorA;
@ -80,7 +79,7 @@ Example.collisionFiltering = function() {
);
// this body will only collide with the walls and the green bodies
World.add(world,
Composite.add(world,
Bodies.circle(310, 40, 30, {
collisionFilter: {
mask: defaultCategory | greenCategory
@ -92,7 +91,7 @@ Example.collisionFiltering = function() {
);
// this body will only collide with the walls and the red bodies
World.add(world,
Composite.add(world,
Bodies.circle(400, 40, 30, {
collisionFilter: {
mask: defaultCategory | redCategory
@ -104,7 +103,7 @@ Example.collisionFiltering = function() {
);
// this body will only collide with the walls and the blue bodies
World.add(world,
Composite.add(world,
Bodies.circle(480, 40, 30, {
collisionFilter: {
mask: defaultCategory | blueCategory
@ -127,7 +126,7 @@ Example.collisionFiltering = function() {
}
});
World.add(world, mouseConstraint);
Composite.add(world, mouseConstraint);
// keep the mouse in sync with rendering
render.mouse = mouse;
@ -154,6 +153,7 @@ Example.collisionFiltering = function() {
};
};
Example.collisionFiltering.title = 'Collision Filtering';
Example.collisionFiltering.for = '>=0.14.2';
if (typeof module !== 'undefined') {

View file

@ -9,7 +9,6 @@ Example.compositeManipulation = function() {
Composites = Matter.Composites,
MouseConstraint = Matter.MouseConstraint,
Mouse = Matter.Mouse,
World = Matter.World,
Bodies = Matter.Bodies;
// create engine
@ -34,7 +33,7 @@ Example.compositeManipulation = function() {
Runner.run(runner, engine);
// add bodies
World.add(world, [
Composite.add(world, [
// walls
Bodies.rectangle(400, 0, 800, 50, { isStatic: true }),
Bodies.rectangle(400, 600, 800, 50, { isStatic: true }),
@ -46,9 +45,9 @@ Example.compositeManipulation = function() {
return Bodies.rectangle(x, y, 40, 40);
});
World.add(world, stack);
Composite.add(world, stack);
world.gravity.y = 0;
engine.gravity.y = 0;
Events.on(engine, 'afterUpdate', function(event) {
var time = engine.timing.timestamp,
@ -84,7 +83,7 @@ Example.compositeManipulation = function() {
}
});
World.add(world, mouseConstraint);
Composite.add(world, mouseConstraint);
// keep the mouse in sync with rendering
render.mouse = mouse;
@ -108,7 +107,8 @@ Example.compositeManipulation = function() {
};
};
Example.compositeManipulation.for = '>=0.14.2';
Example.compositeManipulation.title = 'Composite Manipulation';
Example.compositeManipulation.for = '>0.16.1';
if (typeof module !== 'undefined') {
module.exports = Example.compositeManipulation;

View file

@ -6,9 +6,9 @@ Example.compound = function() {
Runner = Matter.Runner,
Body = Matter.Body,
Constraint = Matter.Constraint,
Composite = Matter.Composite,
MouseConstraint = Matter.MouseConstraint,
Mouse = Matter.Mouse,
World = Matter.World,
Bodies = Matter.Bodies;
// create engine
@ -63,7 +63,7 @@ Example.compound = function() {
pointB: { x: 0, y: 0 }
});
World.add(world, [
Composite.add(world, [
compoundBodyA,
compoundBodyB,
constraint,
@ -82,7 +82,7 @@ Example.compound = function() {
}
});
World.add(world, mouseConstraint);
Composite.add(world, mouseConstraint);
// keep the mouse in sync with rendering
render.mouse = mouse;
@ -106,6 +106,7 @@ Example.compound = function() {
};
};
Example.compound.title = 'Compound Bodies';
Example.compound.for = '>=0.14.2';
if (typeof module !== 'undefined') {

View file

@ -8,7 +8,7 @@ Example.compoundStack = function() {
Composites = Matter.Composites,
MouseConstraint = Matter.MouseConstraint,
Mouse = Matter.Mouse,
World = Matter.World,
Composite = Matter.Composite,
Bodies = Matter.Bodies;
// create engine
@ -35,7 +35,7 @@ Example.compoundStack = function() {
// add bodies
var size = 50;
var stack = Composites.stack(100, 280, 12, 6, 0, 0, function(x, y) {
var stack = Composites.stack(100, 600 - 17 - size * 6, 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 });
@ -44,7 +44,7 @@ Example.compoundStack = function() {
});
});
World.add(world, [
Composite.add(world, [
stack,
// walls
Bodies.rectangle(400, 0, 800, 50, { isStatic: true }),
@ -65,7 +65,7 @@ Example.compoundStack = function() {
}
});
World.add(world, mouseConstraint);
Composite.add(world, mouseConstraint);
// keep the mouse in sync with rendering
render.mouse = mouse;
@ -89,6 +89,7 @@ Example.compoundStack = function() {
};
};
Example.compoundStack.title = 'Compound Stack';
Example.compoundStack.for = '>=0.14.2';
if (typeof module !== 'undefined') {

View file

@ -8,10 +8,13 @@ Example.concave = function() {
Common = Matter.Common,
MouseConstraint = Matter.MouseConstraint,
Mouse = Matter.Mouse,
World = Matter.World,
Composite = Matter.Composite,
Vertices = Matter.Vertices,
Bodies = Matter.Bodies;
// provide concave decomposition support library
Common.setDecomp(require('poly-decomp'));
// create engine
var engine = Engine.create(),
world = engine.world;
@ -33,7 +36,7 @@ Example.concave = function() {
Runner.run(runner, engine);
// add bodies
World.add(world, [
Composite.add(world, [
// walls
Bodies.rectangle(400, 0, 800, 50, { isStatic: true }),
Bodies.rectangle(400, 600, 800, 50, { isStatic: true }),
@ -57,7 +60,7 @@ Example.concave = function() {
}, true);
});
World.add(world, stack);
Composite.add(world, stack);
// add mouse control
var mouse = Mouse.create(render.canvas),
@ -71,7 +74,7 @@ Example.concave = function() {
}
});
World.add(world, mouseConstraint);
Composite.add(world, mouseConstraint);
// keep the mouse in sync with rendering
render.mouse = mouse;
@ -95,7 +98,8 @@ Example.concave = function() {
};
};
Example.concave.for = '>=0.14.2';
Example.concave.title = 'Concave';
Example.concave.for = '>0.16.1';
if (typeof module !== 'undefined') {
module.exports = Example.concave;

View file

@ -9,7 +9,7 @@ Example.constraints = function() {
Constraint = Matter.Constraint,
MouseConstraint = Matter.MouseConstraint,
Mouse = Matter.Mouse,
World = Matter.World,
Composite = Matter.Composite,
Bodies = Matter.Bodies;
// create engine
@ -42,7 +42,7 @@ Example.constraints = function() {
pointB: { x: -10, y: -10 }
});
World.add(world, [body, constraint]);
Composite.add(world, [body, constraint]);
// add soft global constraint
var body = Bodies.polygon(280, 100, 3, 30);
@ -54,7 +54,7 @@ Example.constraints = function() {
stiffness: 0.001
});
World.add(world, [body, constraint]);
Composite.add(world, [body, constraint]);
// add damped soft global constraint
var body = Bodies.polygon(400, 100, 4, 30);
@ -67,7 +67,7 @@ Example.constraints = function() {
damping: 0.05
});
World.add(world, [body, constraint]);
Composite.add(world, [body, constraint]);
// add revolute constraint
var body = Bodies.rectangle(600, 200, 200, 20);
@ -79,7 +79,7 @@ Example.constraints = function() {
length: 0
});
World.add(world, [body, ball, constraint]);
Composite.add(world, [body, ball, constraint]);
// add revolute multi-body constraint
var body = Bodies.rectangle(500, 400, 100, 20, { collisionFilter: { group: -1 } });
@ -90,7 +90,7 @@ Example.constraints = function() {
bodyB: ball
});
World.add(world, [body, ball, constraint]);
Composite.add(world, [body, ball, constraint]);
// add stiff multi-body constraint
var bodyA = Bodies.polygon(100, 400, 6, 20);
@ -103,7 +103,7 @@ Example.constraints = function() {
pointB: { x: -10, y: -10 }
});
World.add(world, [bodyA, bodyB, constraint]);
Composite.add(world, [bodyA, bodyB, constraint]);
// add soft global constraint
var bodyA = Bodies.polygon(300, 400, 4, 20);
@ -117,7 +117,7 @@ Example.constraints = function() {
stiffness: 0.001
});
World.add(world, [bodyA, bodyB, constraint]);
Composite.add(world, [bodyA, bodyB, constraint]);
// add damped soft global constraint
var bodyA = Bodies.polygon(500, 400, 6, 30);
@ -132,9 +132,9 @@ Example.constraints = function() {
damping: 0.1
});
World.add(world, [bodyA, bodyB, constraint]);
Composite.add(world, [bodyA, bodyB, constraint]);
World.add(world, [
Composite.add(world, [
// walls
Bodies.rectangle(400, 0, 800, 50, { isStatic: true }),
Bodies.rectangle(400, 600, 800, 50, { isStatic: true }),
@ -155,7 +155,7 @@ Example.constraints = function() {
}
});
World.add(world, mouseConstraint);
Composite.add(world, mouseConstraint);
// keep the mouse in sync with rendering
render.mouse = mouse;
@ -179,6 +179,7 @@ Example.constraints = function() {
};
};
Example.constraints.title = 'Constraints';
Example.constraints.for = '>=0.14.2';
if (typeof module !== 'undefined') {

View file

@ -11,7 +11,6 @@ Example.doublePendulum = function() {
Constraint = Matter.Constraint,
MouseConstraint = Matter.MouseConstraint,
Mouse = Matter.Mouse,
World = Matter.World,
Bodies = Matter.Bodies,
Vector = Matter.Vector;
@ -53,7 +52,7 @@ Example.doublePendulum = function() {
});
});
world.gravity.scale = 0.002;
engine.gravity.scale = 0.002;
Composites.chain(pendulum, 0.45, 0, -0.45, 0, {
stiffness: 0.9,
@ -82,7 +81,7 @@ Example.doublePendulum = function() {
y: lowerArm.position.y
});
World.add(world, pendulum);
Composite.add(world, pendulum);
var trail = [];
@ -124,7 +123,7 @@ Example.doublePendulum = function() {
}
});
World.add(world, mouseConstraint);
Composite.add(world, mouseConstraint);
// keep the mouse in sync with rendering
render.mouse = mouse;
@ -148,7 +147,8 @@ Example.doublePendulum = function() {
};
};
Example.doublePendulum.for = '>=0.14.2';
Example.doublePendulum.title = 'Double Pendulum';
Example.doublePendulum.for = '>0.16.1';
if (typeof module !== 'undefined') {
module.exports = Example.doublePendulum;

View file

@ -11,7 +11,6 @@ Example.events = function() {
Common = Matter.Common,
MouseConstraint = Matter.MouseConstraint,
Mouse = Matter.Mouse,
World = Matter.World,
Bodies = Matter.Bodies;
// create engine
@ -37,7 +36,7 @@ Example.events = function() {
// an example of using composite events on the world
Events.on(world, 'afterAdd', function(event) {
console.log('added to world:', event.object);
// do something with event.object
});
var lastTime = Common.now();
@ -95,7 +94,7 @@ Example.events = function() {
var bodyStyle = { fillStyle: '#222' };
// scene code
World.add(world, [
Composite.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 }),
@ -106,7 +105,7 @@ Example.events = function() {
return Bodies.circle(x, y, 15, { restitution: 1, render: bodyStyle });
});
World.add(world, stack);
Composite.add(world, stack);
var shakeScene = function(engine, delta) {
var timeScale = delta / 1000;
@ -139,7 +138,7 @@ Example.events = function() {
}
});
World.add(world, mouseConstraint);
Composite.add(world, mouseConstraint);
// keep the mouse in sync with rendering
render.mouse = mouse;
@ -186,6 +185,7 @@ Example.events = function() {
};
};
Example.events.title = 'Events';
Example.events.for = '>=0.14.2';
if (typeof module !== 'undefined') {

View file

@ -6,7 +6,7 @@ Example.friction = function() {
Runner = Matter.Runner,
MouseConstraint = Matter.MouseConstraint,
Mouse = Matter.Mouse,
World = Matter.World,
Composite = Matter.Composite,
Bodies = Matter.Bodies;
// create engine
@ -31,7 +31,7 @@ Example.friction = function() {
Runner.run(runner, engine);
// add bodies
World.add(world, [
Composite.add(world, [
// walls
Bodies.rectangle(400, 0, 800, 50, { isStatic: true }),
Bodies.rectangle(400, 600, 800, 50, { isStatic: true }),
@ -39,17 +39,17 @@ Example.friction = function() {
Bodies.rectangle(0, 300, 50, 600, { isStatic: true })
]);
World.add(world, [
Composite.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, [
Composite.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, [
Composite.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 })
]);
@ -66,7 +66,7 @@ Example.friction = function() {
}
});
World.add(world, mouseConstraint);
Composite.add(world, mouseConstraint);
// keep the mouse in sync with rendering
render.mouse = mouse;
@ -90,6 +90,7 @@ Example.friction = function() {
};
};
Example.friction.title = 'Friction';
Example.friction.for = '>=0.14.2';
if (typeof module !== 'undefined') {

View file

@ -8,7 +8,7 @@ Example.gravity = function() {
Common = Matter.Common,
MouseConstraint = Matter.MouseConstraint,
Mouse = Matter.Mouse,
World = Matter.World,
Composite = Matter.Composite,
Bodies = Matter.Bodies;
// create engine
@ -34,14 +34,14 @@ Example.gravity = function() {
Runner.run(runner, engine);
// add bodies
World.add(world, [
Composite.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;
engine.gravity.y = -1;
var stack = Composites.stack(50, 120, 11, 5, 0, 0, function(x, y) {
switch (Math.round(Common.random(0, 1))) {
@ -58,7 +58,7 @@ Example.gravity = function() {
}
});
World.add(world, stack);
Composite.add(world, stack);
// add mouse control
var mouse = Mouse.create(render.canvas),
@ -72,7 +72,7 @@ Example.gravity = function() {
}
});
World.add(world, mouseConstraint);
Composite.add(world, mouseConstraint);
// keep the mouse in sync with rendering
render.mouse = mouse;
@ -96,7 +96,8 @@ Example.gravity = function() {
};
};
Example.gravity.for = '>=0.14.2';
Example.gravity.title = 'Reverse Gravity';
Example.gravity.for = '>0.16.1';
if (typeof module !== 'undefined') {
module.exports = Example.gravity;

View file

@ -8,7 +8,7 @@ Example.gyro = function() {
Common = Matter.Common,
MouseConstraint = Matter.MouseConstraint,
Mouse = Matter.Mouse,
World = Matter.World,
Composite = Matter.Composite,
Bodies = Matter.Bodies;
// create engine
@ -36,9 +36,6 @@ Example.gyro = function() {
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) {
@ -59,7 +56,7 @@ Example.gyro = function() {
}
});
World.add(world, [
Composite.add(world, [
stack,
Bodies.rectangle(400, 0, 800, 50, { isStatic: true }),
Bodies.rectangle(400, 600, 800, 50, { isStatic: true }),
@ -71,7 +68,7 @@ Example.gyro = function() {
if (typeof window !== 'undefined') {
var updateGravity = function(event) {
var orientation = typeof window.orientation !== 'undefined' ? window.orientation : 0,
gravity = engine.world.gravity;
gravity = engine.gravity;
if (orientation === 0) {
gravity.x = Common.clamp(event.gamma, -90, 90) / 90;
@ -103,7 +100,7 @@ Example.gyro = function() {
}
});
World.add(world, mouseConstraint);
Composite.add(world, mouseConstraint);
// keep the mouse in sync with rendering
render.mouse = mouse;
@ -130,6 +127,7 @@ Example.gyro = function() {
};
};
Example.gyro.title = 'Gyroscope';
Example.gyro.for = '>=0.14.2';
if (typeof module !== 'undefined') {

View file

@ -3,7 +3,6 @@ module.exports = {
avalanche: require('./avalanche.js'),
ballPool: require('./ballPool.js'),
bridge: require('./bridge.js'),
broadphase: require('./broadphase.js'),
car: require('./car.js'),
catapult: require('./catapult.js'),
chains: require('./chains.js'),
@ -28,6 +27,7 @@ module.exports = {
raycasting: require('./raycasting.js'),
restitution: require('./restitution.js'),
rounded: require('./rounded.js'),
remove: require('./remove.js'),
sensors: require('./sensors.js'),
sleeping: require('./sleeping.js'),
slingshot: require('./slingshot.js'),
@ -35,8 +35,10 @@ module.exports = {
sprites: require('./sprites.js'),
stack: require('./stack.js'),
staticFriction: require('./staticFriction.js'),
stats: require('./stats.js'),
stress: require('./stress.js'),
stress2: require('./stress2.js'),
stress3: require('./stress3.js'),
svg: require('./svg.js'),
terrain: require('./terrain.js'),
timescale: require('./timescale.js'),

View file

@ -9,7 +9,7 @@ Example.manipulation = function() {
Events = Matter.Events,
MouseConstraint = Matter.MouseConstraint,
Mouse = Matter.Mouse,
World = Matter.World,
Composite = Matter.Composite,
Bodies = Matter.Bodies;
// create engine
@ -50,9 +50,9 @@ Example.manipulation = function() {
isStatic: true
});
World.add(world, [bodyA, bodyB, bodyC, bodyD, bodyE, bodyF, bodyG, compound]);
Composite.add(world, [bodyA, bodyB, bodyC, bodyD, bodyE, bodyF, bodyG, compound]);
World.add(world, [
Composite.add(world, [
// walls
Bodies.rectangle(400, 0, 800, 50, { isStatic: true }),
Bodies.rectangle(400, 600, 800, 50, { isStatic: true }),
@ -115,7 +115,7 @@ Example.manipulation = function() {
}
});
World.add(world, mouseConstraint);
Composite.add(world, mouseConstraint);
// keep the mouse in sync with rendering
render.mouse = mouse;
@ -139,6 +139,7 @@ Example.manipulation = function() {
};
};
Example.manipulation.title = 'Manipulation';
Example.manipulation.for = '>=0.14.2';
if (typeof module !== 'undefined') {

View file

@ -8,7 +8,7 @@ Example.mixed = function() {
Common = Matter.Common,
MouseConstraint = Matter.MouseConstraint,
Mouse = Matter.Mouse,
World = Matter.World,
Composite = Matter.Composite,
Bodies = Matter.Bodies;
// create engine
@ -36,9 +36,6 @@ Example.mixed = function() {
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) {
@ -59,9 +56,9 @@ Example.mixed = function() {
}
});
World.add(world, stack);
Composite.add(world, stack);
World.add(world, [
Composite.add(world, [
// walls
Bodies.rectangle(400, 0, 800, 50, { isStatic: true }),
Bodies.rectangle(400, 600, 800, 50, { isStatic: true }),
@ -81,7 +78,7 @@ Example.mixed = function() {
}
});
World.add(world, mouseConstraint);
Composite.add(world, mouseConstraint);
// keep the mouse in sync with rendering
render.mouse = mouse;
@ -105,6 +102,7 @@ Example.mixed = function() {
};
};
Example.mixed.title = 'Mixed Shapes';
Example.mixed.for = '>=0.14.2';
if (typeof module !== 'undefined') {

View file

@ -8,7 +8,7 @@ Example.newtonsCradle = function() {
Composites = Matter.Composites,
MouseConstraint = Matter.MouseConstraint,
Mouse = Matter.Mouse,
World = Matter.World;
Composite = Matter.Composite;
// create engine
var engine = Engine.create(),
@ -31,13 +31,13 @@ Example.newtonsCradle = function() {
var runner = Runner.create();
Runner.run(runner, engine);
// add bodies
var cradle = Composites.newtonsCradle(280, 100, 5, 30, 200);
World.add(world, cradle);
// see newtonsCradle function defined later in this file
var cradle = Example.newtonsCradle.newtonsCradle(280, 100, 5, 30, 200);
Composite.add(world, cradle);
Body.translate(cradle.bodies[0], { x: -180, y: -100 });
cradle = Composites.newtonsCradle(280, 380, 7, 20, 140);
World.add(world, cradle);
cradle = Example.newtonsCradle.newtonsCradle(280, 380, 7, 20, 140);
Composite.add(world, cradle);
Body.translate(cradle.bodies[0], { x: -140, y: -100 });
// add mouse control
@ -52,7 +52,7 @@ Example.newtonsCradle = function() {
}
});
World.add(world, mouseConstraint);
Composite.add(world, mouseConstraint);
// keep the mouse in sync with rendering
render.mouse = mouse;
@ -76,8 +76,39 @@ Example.newtonsCradle = function() {
};
};
Example.newtonsCradle.title = 'Newton\'s Cradle';
Example.newtonsCradle.for = '>=0.14.2';
/**
* 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
*/
Example.newtonsCradle.newtonsCradle = function(xx, yy, number, size, length) {
var Composite = Matter.Composite,
Constraint = Matter.Constraint,
Bodies = Matter.Bodies;
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;
};
if (typeof module !== 'undefined') {
module.exports = Example.newtonsCradle;
}

View file

@ -7,7 +7,7 @@ Example.pyramid = function() {
Composites = Matter.Composites,
MouseConstraint = Matter.MouseConstraint,
Mouse = Matter.Mouse,
World = Matter.World,
Composite = Matter.Composite,
Bodies = Matter.Bodies;
// create engine
@ -32,11 +32,11 @@ Example.pyramid = function() {
Runner.run(runner, engine);
// add bodies
var stack = Composites.pyramid(100, 258, 15, 10, 0, 0, function(x, y) {
var stack = Composites.pyramid(100, 605 - 25 - 16 * 20, 15, 10, 0, 0, function(x, y) {
return Bodies.rectangle(x, y, 40, 40);
});
World.add(world, [
Composite.add(world, [
stack,
// walls
Bodies.rectangle(400, 0, 800, 50, { isStatic: true }),
@ -57,7 +57,7 @@ Example.pyramid = function() {
}
});
World.add(world, mouseConstraint);
Composite.add(world, mouseConstraint);
// keep the mouse in sync with rendering
render.mouse = mouse;
@ -81,6 +81,7 @@ Example.pyramid = function() {
};
};
Example.pyramid.title = 'Pyramid';
Example.pyramid.for = '>=0.14.2';
if (typeof module !== 'undefined') {

View file

@ -11,7 +11,6 @@ Example.ragdoll = function() {
Composites = Matter.Composites,
MouseConstraint = Matter.MouseConstraint,
Mouse = Matter.Mouse,
World = Matter.World,
Bodies = Matter.Bodies;
// create engine
@ -78,7 +77,7 @@ Example.ragdoll = function() {
Composite.add(ragdolls, ragdoll);
}
World.add(world, [stack, obstacles, ragdolls]);
Composite.add(world, [stack, obstacles, ragdolls]);
var timeScaleTarget = 1,
lastTime = Common.now();
@ -171,7 +170,7 @@ Example.ragdoll = function() {
}
});
World.add(world, mouseConstraint);
Composite.add(world, mouseConstraint);
// keep the mouse in sync with rendering
render.mouse = mouse;
@ -496,6 +495,7 @@ Example.ragdoll.ragdoll = function(x, y, scale, options) {
return person;
};
Example.ragdoll.title = 'Ragdoll';
Example.ragdoll.for = '>=0.14.2';
if (typeof module !== 'undefined') {

View file

@ -11,7 +11,6 @@ Example.raycasting = function() {
MouseConstraint = Matter.MouseConstraint,
Mouse = Matter.Mouse,
Events = Matter.Events,
World = Matter.World,
Vertices = Matter.Vertices,
Bodies = Matter.Bodies;
@ -53,10 +52,13 @@ Example.raycasting = function() {
}
});
// for testing raycasting on concave bodies
Common.setDecomp(require('poly-decomp'));
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, [
Composite.add(world, [
stack,
concave,
// walls
@ -66,14 +68,21 @@ Example.raycasting = function() {
Bodies.rectangle(0, 300, 50, 600, { isStatic: true })
]);
var collisions = [],
startPoint = { x: 400, y: 100 };
Events.on(engine, 'afterUpdate', function() {
var mouse = mouseConstraint.mouse,
bodies = Composite.allBodies(engine.world),
endPoint = mouse.position || { x: 100, y: 600 };
collisions = Query.ray(bodies, startPoint, endPoint);
});
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);
endPoint = mouse.position || { x: 100, y: 600 };
Render.startViewTransform(render);
@ -111,7 +120,7 @@ Example.raycasting = function() {
}
});
World.add(world, mouseConstraint);
Composite.add(world, mouseConstraint);
// keep the mouse in sync with rendering
render.mouse = mouse;
@ -135,7 +144,8 @@ Example.raycasting = function() {
};
};
Example.raycasting.for = '>=0.14.2';
Example.raycasting.title = 'Raycasting';
Example.raycasting.for = '>0.16.1';
if (typeof module !== 'undefined') {
module.exports = Example.raycasting;

138
examples/remove.js Normal file
View file

@ -0,0 +1,138 @@
var Example = Example || {};
Example.remove = function() {
var Engine = Matter.Engine,
Render = Matter.Render,
Runner = Matter.Runner,
Composites = Matter.Composites,
Common = Matter.Common,
MouseConstraint = Matter.MouseConstraint,
Mouse = Matter.Mouse,
Composite = Matter.Composite,
Bodies = Matter.Bodies,
Events = Matter.Events;
// 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);
var stack = null,
updateCount = 0;
var createStack = function() {
return Composites.stack(20, 20, 10, 5, 0, 0, function(x, y) {
var sides = Math.round(Common.random(1, 8));
// 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 });
}
});
};
// add and remove stacks every few updates
Events.on(engine, 'afterUpdate', function() {
// limit rate
if (stack && updateCount <= 50) {
updateCount += 1;
return;
}
updateCount = 0;
// remove last stack
if (stack) {
Composite.remove(world, stack);
}
// create a new stack
stack = createStack();
// add the new stack
Composite.add(world, stack);
});
// add another stack that will not be removed
Composite.add(world, createStack());
Composite.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
}
}
});
Composite.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.remove.title = 'Composite Remove';
Example.remove.for = '>=0.14.2';
if (typeof module !== 'undefined') {
module.exports = Example.remove;
}

View file

@ -6,7 +6,7 @@ Example.restitution = function() {
Runner = Matter.Runner,
MouseConstraint = Matter.MouseConstraint,
Mouse = Matter.Mouse,
World = Matter.World,
Composite = Matter.Composite,
Bodies = Matter.Bodies;
// create engine
@ -36,7 +36,7 @@ Example.restitution = function() {
var rest = 0.9,
space = 600 / 5;
World.add(world, [
Composite.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 }),
@ -61,7 +61,7 @@ Example.restitution = function() {
}
});
World.add(world, mouseConstraint);
Composite.add(world, mouseConstraint);
// keep the mouse in sync with rendering
render.mouse = mouse;
@ -85,6 +85,7 @@ Example.restitution = function() {
};
};
Example.restitution.title = 'Restitution';
Example.restitution.for = '>=0.14.2';
if (typeof module !== 'undefined') {

View file

@ -6,7 +6,7 @@ Example.rounded = function() {
Runner = Matter.Runner,
MouseConstraint = Matter.MouseConstraint,
Mouse = Matter.Mouse,
World = Matter.World,
Composite = Matter.Composite,
Bodies = Matter.Bodies;
// create engine
@ -31,7 +31,7 @@ Example.rounded = function() {
Runner.run(runner, engine);
// add bodies
World.add(world, [
Composite.add(world, [
// walls
Bodies.rectangle(400, 0, 800, 50, { isStatic: true }),
Bodies.rectangle(400, 600, 800, 50, { isStatic: true }),
@ -39,7 +39,7 @@ Example.rounded = function() {
Bodies.rectangle(0, 300, 50, 600, { isStatic: true })
]);
World.add(world, [
Composite.add(world, [
Bodies.rectangle(200, 200, 100, 100, {
chamfer: { radius: 20 }
}),
@ -85,7 +85,7 @@ Example.rounded = function() {
}
});
World.add(world, mouseConstraint);
Composite.add(world, mouseConstraint);
// keep the mouse in sync with rendering
render.mouse = mouse;
@ -109,6 +109,7 @@ Example.rounded = function() {
};
};
Example.rounded.title = 'Rounded Corners (Chamfering)';
Example.rounded.for = '>=0.14.2';
if (typeof module !== 'undefined') {

View file

@ -7,7 +7,7 @@ Example.sensors = function() {
Events = Matter.Events,
MouseConstraint = Matter.MouseConstraint,
Mouse = Matter.Mouse,
World = Matter.World,
Composite = Matter.Composite,
Bodies = Matter.Bodies;
// create engine
@ -45,7 +45,7 @@ Example.sensors = function() {
}
});
World.add(world, [
Composite.add(world, [
collider,
Bodies.rectangle(400, 600, 800, 50, {
isStatic: true,
@ -56,7 +56,7 @@ Example.sensors = function() {
})
]);
World.add(world,
Composite.add(world,
Bodies.circle(400, 40, 30, {
render: {
strokeStyle: colorB,
@ -106,7 +106,7 @@ Example.sensors = function() {
}
});
World.add(world, mouseConstraint);
Composite.add(world, mouseConstraint);
// keep the mouse in sync with rendering
render.mouse = mouse;
@ -130,6 +130,7 @@ Example.sensors = function() {
};
};
Example.sensors.title = 'Sensors';
Example.sensors.for = '>=0.14.2';
if (typeof module !== 'undefined') {

View file

@ -9,7 +9,7 @@ Example.sleeping = function() {
Events = Matter.Events,
MouseConstraint = Matter.MouseConstraint,
Mouse = Matter.Mouse,
World = Matter.World,
Composite = Matter.Composite,
Bodies = Matter.Bodies;
// create engine
@ -36,7 +36,7 @@ Example.sleeping = function() {
Runner.run(runner, engine);
// add bodies
World.add(world, [
Composite.add(world, [
// walls
Bodies.rectangle(400, 0, 800, 50, { isStatic: true }),
Bodies.rectangle(400, 600, 800, 50, { isStatic: true }),
@ -59,14 +59,17 @@ Example.sleeping = function() {
}
});
World.add(world, stack);
Composite.add(world, stack);
/*
// sleep events
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),
@ -80,7 +83,7 @@ Example.sleeping = function() {
}
});
World.add(world, mouseConstraint);
Composite.add(world, mouseConstraint);
// keep the mouse in sync with rendering
render.mouse = mouse;
@ -104,6 +107,7 @@ Example.sleeping = function() {
};
};
Example.sleeping.title = 'Sleeping';
Example.sleeping.for = '>=0.14.2';
if (typeof module !== 'undefined') {

View file

@ -9,8 +9,8 @@ Example.slingshot = function() {
Constraint = Matter.Constraint,
MouseConstraint = Matter.MouseConstraint,
Mouse = Matter.Mouse,
World = Matter.World,
Body = Matter.Body,
Composite = Matter.Composite,
Bodies = Matter.Bodies;
// create engine
@ -55,7 +55,7 @@ Example.slingshot = function() {
return Bodies.rectangle(x, y, 25, 40);
});
World.add(engine.world, [ground, pyramid, ground2, pyramid2, rock, elastic]);
Composite.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)) {
@ -66,7 +66,7 @@ Example.slingshot = function() {
// Release current rock and add a new one.
rock = Bodies.polygon(170, 450, 7, 20, rockOptions);
World.add(engine.world, rock);
Composite.add(engine.world, rock);
elastic.bodyB = rock;
}
});
@ -83,7 +83,7 @@ Example.slingshot = function() {
}
});
World.add(world, mouseConstraint);
Composite.add(world, mouseConstraint);
// keep the mouse in sync with rendering
render.mouse = mouse;
@ -107,6 +107,7 @@ Example.slingshot = function() {
};
};
Example.slingshot.title = 'Slingshot';
Example.slingshot.for = '>=0.14.2';
if (typeof module !== 'undefined') {

View file

@ -7,7 +7,7 @@ Example.softBody = function() {
Composites = Matter.Composites,
MouseConstraint = Matter.MouseConstraint,
Mouse = Matter.Mouse,
World = Matter.World,
Composite = Matter.Composite,
Bodies = Matter.Bodies;
// create engine
@ -38,10 +38,11 @@ Example.softBody = function() {
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),
Composite.add(world, [
// see softBody function defined later in this file
Example.softBody.softBody(250, 100, 5, 5, 0, 0, true, 18, particleOptions),
Example.softBody.softBody(400, 300, 8, 3, 0, 0, true, 15, particleOptions),
Example.softBody.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 }),
@ -61,7 +62,7 @@ Example.softBody = function() {
}
});
World.add(world, mouseConstraint);
Composite.add(world, mouseConstraint);
// keep the mouse in sync with rendering
render.mouse = mouse;
@ -85,8 +86,43 @@ Example.softBody = function() {
};
};
Example.softBody.title = 'Soft Body';
Example.softBody.for = '>=0.14.2';
/**
* 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
*/
Example.softBody.softBody = function(xx, yy, columns, rows, columnGap, rowGap, crossBrace, particleRadius, particleOptions, constraintOptions) {
var Common = Matter.Common,
Composites = Matter.Composites,
Bodies = Matter.Bodies;
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;
};
if (typeof module !== 'undefined') {
module.exports = Example.softBody;
}

View file

@ -8,7 +8,7 @@ Example.sprites = function() {
Common = Matter.Common,
MouseConstraint = Matter.MouseConstraint,
Mouse = Matter.Mouse,
World = Matter.World,
Composite = Matter.Composite,
Bodies = Matter.Bodies;
// create engine
@ -42,7 +42,7 @@ Example.sprites = function() {
world.bodies = [];
// these static walls will not be rendered in this sprites example, see options
World.add(world, [
Composite.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),
@ -74,7 +74,7 @@ Example.sprites = function() {
}
});
World.add(world, stack);
Composite.add(world, stack);
// add mouse control
var mouse = Mouse.create(render.canvas),
@ -88,7 +88,7 @@ Example.sprites = function() {
}
});
World.add(world, mouseConstraint);
Composite.add(world, mouseConstraint);
// keep the mouse in sync with rendering
render.mouse = mouse;
@ -112,6 +112,7 @@ Example.sprites = function() {
};
};
Example.sprites.title = 'Sprites';
Example.sprites.for = '>=0.14.2';
if (typeof module !== 'undefined') {

View file

@ -7,7 +7,7 @@ Example.stack = function() {
Composites = Matter.Composites,
MouseConstraint = Matter.MouseConstraint,
Mouse = Matter.Mouse,
World = Matter.World,
Composite = Matter.Composite,
Bodies = Matter.Bodies;
// create engine
@ -32,11 +32,11 @@ Example.stack = function() {
Runner.run(runner, engine);
// add bodies
var stack = Composites.stack(200, 380, 10, 5, 0, 0, function(x, y) {
var stack = Composites.stack(200, 606 - 25.25 - 5 * 40, 10, 5, 0, 0, function(x, y) {
return Bodies.rectangle(x, y, 40, 40);
});
World.add(world, [
Composite.add(world, [
stack,
// walls
Bodies.rectangle(400, 0, 800, 50, { isStatic: true }),
@ -57,7 +57,7 @@ Example.stack = function() {
}
});
World.add(world, mouseConstraint);
Composite.add(world, mouseConstraint);
// keep the mouse in sync with rendering
render.mouse = mouse;
@ -81,6 +81,7 @@ Example.stack = function() {
};
};
Example.stack.title = 'Stack';
Example.stack.for = '>=0.14.2';
if (typeof module !== 'undefined') {

View file

@ -9,7 +9,7 @@ Example.staticFriction = function() {
Events = Matter.Events,
MouseConstraint = Matter.MouseConstraint,
Mouse = Matter.Mouse,
World = Matter.World,
Composite = Matter.Composite,
Bodies = Matter.Bodies;
// create engine
@ -45,7 +45,7 @@ Example.staticFriction = function() {
});
});
World.add(world, [
Composite.add(world, [
body,
stack,
// walls
@ -77,7 +77,7 @@ Example.staticFriction = function() {
}
});
World.add(world, mouseConstraint);
Composite.add(world, mouseConstraint);
// keep the mouse in sync with rendering
render.mouse = mouse;
@ -101,6 +101,7 @@ Example.staticFriction = function() {
};
};
Example.staticFriction.title = 'Static Friction';
Example.staticFriction.for = '>=0.14.2';
if (typeof module !== 'undefined') {

View file

@ -1,11 +1,11 @@
var Example = Example || {};
Example.broadphase = function() {
Example.stats = function() {
var Engine = Matter.Engine,
Render = Matter.Render,
Runner = Matter.Runner,
Composites = Matter.Composites,
Common = Matter.Common,
Composites = Matter.Composites,
MouseConstraint = Matter.MouseConstraint,
Mouse = Matter.Mouse,
World = Matter.World,
@ -22,8 +22,9 @@ Example.broadphase = function() {
options: {
width: 800,
height: 600,
showAngleIndicator: true,
showBroadphase: true
// show stats and performance monitors
showStats: true,
showPerformance: true
}
});
@ -33,32 +34,19 @@ Example.broadphase = function() {
var runner = Runner.create();
Runner.run(runner, engine);
// add bodies
// scene code
var stack = Composites.stack(70, 30, 13, 9, 5, 5, function(x, y) {
return Bodies.circle(x, y, 10 + Common.random() * 20);
});
World.add(world, [
// walls
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 })
]);
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, {
@ -95,8 +83,9 @@ Example.broadphase = function() {
};
};
Example.broadphase.for = '>=0.14.2';
Example.stats.title = 'Stats & Performance';
Example.stats.for = '>=0.16.1';
if (typeof module !== 'undefined') {
module.exports = Example.broadphase;
module.exports = Example.stats;
}

View file

@ -7,7 +7,7 @@ Example.stress = function() {
Composites = Matter.Composites,
MouseConstraint = Matter.MouseConstraint,
Mouse = Matter.Mouse,
World = Matter.World,
Composite = Matter.Composite,
Bodies = Matter.Bodies;
// create engine
@ -20,7 +20,9 @@ Example.stress = function() {
engine: engine,
options: {
width: 800,
height: 600
height: 600,
showStats: true,
showPerformance: true
}
});
@ -31,11 +33,11 @@ Example.stress = function() {
Runner.run(runner, engine);
// scene code
var stack = Composites.stack(90, 50, 18, 15, 0, 0, function(x, y) {
var stack = Composites.stack(90, 600 - 25 - 15 * 35, 18, 15, 0, 0, function(x, y) {
return Bodies.rectangle(x, y, 35, 35);
});
World.add(world, [
Composite.add(world, [
stack,
Bodies.rectangle(400, 0, 800, 50, { isStatic: true }),
Bodies.rectangle(400, 600, 800, 50, { isStatic: true }),
@ -55,7 +57,7 @@ Example.stress = function() {
}
});
World.add(world, mouseConstraint);
Composite.add(world, mouseConstraint);
// keep the mouse in sync with rendering
render.mouse = mouse;
@ -79,6 +81,7 @@ Example.stress = function() {
};
};
Example.stress.title = 'Stress';
Example.stress.for = '>=0.14.2';
if (typeof module !== 'undefined') {

View file

@ -7,7 +7,7 @@ Example.stress2 = function() {
Composites = Matter.Composites,
MouseConstraint = Matter.MouseConstraint,
Mouse = Matter.Mouse,
World = Matter.World,
Composite = Matter.Composite,
Bodies = Matter.Bodies;
// create engine
@ -20,7 +20,9 @@ Example.stress2 = function() {
engine: engine,
options: {
width: 800,
height: 600
height: 600,
showStats: true,
showPerformance: true
}
});
@ -31,11 +33,11 @@ Example.stress2 = function() {
Runner.run(runner, engine);
// scene code
var stack = Composites.stack(100, 120, 25, 18, 0, 0, function(x, y) {
var stack = Composites.stack(100, 600 - 25 - 18 * 25, 25, 18, 0, 0, function(x, y) {
return Bodies.rectangle(x, y, 25, 25);
});
World.add(world, [
Composite.add(world, [
stack,
Bodies.rectangle(400, 0, 800, 50, { isStatic: true }),
Bodies.rectangle(400, 600, 800, 50, { isStatic: true }),
@ -55,7 +57,7 @@ Example.stress2 = function() {
}
});
World.add(world, mouseConstraint);
Composite.add(world, mouseConstraint);
// keep the mouse in sync with rendering
render.mouse = mouse;
@ -79,6 +81,7 @@ Example.stress2 = function() {
};
};
Example.stress2.title = 'Stress 2';
Example.stress2.for = '>=0.14.2';
if (typeof module !== 'undefined') {

111
examples/stress3.js Normal file
View file

@ -0,0 +1,111 @@
var Example = Example || {};
Example.stress3 = function() {
var Engine = Matter.Engine,
Render = Matter.Render,
Runner = Matter.Runner,
Composites = Matter.Composites,
Common = Matter.Common,
MouseConstraint = Matter.MouseConstraint,
Mouse = Matter.Mouse,
Composite = Matter.Composite,
Bodies = Matter.Bodies;
// create engine
var engine = Engine.create({
positionIterations: 10,
velocityIterations: 10
});
var world = engine.world;
// create renderer
var render = Render.create({
element: document.body,
engine: engine,
options: {
width: 800,
height: 600,
showStats: true,
showPerformance: true
}
});
Render.run(render);
// create runner
var runner = Runner.create({
isFixed: true
});
Runner.run(runner, engine);
// add bodies
var scale = 0.3;
var stack = Composites.stack(40, 40, 38, 18, 0, 0, function(x, y) {
var sides = Math.round(Common.random(1, 8));
switch (Math.round(Common.random(0, 1))) {
case 0:
if (Common.random() < 0.8) {
return Bodies.rectangle(x, y, Common.random(25, 50) * scale, Common.random(25, 50) * scale);
} else {
return Bodies.rectangle(x, y, Common.random(80, 120) * scale, Common.random(25, 30) * scale);
}
case 1:
return Bodies.polygon(x, y, sides, Common.random(25, 50) * scale);
}
});
Composite.add(world, stack);
Composite.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
}
}
});
Composite.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.stress3.title = 'Stress 3';
Example.stress3.for = '>=0.14.2';
if (typeof module !== 'undefined') {
module.exports = Example.stress3;
}

View file

@ -7,11 +7,14 @@ Example.svg = function() {
Common = Matter.Common,
MouseConstraint = Matter.MouseConstraint,
Mouse = Matter.Mouse,
World = Matter.World,
Composite = Matter.Composite,
Vertices = Matter.Vertices,
Svg = Matter.Svg,
Bodies = Matter.Bodies;
// provide concave decomposition support library
Common.setDecomp(require('poly-decomp'));
// create engine
var engine = Engine.create(),
world = engine.world;
@ -33,45 +36,46 @@ Example.svg = function() {
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 fetch !== 'undefined') {
var select = function(root, selector) {
return Array.prototype.slice.call(root.querySelectorAll(selector));
};
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']);
var loadSvg = function(url) {
return fetch(url)
.then(function(response) { return response.text(); })
.then(function(raw) { return (new window.DOMParser()).parseFromString(raw, 'image/svg+xml'); });
};
$(data).find('path').each(function(i, path) {
var points = Svg.pathToVertices(path, 30);
vertexSets.push(Vertices.scale(points, 0.4, 0.4));
});
([
'./svg/iconmonstr-check-mark-8-icon.svg',
'./svg/iconmonstr-paperclip-2-icon.svg',
'./svg/iconmonstr-puzzle-icon.svg',
'./svg/iconmonstr-user-icon.svg'
]).forEach(function(path, i) {
loadSvg(path).then(function(root) {
var color = Common.choose(['#f19648', '#f5d259', '#f55a3c', '#063e7b', '#ececd1']);
World.add(world, Bodies.fromVertices(100 + i * 150, 200 + i * 50, vertexSets, {
render: {
fillStyle: color,
strokeStyle: color,
lineWidth: 1
}
}, true));
});
})(i);
}
var vertexSets = select(root, 'path')
.map(function(path) { return Vertices.scale(Svg.pathToVertices(path, 30), 0.4, 0.4); });
$.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));
Composite.add(world, Bodies.fromVertices(100 + i * 150, 200 + i * 50, vertexSets, {
render: {
fillStyle: color,
strokeStyle: color,
lineWidth: 1
}
}, true));
});
});
World.add(world, Bodies.fromVertices(400, 80, vertexSets, {
loadSvg('./svg/svg.svg').then(function(root) {
var color = Common.choose(['#f19648', '#f5d259', '#f55a3c', '#063e7b', '#ececd1']);
var vertexSets = select(root, 'path')
.map(function(path) { return Svg.pathToVertices(path, 30); });
Composite.add(world, Bodies.fromVertices(400, 80, vertexSets, {
render: {
fillStyle: color,
strokeStyle: color,
@ -79,9 +83,11 @@ Example.svg = function() {
}
}, true));
});
} else {
Common.warn('Fetch is not available. Could not load SVG.');
}
World.add(world, [
Composite.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 }),
@ -100,7 +106,7 @@ Example.svg = function() {
}
});
World.add(world, mouseConstraint);
Composite.add(world, mouseConstraint);
// keep the mouse in sync with rendering
render.mouse = mouse;
@ -124,7 +130,8 @@ Example.svg = function() {
};
};
Example.svg.for = '>=0.14.2';
Example.svg.title = 'Concave SVG Paths';
Example.svg.for = '>0.16.1';
if (typeof module !== 'undefined') {
module.exports = Example.svg;

View file

@ -8,11 +8,14 @@ Example.terrain = function() {
Common = Matter.Common,
MouseConstraint = Matter.MouseConstraint,
Mouse = Matter.Mouse,
World = Matter.World,
Composite = Matter.Composite,
Query = Matter.Query,
Svg = Matter.Svg,
Bodies = Matter.Bodies;
// provide concave decomposition support library
Common.setDecomp(require('poly-decomp'));
// create engine
var engine = Engine.create(),
world = engine.world;
@ -34,39 +37,48 @@ Example.terrain = function() {
Runner.run(runner, engine);
// add bodies
var terrain;
if (typeof fetch !== 'undefined') {
var select = function(root, selector) {
return Array.prototype.slice.call(root.querySelectorAll(selector));
};
if (typeof $ !== 'undefined') {
$.get('./svg/terrain.svg').done(function(data) {
var vertexSets = [];
var loadSvg = function(url) {
return fetch(url)
.then(function(response) { return response.text(); })
.then(function(raw) { return (new window.DOMParser()).parseFromString(raw, 'image/svg+xml'); });
};
$(data).find('path').each(function(i, path) {
vertexSets.push(Svg.pathToVertices(path, 30));
loadSvg('./svg/terrain.svg')
.then(function(root) {
var paths = select(root, 'path');
var vertexSets = paths.map(function(path) { return Svg.pathToVertices(path, 30); });
var terrain = Bodies.fromVertices(400, 350, vertexSets, {
isStatic: true,
render: {
fillStyle: '#060a19',
strokeStyle: '#060a19',
lineWidth: 1
}
}, true);
Composite.add(world, terrain);
var bodyOptions = {
frictionAir: 0,
friction: 0.0001,
restitution: 0.6
};
Composite.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);
}
}));
});
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);
}
}));
});
} else {
Common.warn('Fetch is not available. Could not load SVG.');
}
// add mouse control
@ -81,7 +93,7 @@ Example.terrain = function() {
}
});
World.add(world, mouseConstraint);
Composite.add(world, mouseConstraint);
// keep the mouse in sync with rendering
render.mouse = mouse;
@ -105,7 +117,8 @@ Example.terrain = function() {
};
};
Example.terrain.for = '>=0.14.2';
Example.terrain.title = 'Terrain';
Example.terrain.for = '>0.16.1';
if (typeof module !== 'undefined') {
module.exports = Example.terrain;

View file

@ -11,7 +11,6 @@ Example.timescale = function() {
Common = Matter.Common,
MouseConstraint = Matter.MouseConstraint,
Mouse = Matter.Mouse,
World = Matter.World,
Bodies = Matter.Bodies;
// create engine
@ -36,7 +35,7 @@ Example.timescale = function() {
Runner.run(runner, engine);
// add bodies
World.add(world, [
Composite.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 }),
@ -95,11 +94,11 @@ Example.timescale = function() {
restitution: 0.8
};
World.add(world, Composites.stack(20, 100, 15, 3, 20, 40, function(x, y) {
Composite.add(world, Composites.stack(20, 100, 15, 3, 20, 40, function(x, y) {
return Bodies.circle(x, y, Common.random(10, 20), bodyOptions);
}));
World.add(world, Composites.stack(50, 50, 8, 3, 0, 0, function(x, y) {
Composite.add(world, Composites.stack(50, 50, 8, 3, 0, 0, function(x, y) {
switch (Math.round(Common.random(0, 1))) {
case 0:
@ -126,7 +125,7 @@ Example.timescale = function() {
}
});
World.add(world, mouseConstraint);
Composite.add(world, mouseConstraint);
// keep the mouse in sync with rendering
render.mouse = mouse;
@ -150,6 +149,7 @@ Example.timescale = function() {
};
};
Example.timescale.title = 'Time Scaling';
Example.timescale.for = '>=0.14.2';
if (typeof module !== 'undefined') {

View file

@ -9,7 +9,7 @@ Example.views = function() {
Common = Matter.Common,
MouseConstraint = Matter.MouseConstraint,
Mouse = Matter.Mouse,
World = Matter.World,
Composite = Matter.Composite,
Vector = Matter.Vector,
Bounds = Matter.Bounds,
Bodies = Matter.Bodies;
@ -48,13 +48,13 @@ Example.views = function() {
}
});
World.add(world, mouseConstraint);
Composite.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) {
var stack = Composites.stack(20, 20, 10, 4, 0, 0, function(x, y) {
switch (Math.round(Common.random(0, 1))) {
case 0:
@ -70,7 +70,7 @@ Example.views = function() {
}
});
World.add(world, [
Composite.add(world, [
stack,
// walls
Bodies.rectangle(400, 0, 800, 50, { isStatic: true }),
@ -85,11 +85,11 @@ Example.views = function() {
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;
// create limits for the viewport
var extents = {
min: { x: -300, y: -300 },
max: { x: 1100, y: 900 }
};
// keep track of current bounds scale (view zoom)
var boundsScaleTarget = 1,
@ -98,8 +98,8 @@ Example.views = function() {
y: 1
};
// use the engine tick event to control our view
Events.on(engine, 'beforeTick', function() {
// use a render event to control our view
Events.on(render, 'beforeRender', function() {
var world = engine.world,
mouse = mouseConstraint.mouse,
translate;
@ -148,18 +148,18 @@ Example.views = function() {
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;
// prevent the view moving outside the extents
if (render.bounds.min.x + translate.x < extents.min.x)
translate.x = extents.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.max.x + translate.x > extents.max.x)
translate.x = extents.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.min.y + translate.y < extents.min.y)
translate.y = extents.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;
if (render.bounds.max.y + translate.y > extents.max.y)
translate.y = extents.max.y - render.bounds.max.y;
// move the view
Bounds.translate(render.bounds, translate);
@ -182,6 +182,7 @@ Example.views = function() {
};
};
Example.views.title = 'Views';
Example.views.for = '>=0.14.2';
if (typeof module !== 'undefined') {

View file

@ -7,7 +7,7 @@ Example.wreckingBall = function() {
Composites = Matter.Composites,
MouseConstraint = Matter.MouseConstraint,
Mouse = Matter.Mouse,
World = Matter.World,
Composite = Matter.Composite,
Constraint = Matter.Constraint,
Bodies = Matter.Bodies;
@ -34,13 +34,13 @@ Example.wreckingBall = function() {
// add bodies
var rows = 10,
yy = 600 - 21 - 40 * rows;
yy = 600 - 25 - 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, [
Composite.add(world, [
stack,
// walls
Bodies.rectangle(400, 0, 800, 50, { isStatic: true }),
@ -51,8 +51,8 @@ Example.wreckingBall = function() {
var ball = Bodies.circle(100, 400, 50, { density: 0.04, frictionAir: 0.005});
World.add(world, ball);
World.add(world, Constraint.create({
Composite.add(world, ball);
Composite.add(world, Constraint.create({
pointA: { x: 300, y: 100 },
bodyB: ball
}));
@ -69,7 +69,7 @@ Example.wreckingBall = function() {
}
});
World.add(world, mouseConstraint);
Composite.add(world, mouseConstraint);
// keep the mouse in sync with rendering
render.mouse = mouse;
@ -93,6 +93,7 @@ Example.wreckingBall = function() {
};
};
Example.wreckingBall.title = 'Wrecking Ball';
Example.wreckingBall.for = '>=0.14.2';
if (typeof module !== 'undefined') {

20857
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,6 @@
{
"name": "matter-js",
"version": "0.15.0",
"version": "0.18.0",
"license": "MIT",
"homepage": "http://brm.io/matter-js/",
"author": "Liam Brummitt <liam@brm.io> (http://brm.io/)",
@ -22,35 +22,46 @@
"devDependencies": {
"conventional-changelog-cli": "^2.1.1",
"eslint": "^6.8.0",
"html-webpack-plugin": "^4.5.1",
"jest": "^25.1.0",
"jest-worker": "^24.9.0",
"json-stringify-pretty-compact": "^2.0.0",
"matter-tools": "^0.14.0",
"matter-wrap": "^0.2.0",
"mock-require": "^3.0.3",
"pathseg": "^1.2.0",
"poly-decomp": "^0.3.0",
"puppeteer-core": "^5.5.0",
"run-sequence": "^2.2.1",
"webpack": "^4.44.2",
"terser-webpack-plugin": "^4.2.3",
"webpack": "^4.46.0",
"webpack-bundle-analyzer": "^4.4.0",
"webpack-cli": "^3.3.11",
"webpack-dev-server": "^3.11.0"
"webpack-dev-server": "^3.11.1"
},
"scripts": {
"dev": "webpack-dev-server --watch-content-base",
"build": "webpack --mode=production & webpack --mode=production --env.MINIMIZE",
"build-alpha": "webpack --mode=production --env.ALPHA & webpack --mode=production --env.MINIMIZE --env.ALPHA",
"build-examples": "webpack --config webpack.examples.config.js --mode=production & webpack --config webpack.examples.config.js --mode=production --env.MINIMIZE",
"build-examples-alpha": "webpack --config webpack.examples.config.js --mode=production --env.ALPHA & webpack --config webpack.examples.config.js --mode=production --env.MINIMIZE --env.ALPHA",
"lint": "eslint 'src/**/*.js' 'demo/js/Demo.js' 'demo/js/Compare.js' 'examples/*.js' 'webpack.*.js'",
"start": "npm run dev",
"dev": "npm run serve -- --open",
"serve": "webpack-dev-server --no-cache --mode development --config webpack.demo.config.js",
"watch": "nodemon --watch webpack.demo.config.js --exec \"npm run serve\"",
"build": "webpack --mode=production --no-hot --no-watch & webpack --mode=production --no-hot --no-watch --env.MINIMIZE",
"build-alpha": "webpack --mode=production --no-hot --no-watch --env.KIND=alpha & webpack --mode=production --no-hot --no-watch --env.MINIMIZE --env.KIND=alpha",
"build-dev": "webpack --mode=production --no-hot --no-watch --env.KIND=dev & webpack --mode=production --no-hot --no-watch --env.MINIMIZE --env.KIND=dev",
"build-demo": "rm -rf ./demo/js && webpack --no-hot --no-watch --config webpack.demo.config.js --mode=production && webpack --no-hot --no-watch --config webpack.demo.config.js --mode=production --env.MINIMIZE",
"lint": "eslint 'src/**/*.js' 'demo/src/**/*.js' 'examples/*.js' 'webpack.*.js'",
"doc": "yuidoc --config yuidoc.json --project-version $npm_package_version",
"doc-watch": "nodemon --delay 3 --watch 'matter-doc-theme' --watch src -e 'js,html,css,handlebars' --exec 'npm run doc'",
"benchmark": "EXAMPLES=stress3 npm run test-node",
"test": "npm run test-node",
"test-all": "jest",
"test-node": "npm run build-dev && node --expose-gc node_modules/.bin/jest --force-exit --no-cache --runInBand ./test/Examples.spec.js",
"test-browser": "node --expose-gc node_modules/.bin/jest --force-exit --no-cache --runInBand ./test/Browser.spec.js",
"test-all": "npm run test-node && npm run test-browser",
"test-save": "SAVE=true npm run test-node",
"test-watch": "npm run test-node -- --watch",
"test-node": "jest ./test/Examples.spec.js",
"test-browser": "jest ./test/Browser.spec.js",
"changelog": "conventional-changelog -i CHANGELOG.md -s -r",
"release": "npm version --no-git-tag-version",
"preversion": "git checkout master && npm run lint && SAVE=true npm run test-all",
"version": "git checkout -b release/$npm_package_version && npm run build"
},
"dependencies": {},
"files": [
"src",
"build",

View file

@ -1,8 +1,10 @@
/**
* 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`.
* A composite is a collection of `Matter.Body`, `Matter.Constraint` and other `Matter.Composite` objects.
*
* They are a container that can represent complex objects made of multiple parts, even if they are not physically connected.
* A composite could contain anything from a single body all the way up to a whole world.
*
* When making any changes to composites, use the included functions rather than changing their properties directly.
*
* See the included usage [examples](https://github.com/liabru/matter-js/tree/master/examples).
*
@ -37,7 +39,12 @@ var Body = require('./Body');
constraints: [],
composites: [],
label: 'Composite',
plugin: {}
plugin: {},
cache: {
allBodies: null,
allConstraints: null,
allComposites: null
}
}, options);
};
@ -45,6 +52,7 @@ var Body = require('./Body');
* Sets the composite's `isModified` flag.
* If `updateParents` is true, all parents will be set (default: false).
* If `updateChildren` is true, all children will be set (default: false).
* @private
* @method setModified
* @param {composite} composite
* @param {boolean} isModified
@ -54,12 +62,18 @@ var Body = require('./Body');
Composite.setModified = function(composite, isModified, updateParents, updateChildren) {
composite.isModified = isModified;
if (isModified && composite.cache) {
composite.cache.allBodies = null;
composite.cache.allConstraints = null;
composite.cache.allComposites = null;
}
if (updateParents && composite.parent) {
Composite.setModified(composite.parent, isModified, updateParents, updateChildren);
}
if (updateChildren) {
for(var i = 0; i < composite.composites.length; i++) {
for (var i = 0; i < composite.composites.length; i++) {
var childComposite = composite.composites[i];
Composite.setModified(childComposite, isModified, updateParents, updateChildren);
}
@ -67,11 +81,11 @@ var Body = require('./Body');
};
/**
* Generic add function. Adds one or many body(s), constraint(s) or a composite(s) to the given composite.
* Generic single or multi-add function. Adds a single or an array of body(s), constraint(s) or composite(s) to the given composite.
* Triggers `beforeAdd` and `afterAdd` events on the `composite`.
* @method add
* @param {composite} composite
* @param {} object
* @param {object|array} object A single or an array of body(s), constraint(s) or composite(s)
* @return {composite} The original composite with the objects added
*/
Composite.add = function(composite, object) {
@ -117,7 +131,7 @@ var Body = require('./Body');
* Triggers `beforeRemove` and `afterRemove` events on the `composite`.
* @method remove
* @param {composite} composite
* @param {} object
* @param {object|array} object
* @param {boolean} [deep=false]
* @return {composite} The original composite with the objects removed
*/
@ -180,7 +194,6 @@ var Body = require('./Body');
var position = Common.indexOf(compositeA.composites, compositeB);
if (position !== -1) {
Composite.removeCompositeAt(compositeA, position);
Composite.setModified(compositeA, true, true, false);
}
if (deep) {
@ -233,7 +246,6 @@ var Body = require('./Body');
var position = Common.indexOf(composite.bodies, body);
if (position !== -1) {
Composite.removeBodyAt(composite, position);
Composite.setModified(composite, true, true, false);
}
if (deep) {
@ -334,6 +346,7 @@ var Body = require('./Body');
composite.constraints.length = 0;
composite.composites.length = 0;
Composite.setModified(composite, true, true, false);
return composite;
@ -346,11 +359,19 @@ var Body = require('./Body');
* @return {body[]} All the bodies
*/
Composite.allBodies = function(composite) {
if (composite.cache && composite.cache.allBodies) {
return composite.cache.allBodies;
}
var bodies = [].concat(composite.bodies);
for (var i = 0; i < composite.composites.length; i++)
bodies = bodies.concat(Composite.allBodies(composite.composites[i]));
if (composite.cache) {
composite.cache.allBodies = bodies;
}
return bodies;
};
@ -361,11 +382,19 @@ var Body = require('./Body');
* @return {constraint[]} All the constraints
*/
Composite.allConstraints = function(composite) {
if (composite.cache && composite.cache.allConstraints) {
return composite.cache.allConstraints;
}
var constraints = [].concat(composite.constraints);
for (var i = 0; i < composite.composites.length; i++)
constraints = constraints.concat(Composite.allConstraints(composite.composites[i]));
if (composite.cache) {
composite.cache.allConstraints = constraints;
}
return constraints;
};
@ -376,11 +405,19 @@ var Body = require('./Body');
* @return {composite[]} All the composites
*/
Composite.allComposites = function(composite) {
if (composite.cache && composite.cache.allComposites) {
return composite.cache.allComposites;
}
var composites = [].concat(composite.composites);
for (var i = 0; i < composite.composites.length; i++)
composites = composites.concat(Composite.allComposites(composite.composites[i]));
if (composite.cache) {
composite.cache.allComposites = composites;
}
return composites;
};
@ -447,8 +484,6 @@ var Body = require('./Body');
objects[i].id = Common.nextId();
}
Composite.setModified(composite, true, true, false);
return composite;
};
@ -467,8 +502,6 @@ var Body = require('./Body');
Body.translate(bodies[i], translation);
}
Composite.setModified(composite, true, true, false);
return composite;
};
@ -498,8 +531,6 @@ var Body = require('./Body');
Body.rotate(body, rotation);
}
Composite.setModified(composite, true, true, false);
return composite;
};
@ -528,8 +559,6 @@ var Body = require('./Body');
Body.scale(body, scaleX, scaleY);
}
Composite.setModified(composite, true, true, false);
return composite;
};
@ -629,8 +658,7 @@ var Body = require('./Body');
/**
* 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.
* This is automatically managed when bodies, constraints or composites are added or removed.
*
* @property isModified
* @type boolean
@ -682,4 +710,13 @@ var Body = require('./Body');
* @type {}
*/
/**
* An object used for storing cached results for performance reasons.
* This is used internally only and is automatically managed.
*
* @private
* @property cache
* @type {}
*/
})();

View file

@ -1,14 +1,15 @@
/**
* 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.
* This module has now been replaced by `Matter.Composite`.
*
* See the included usage [examples](https://github.com/liabru/matter-js/tree/master/examples).
* All usage should be migrated to the equivalent functions found on `Matter.Composite`.
* For example `World.add(world, body)` now becomes `Composite.add(world, body)`.
*
* The property `world.gravity` has been moved to `engine.gravity`.
*
* For back-compatibility purposes this module will remain as a direct alias to `Matter.Composite` in the short term during migration.
* Eventually this alias module will be marked as deprecated and then later removed in a future release.
*
* @class World
* @extends Composite
*/
var World = {};
@ -16,132 +17,19 @@ var World = {};
module.exports = World;
var Composite = require('./Composite');
var Constraint = require('../constraint/Constraint');
var Common = require('../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
* See above, aliases for back compatibility only
*/
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
*/
World.create = Composite.create;
World.add = Composite.add;
World.remove = Composite.remove;
World.clear = Composite.clear;
World.addComposite = Composite.addComposite;
World.addBody = Composite.addBody;
World.addConstraint = Composite.addConstraint;
})();

408
src/collision/Collision.js Normal file
View file

@ -0,0 +1,408 @@
/**
* The `Matter.Collision` module contains methods for detecting collisions between a given pair of bodies.
*
* For efficient detection between a list of bodies, see `Matter.Detector` and `Matter.Query`.
*
* See `Matter.Engine` for collision events.
*
* @class Collision
*/
var Collision = {};
module.exports = Collision;
var Vertices = require('../geometry/Vertices');
var Pair = require('./Pair');
(function() {
var _supports = [];
var _overlapAB = {
overlap: 0,
axis: null
};
var _overlapBA = {
overlap: 0,
axis: null
};
/**
* Creates a new collision record.
* @method create
* @param {body} bodyA The first body part represented by the collision record
* @param {body} bodyB The second body part represented by the collision record
* @return {collision} A new collision record
*/
Collision.create = function(bodyA, bodyB) {
return {
pair: null,
collided: false,
bodyA: bodyA,
bodyB: bodyB,
parentA: bodyA.parent,
parentB: bodyB.parent,
depth: 0,
normal: { x: 0, y: 0 },
tangent: { x: 0, y: 0 },
penetration: { x: 0, y: 0 },
supports: []
};
};
/**
* Detect collision between two bodies.
* @method collides
* @param {body} bodyA
* @param {body} bodyB
* @param {pairs} [pairs] Optionally reuse collision records from existing pairs.
* @return {collision|null} A collision record if detected, otherwise null
*/
Collision.collides = function(bodyA, bodyB, pairs) {
Collision._overlapAxes(_overlapAB, bodyA.vertices, bodyB.vertices, bodyA.axes);
if (_overlapAB.overlap <= 0) {
return null;
}
Collision._overlapAxes(_overlapBA, bodyB.vertices, bodyA.vertices, bodyB.axes);
if (_overlapBA.overlap <= 0) {
return null;
}
// reuse collision records for gc efficiency
var pair = pairs && pairs.table[Pair.id(bodyA, bodyB)],
collision;
if (!pair) {
collision = Collision.create(bodyA, bodyB);
collision.collided = true;
collision.bodyA = bodyA.id < bodyB.id ? bodyA : bodyB;
collision.bodyB = bodyA.id < bodyB.id ? bodyB : bodyA;
collision.parentA = collision.bodyA.parent;
collision.parentB = collision.bodyB.parent;
} else {
collision = pair.collision;
}
bodyA = collision.bodyA;
bodyB = collision.bodyB;
var minOverlap;
if (_overlapAB.overlap < _overlapBA.overlap) {
minOverlap = _overlapAB;
} else {
minOverlap = _overlapBA;
}
var normal = collision.normal,
supports = collision.supports,
minAxis = minOverlap.axis,
minAxisX = minAxis.x,
minAxisY = minAxis.y;
// ensure normal is facing away from bodyA
if (minAxisX * (bodyB.position.x - bodyA.position.x) + minAxisY * (bodyB.position.y - bodyA.position.y) < 0) {
normal.x = minAxisX;
normal.y = minAxisY;
} else {
normal.x = -minAxisX;
normal.y = -minAxisY;
}
collision.tangent.x = -normal.y;
collision.tangent.y = normal.x;
collision.depth = minOverlap.overlap;
collision.penetration.x = normal.x * collision.depth;
collision.penetration.y = normal.y * collision.depth;
// find support points, there is always either exactly one or two
var supportsB = Collision._findSupports(bodyA, bodyB, normal, 1),
supportCount = 0;
// find the supports from bodyB that are inside bodyA
if (Vertices.contains(bodyA.vertices, supportsB[0])) {
supports[supportCount++] = supportsB[0];
}
if (Vertices.contains(bodyA.vertices, supportsB[1])) {
supports[supportCount++] = supportsB[1];
}
// find the supports from bodyA that are inside bodyB
if (supportCount < 2) {
var supportsA = Collision._findSupports(bodyB, bodyA, normal, -1);
if (Vertices.contains(bodyB.vertices, supportsA[0])) {
supports[supportCount++] = supportsA[0];
}
if (supportCount < 2 && Vertices.contains(bodyB.vertices, supportsA[1])) {
supports[supportCount++] = supportsA[1];
}
}
// account for the edge case of overlapping but no vertex containment
if (supportCount === 0) {
supports[supportCount++] = supportsB[0];
}
// update supports array size
supports.length = supportCount;
return collision;
};
/**
* Find the overlap between two sets of vertices.
* @method _overlapAxes
* @private
* @param {object} result
* @param {vertices} verticesA
* @param {vertices} verticesB
* @param {axes} axes
*/
Collision._overlapAxes = function(result, verticesA, verticesB, axes) {
var verticesALength = verticesA.length,
verticesBLength = verticesB.length,
verticesAX = verticesA[0].x,
verticesAY = verticesA[0].y,
verticesBX = verticesB[0].x,
verticesBY = verticesB[0].y,
axesLength = axes.length,
overlapMin = Number.MAX_VALUE,
overlapAxisNumber = 0,
overlap,
overlapAB,
overlapBA,
dot,
i,
j;
for (i = 0; i < axesLength; i++) {
var axis = axes[i],
axisX = axis.x,
axisY = axis.y,
minA = verticesAX * axisX + verticesAY * axisY,
minB = verticesBX * axisX + verticesBY * axisY,
maxA = minA,
maxB = minB;
for (j = 1; j < verticesALength; j += 1) {
dot = verticesA[j].x * axisX + verticesA[j].y * axisY;
if (dot > maxA) {
maxA = dot;
} else if (dot < minA) {
minA = dot;
}
}
for (j = 1; j < verticesBLength; j += 1) {
dot = verticesB[j].x * axisX + verticesB[j].y * axisY;
if (dot > maxB) {
maxB = dot;
} else if (dot < minB) {
minB = dot;
}
}
overlapAB = maxA - minB;
overlapBA = maxB - minA;
overlap = overlapAB < overlapBA ? overlapAB : overlapBA;
if (overlap < overlapMin) {
overlapMin = overlap;
overlapAxisNumber = i;
if (overlap <= 0) {
// can not be intersecting
break;
}
}
}
result.axis = axes[overlapAxisNumber];
result.overlap = overlapMin;
};
/**
* Projects vertices on an axis and returns an interval.
* @method _projectToAxis
* @private
* @param {} projection
* @param {} vertices
* @param {} axis
*/
Collision._projectToAxis = function(projection, vertices, axis) {
var min = vertices[0].x * axis.x + vertices[0].y * axis.y,
max = min;
for (var i = 1; i < vertices.length; i += 1) {
var dot = vertices[i].x * axis.x + vertices[i].y * axis.y;
if (dot > max) {
max = dot;
} else if (dot < min) {
min = dot;
}
}
projection.min = min;
projection.max = max;
};
/**
* Finds supporting vertices given two bodies along a given direction using hill-climbing.
* @method _findSupports
* @private
* @param {body} bodyA
* @param {body} bodyB
* @param {vector} normal
* @param {number} direction
* @return [vector]
*/
Collision._findSupports = function(bodyA, bodyB, normal, direction) {
var vertices = bodyB.vertices,
verticesLength = vertices.length,
bodyAPositionX = bodyA.position.x,
bodyAPositionY = bodyA.position.y,
normalX = normal.x * direction,
normalY = normal.y * direction,
nearestDistance = Number.MAX_VALUE,
vertexA,
vertexB,
vertexC,
distance,
j;
// find deepest vertex relative to the axis
for (j = 0; j < verticesLength; j += 1) {
vertexB = vertices[j];
distance = normalX * (bodyAPositionX - vertexB.x) + normalY * (bodyAPositionY - vertexB.y);
// convex hill-climbing
if (distance < nearestDistance) {
nearestDistance = distance;
vertexA = vertexB;
}
}
// measure next vertex
vertexC = vertices[(verticesLength + vertexA.index - 1) % verticesLength];
nearestDistance = normalX * (bodyAPositionX - vertexC.x) + normalY * (bodyAPositionY - vertexC.y);
// compare with previous vertex
vertexB = vertices[(vertexA.index + 1) % verticesLength];
if (normalX * (bodyAPositionX - vertexB.x) + normalY * (bodyAPositionY - vertexB.y) < nearestDistance) {
_supports[0] = vertexA;
_supports[1] = vertexB;
return _supports;
}
_supports[0] = vertexA;
_supports[1] = vertexC;
return _supports;
};
/*
*
* Properties Documentation
*
*/
/**
* A reference to the pair using this collision record, if there is one.
*
* @property pair
* @type {pair|null}
* @default null
*/
/**
* A flag that indicates if the bodies were colliding when the collision was last updated.
*
* @property collided
* @type boolean
* @default false
*/
/**
* The first body part represented by the collision (see also `collision.parentA`).
*
* @property bodyA
* @type body
*/
/**
* The second body part represented by the collision (see also `collision.parentB`).
*
* @property bodyB
* @type body
*/
/**
* The first body represented by the collision (i.e. `collision.bodyA.parent`).
*
* @property parentA
* @type body
*/
/**
* The second body represented by the collision (i.e. `collision.bodyB.parent`).
*
* @property parentB
* @type body
*/
/**
* A `Number` that represents the minimum separating distance between the bodies along the collision normal.
*
* @readOnly
* @property depth
* @type number
* @default 0
*/
/**
* A normalised `Vector` that represents the direction between the bodies that provides the minimum separating distance.
*
* @property normal
* @type vector
* @default { x: 0, y: 0 }
*/
/**
* A normalised `Vector` that is the tangent direction to the collision normal.
*
* @property tangent
* @type vector
* @default { x: 0, y: 0 }
*/
/**
* A `Vector` that represents the direction and depth of the collision.
*
* @property penetration
* @type vector
* @default { x: 0, y: 0 }
*/
/**
* An array of body vertices that represent the support points in the collision.
* These are the deepest vertices (along the collision normal) of each body that are contained by the other body's vertices.
*
* @property supports
* @type vector[]
* @default []
*/
})();

View file

@ -18,21 +18,10 @@ module.exports = 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;
};
})();

View file

@ -1,85 +1,132 @@
/**
* The `Matter.Detector` module contains methods for detecting collisions given a set of pairs.
* The `Matter.Detector` module contains methods for efficiently detecting collisions between a list of bodies using a broadphase algorithm.
*
* @class Detector
*/
// TODO: speculative contacts
var Detector = {};
module.exports = Detector;
var SAT = require('./SAT');
var Pair = require('./Pair');
var Bounds = require('../geometry/Bounds');
var Common = require('../core/Common');
var Collision = require('./Collision');
(function() {
/**
* Finds all collisions given a list of pairs.
* @method collisions
* @param {pair[]} broadphasePairs
* @param {engine} engine
* @param {number} delta
* @return {array} collisions
* Creates a new collision detector.
* @method create
* @param {} options
* @return {detector} A new collision detector
*/
Detector.collisions = function(broadphasePairs, engine, delta) {
Detector.create = function(options) {
var defaults = {
bodies: [],
pairs: null
};
return Common.extend(defaults, options);
};
/**
* Sets the list of bodies in the detector.
* @method setBodies
* @param {detector} detector
* @param {body[]} bodies
*/
Detector.setBodies = function(detector, bodies) {
detector.bodies = bodies.slice(0);
};
/**
* Clears the detector including its list of bodies.
* @method clear
* @param {detector} detector
*/
Detector.clear = function(detector) {
detector.bodies = [];
};
/**
* Efficiently finds all collisions among all the bodies in `detector.bodies` using a broadphase algorithm.
*
* _Note:_ The specific ordering of collisions returned is not guaranteed between releases and may change for performance reasons.
* If a specific ordering is required then apply a sort to the resulting array.
* @method collisions
* @param {detector} detector
* @return {collision[]} collisions
*/
Detector.collisions = function(detector) {
var collisions = [],
pairsTable = engine.pairs.table;
pairs = detector.pairs,
bodies = detector.bodies,
bodiesLength = bodies.length,
canCollide = Detector.canCollide,
collides = Collision.collides,
i,
j;
// @if DEBUG
var metrics = engine.metrics;
// @endif
bodies.sort(Detector._compareBoundsX);
for (var i = 0; i < broadphasePairs.length; i++) {
var bodyA = broadphasePairs[i][0],
bodyB = broadphasePairs[i][1];
for (i = 0; i < bodiesLength; i++) {
var bodyA = bodies[i],
boundsA = bodyA.bounds,
boundXMax = bodyA.bounds.max.x,
boundYMax = bodyA.bounds.max.y,
boundYMin = bodyA.bounds.min.y,
bodyAStatic = bodyA.isStatic || bodyA.isSleeping,
partsALength = bodyA.parts.length,
partsASingle = partsALength === 1;
if ((bodyA.isStatic || bodyA.isSleeping) && (bodyB.isStatic || bodyB.isSleeping))
continue;
for (j = i + 1; j < bodiesLength; j++) {
var bodyB = bodies[j],
boundsB = bodyB.bounds;
if (!Detector.canCollide(bodyA.collisionFilter, bodyB.collisionFilter))
continue;
if (boundsB.min.x > boundXMax) {
break;
}
// @if DEBUG
metrics.midphaseTests += 1;
// @endif
if (boundYMax < boundsB.min.y || boundYMin > boundsB.max.y) {
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];
if (bodyAStatic && (bodyB.isStatic || bodyB.isSleeping)) {
continue;
}
for (var k = bodyB.parts.length > 1 ? 1 : 0; k < bodyB.parts.length; k++) {
var partB = bodyB.parts[k];
if (!canCollide(bodyA.collisionFilter, bodyB.collisionFilter)) {
continue;
}
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;
var partsBLength = bodyB.parts.length;
if (pair && pair.isActive) {
previousCollision = pair.collision;
} else {
previousCollision = null;
if (partsASingle && partsBLength === 1) {
var collision = collides(bodyA, bodyB, pairs);
if (collision) {
collisions.push(collision);
}
} else {
var partsAStart = partsALength > 1 ? 1 : 0,
partsBStart = partsBLength > 1 ? 1 : 0;
for (var k = partsAStart; k < partsALength; k++) {
var partA = bodyA.parts[k],
boundsA = partA.bounds;
for (var z = partsBStart; z < partsBLength; z++) {
var partB = bodyB.parts[z],
boundsB = partB.bounds;
if (boundsA.min.x > boundsB.max.x || boundsA.max.x < boundsB.min.x
|| boundsA.max.y < boundsB.min.y || boundsA.min.y > boundsB.max.y) {
continue;
}
// narrow phase
var collision = SAT.collides(partA, partB, previousCollision, delta);
var collision = collides(partA, partB, pairs);
// @if DEBUG
metrics.narrowphaseTests += 1;
if (collision.reused)
metrics.narrowReuseCount += 1;
// @endif
if (collision.collided) {
if (collision) {
collisions.push(collision);
// @if DEBUG
metrics.narrowDetections += 1;
// @endif
}
}
}
@ -105,4 +152,39 @@ var Bounds = require('../geometry/Bounds');
return (filterA.mask & filterB.category) !== 0 && (filterB.mask & filterA.category) !== 0;
};
/**
* The comparison function used in the broadphase algorithm.
* Returns the signed delta of the bodies bounds on the x-axis.
* @private
* @method _sortCompare
* @param {body} bodyA
* @param {body} bodyB
* @return {number} The signed delta used for sorting
*/
Detector._compareBoundsX = function(bodyA, bodyB) {
return bodyA.bounds.min.x - bodyB.bounds.min.x;
};
/*
*
* Properties Documentation
*
*/
/**
* The array of `Matter.Body` between which the detector finds collisions.
*
* _Note:_ The order of bodies in this array _is not fixed_ and will be continually managed by the detector.
* @property bodies
* @type body[]
* @default []
*/
/**
* Optional. A `Matter.Pairs` object from which previous collision objects may be reused. Intended for internal `Matter.Engine` usage.
* @property pairs
* @type {pairs|null}
* @default null
*/
})();

View file

@ -1,7 +1,13 @@
/**
* This module has now been replaced by `Matter.Detector`.
*
* All usage should be migrated to `Matter.Detector` or another alternative.
* For back-compatibility purposes this module will remain for a short term and then later removed in a future release.
*
* The `Matter.Grid` module contains methods for creating and manipulating collision broadphase grid structures.
*
* @class Grid
* @deprecated
*/
var Grid = {};
@ -9,21 +15,20 @@ var Grid = {};
module.exports = Grid;
var Pair = require('./Pair');
var Detector = require('./Detector');
var Common = require('../core/Common');
var deprecated = Common.deprecated;
(function() {
/**
* Creates a new grid.
* @deprecated replaced by Matter.Detector
* @method create
* @param {} options
* @return {grid} A new grid
*/
Grid.create = function(options) {
var defaults = {
controller: Grid,
detector: Detector.collisions,
buckets: {},
pairs: {},
pairsList: [],
@ -52,6 +57,7 @@ var Common = require('../core/Common');
/**
* Updates the grid.
* @deprecated replaced by Matter.Detector
* @method update
* @param {grid} grid
* @param {body[]} bodies
@ -66,20 +72,15 @@ var Common = require('../core/Common');
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)
// temporary back compatibility bounds check
if (world.bounds && (body.bounds.max.x < world.bounds.min.x || body.bounds.min.x > world.bounds.max.x
|| body.bounds.max.y < world.bounds.min.y || body.bounds.min.y > world.bounds.max.y))
continue;
var newRegion = Grid._getRegion(grid, body);
@ -87,10 +88,6 @@ var Common = require('../core/Common');
// 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;
@ -139,8 +136,11 @@ var Common = require('../core/Common');
grid.pairsList = Grid._createActivePairsList(grid);
};
deprecated(Grid, 'update', 'Grid.update ➤ replaced by Matter.Detector');
/**
* Clears the grid.
* @deprecated replaced by Matter.Detector
* @method clear
* @param {grid} grid
*/
@ -150,9 +150,12 @@ var Common = require('../core/Common');
grid.pairsList = [];
};
deprecated(Grid, 'clear', 'Grid.clear ➤ replaced by Matter.Detector');
/**
* Finds the union of two regions.
* @method _regionUnion
* @deprecated replaced by Matter.Detector
* @private
* @param {} regionA
* @param {} regionB
@ -170,6 +173,7 @@ var Common = require('../core/Common');
/**
* Gets the region a given body falls in for a given grid.
* @method _getRegion
* @deprecated replaced by Matter.Detector
* @private
* @param {} grid
* @param {} body
@ -188,6 +192,7 @@ var Common = require('../core/Common');
/**
* Creates a region.
* @method _createRegion
* @deprecated replaced by Matter.Detector
* @private
* @param {} startCol
* @param {} endCol
@ -208,6 +213,7 @@ var Common = require('../core/Common');
/**
* Gets the bucket id at the given position.
* @method _getBucketId
* @deprecated replaced by Matter.Detector
* @private
* @param {} column
* @param {} row
@ -220,6 +226,7 @@ var Common = require('../core/Common');
/**
* Creates a bucket.
* @method _createBucket
* @deprecated replaced by Matter.Detector
* @private
* @param {} buckets
* @param {} bucketId
@ -233,14 +240,20 @@ var Common = require('../core/Common');
/**
* Adds a body to a bucket.
* @method _bucketAddBody
* @deprecated replaced by Matter.Detector
* @private
* @param {} grid
* @param {} bucket
* @param {} body
*/
Grid._bucketAddBody = function(grid, bucket, body) {
var gridPairs = grid.pairs,
pairId = Pair.id,
bucketLength = bucket.length,
i;
// add new pairs
for (var i = 0; i < bucket.length; i++) {
for (i = 0; i < bucketLength; i++) {
var bodyB = bucket[i];
if (body.id === bodyB.id || (body.isStatic && bodyB.isStatic))
@ -248,13 +261,13 @@ var Common = require('../core/Common');
// 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];
var id = pairId(body, bodyB),
pair = gridPairs[id];
if (pair) {
pair[2] += 1;
} else {
grid.pairs[pairId] = [body, bodyB, 1];
gridPairs[id] = [body, bodyB, 1];
}
}
@ -265,22 +278,27 @@ var Common = require('../core/Common');
/**
* Removes a body from a bucket.
* @method _bucketRemoveBody
* @deprecated replaced by Matter.Detector
* @private
* @param {} grid
* @param {} bucket
* @param {} body
*/
Grid._bucketRemoveBody = function(grid, bucket, body) {
var gridPairs = grid.pairs,
pairId = Pair.id,
i;
// remove from bucket
bucket.splice(Common.indexOf(bucket, body), 1);
var bucketLength = bucket.length;
// update pair counts
for (var i = 0; i < bucket.length; i++) {
for (i = 0; i < bucketLength; 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];
var pair = gridPairs[pairId(body, bucket[i])];
if (pair)
pair[2] -= 1;
@ -290,28 +308,29 @@ var Common = require('../core/Common');
/**
* Generates a list of the active pairs in the grid.
* @method _createActivePairsList
* @deprecated replaced by Matter.Detector
* @private
* @param {} grid
* @return [] pairs
*/
Grid._createActivePairsList = function(grid) {
var pairKeys,
pair,
pairs = [];
// grid.pairs is used as a hashmap
pairKeys = Common.keys(grid.pairs);
var pair,
gridPairs = grid.pairs,
pairKeys = Common.keys(gridPairs),
pairKeysLength = pairKeys.length,
pairs = [],
k;
// iterate over grid.pairs
for (var k = 0; k < pairKeys.length; k++) {
pair = grid.pairs[pairKeys[k]];
for (k = 0; k < pairKeysLength; k++) {
pair = gridPairs[pairKeys[k]];
// if pair exists in at least one bucket
// it is a pair that needs further collision testing so push it
if (pair[2] > 0) {
pairs.push(pair);
} else {
delete grid.pairs[pairKeys[k]];
delete gridPairs[pairKeys[k]];
}
}

View file

@ -21,15 +21,14 @@ var Contact = require('./Contact');
*/
Pair.create = function(collision, timestamp) {
var bodyA = collision.bodyA,
bodyB = collision.bodyB,
parentA = collision.parentA,
parentB = collision.parentB;
bodyB = collision.bodyB;
var pair = {
id: Pair.id(bodyA, bodyB),
bodyA: bodyA,
bodyB: bodyB,
contacts: {},
collision: collision,
contacts: [],
activeContacts: [],
separation: 0,
isActive: true,
@ -37,11 +36,11 @@ var Contact = require('./Contact');
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)
inverseMass: 0,
friction: 0,
frictionStatic: 0,
restitution: 0,
slop: 0
};
Pair.update(pair, collision, timestamp);
@ -61,34 +60,32 @@ var Contact = require('./Contact');
supports = collision.supports,
activeContacts = pair.activeContacts,
parentA = collision.parentA,
parentB = collision.parentB;
parentB = collision.parentB,
parentAVerticesLength = parentA.vertices.length;
pair.isActive = true;
pair.timeUpdated = timestamp;
pair.collision = collision;
pair.separation = collision.depth;
pair.inverseMass = parentA.inverseMass + parentB.inverseMass;
pair.friction = 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);
pair.friction = parentA.friction < parentB.friction ? parentA.friction : parentB.friction;
pair.frictionStatic = parentA.frictionStatic > parentB.frictionStatic ? parentA.frictionStatic : parentB.frictionStatic;
pair.restitution = parentA.restitution > parentB.restitution ? parentA.restitution : parentB.restitution;
pair.slop = parentA.slop > parentB.slop ? parentA.slop : parentB.slop;
collision.pair = pair;
activeContacts.length = 0;
if (collision.collided) {
for (var i = 0; i < supports.length; i++) {
var support = supports[i],
contactId = Contact.id(support),
contact = contacts[contactId];
for (var i = 0; i < supports.length; i++) {
var support = supports[i],
contactId = support.body === parentA ? support.index : parentAVerticesLength + support.index,
contact = contacts[contactId];
if (contact) {
activeContacts.push(contact);
} else {
activeContacts.push(contacts[contactId] = Contact.create(support));
}
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);
}
};

View file

@ -13,8 +13,6 @@ var Common = require('../core/Common');
(function() {
Pairs._pairMaxIdleLife = 1000;
/**
* Creates a new pairs structure.
* @method create
@ -40,12 +38,14 @@ var Common = require('../core/Common');
*/
Pairs.update = function(pairs, collisions, timestamp) {
var pairsList = pairs.list,
pairsListLength = pairsList.length,
pairsTable = pairs.table,
collisionsLength = collisions.length,
collisionStart = pairs.collisionStart,
collisionEnd = pairs.collisionEnd,
collisionActive = pairs.collisionActive,
collision,
pairId,
pairIndex,
pair,
i;
@ -54,90 +54,61 @@ var Common = require('../core/Common');
collisionEnd.length = 0;
collisionActive.length = 0;
for (i = 0; i < pairsList.length; i++) {
for (i = 0; i < pairsListLength; i++) {
pairsList[i].confirmedActive = false;
}
for (i = 0; i < collisions.length; i++) {
for (i = 0; i < collisionsLength; i++) {
collision = collisions[i];
pair = collision.pair;
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;
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 did not exist, create a new pair
pair = Pair.create(collision, timestamp);
pairsTable[pairId] = pair;
// push the new pair
// pair exists but was inactive, so a collision has just started again
collisionStart.push(pair);
pairsList.push(pair);
}
// update the pair
Pair.update(pair, collision, timestamp);
pair.confirmedActive = true;
} else {
// pair did not exist, create a new pair
pair = Pair.create(collision, timestamp);
pairsTable[pair.id] = pair;
// push the new pair
collisionStart.push(pair);
pairsList.push(pair);
}
}
// find pairs that are no longer active
var removePairIndex = [];
pairsListLength = pairsList.length;
for (i = 0; i < pairsListLength; i++) {
pair = pairsList[i];
if (!pair.confirmedActive) {
Pair.setActive(pair, false, timestamp);
collisionEnd.push(pair);
if (!pair.collision.bodyA.isSleeping && !pair.collision.bodyB.isSleeping) {
removePairIndex.push(i);
}
}
}
// 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;
// remove inactive pairs
for (i = 0; i < removePairIndex.length; i++) {
pairIndex = removePairIndex[i] - i;
pair = pairsList[pairIndex];
delete pairsTable[pair.id];
pairsList.splice(pairIndex, 1);
delete pairsTable[pair.id];
}
};

View file

@ -11,7 +11,7 @@ var Query = {};
module.exports = Query;
var Vector = require('../geometry/Vector');
var SAT = require('./SAT');
var Collision = require('./Collision');
var Bounds = require('../geometry/Bounds');
var Bodies = require('../factory/Bodies');
var Vertices = require('../geometry/Vertices');
@ -23,22 +23,28 @@ var Vertices = require('../geometry/Vertices');
* @method collides
* @param {body} body
* @param {body[]} bodies
* @return {object[]} Collisions
* @return {collision[]} Collisions
*/
Query.collides = function(body, bodies) {
var collisions = [];
var collisions = [],
bodiesLength = bodies.length,
bounds = body.bounds,
collides = Collision.collides,
overlaps = Bounds.overlaps;
for (var i = 0; i < bodies.length; i++) {
var bodyA = bodies[i];
for (var i = 0; i < bodiesLength; i++) {
var bodyA = bodies[i],
partsALength = bodyA.parts.length,
partsAStart = partsALength === 1 ? 0 : 1;
if (Bounds.overlaps(bodyA.bounds, body.bounds)) {
for (var j = bodyA.parts.length === 1 ? 0 : 1; j < bodyA.parts.length; j++) {
if (overlaps(bodyA.bounds, bounds)) {
for (var j = partsAStart; j < partsALength; j++) {
var part = bodyA.parts[j];
if (Bounds.overlaps(part.bounds, body.bounds)) {
var collision = SAT.collides(part, body);
if (overlaps(part.bounds, bounds)) {
var collision = collides(part, body);
if (collision.collided) {
if (collision) {
collisions.push(collision);
break;
}
@ -57,7 +63,7 @@ var Vertices = require('../geometry/Vertices');
* @param {vector} startPoint
* @param {vector} endPoint
* @param {number} [rayWidth]
* @return {object[]} Collisions
* @return {collision[]} Collisions
*/
Query.ray = function(bodies, startPoint, endPoint, rayWidth) {
rayWidth = rayWidth || 1e-100;

View file

@ -29,10 +29,11 @@ var Bounds = require('../geometry/Bounds');
Resolver.preSolvePosition = function(pairs) {
var i,
pair,
activeCount;
activeCount,
pairsLength = pairs.length;
// find total contacts on each body
for (i = 0; i < pairs.length; i++) {
for (i = 0; i < pairsLength; i++) {
pair = pairs[i];
if (!pair.isActive)
@ -57,18 +58,15 @@ var Bounds = require('../geometry/Bounds');
bodyA,
bodyB,
normal,
bodyBtoA,
contactShare,
positionImpulse,
timeScale = delta / Common._timeUnit,
damping = Common.clamp(Resolver._positionDampen * timeScale, 0, 1),
tempA = Vector._temp[0],
tempB = Vector._temp[1],
tempC = Vector._temp[2],
tempD = Vector._temp[3];
positionDampen = Resolver._positionDampen,
pairsLength = pairs.length;
// find impulses required to resolve penetration
for (i = 0; i < pairs.length; i++) {
for (i = 0; i < pairsLength; i++) {
pair = pairs[i];
if (!pair.isActive || pair.isSensor)
@ -80,14 +78,12 @@ var Bounds = require('../geometry/Bounds');
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);
pair.separation =
normal.x * (bodyB.positionImpulse.x + collision.penetration.x - bodyA.positionImpulse.x)
+ normal.y * (bodyB.positionImpulse.y + collision.penetration.y - bodyA.positionImpulse.y);
}
for (i = 0; i < pairs.length; i++) {
for (i = 0; i < pairsLength; i++) {
pair = pairs[i];
if (!pair.isActive || pair.isSensor)
@ -103,13 +99,13 @@ var Bounds = require('../geometry/Bounds');
positionImpulse *= 2;
if (!(bodyA.isStatic || bodyA.isSleeping)) {
contactShare = Resolver._positionDampen / bodyA.totalContacts;
contactShare = 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;
contactShare = positionDampen / bodyB.totalContacts;
bodyB.positionImpulse.x -= normal.x * positionImpulse * contactShare;
bodyB.positionImpulse.y -= normal.y * positionImpulse * contactShare;
}
@ -122,34 +118,43 @@ var Bounds = require('../geometry/Bounds');
* @param {body[]} bodies
*/
Resolver.postSolvePosition = function(bodies) {
for (var i = 0; i < bodies.length; i++) {
var body = bodies[i];
var positionWarming = Resolver._positionWarming,
bodiesLength = bodies.length,
verticesTranslate = Vertices.translate,
boundsUpdate = Bounds.update;
for (var i = 0; i < bodiesLength; i++) {
var body = bodies[i],
positionImpulse = body.positionImpulse,
positionImpulseX = positionImpulse.x,
positionImpulseY = positionImpulse.y,
velocity = body.velocity;
// reset contact count
body.totalContacts = 0;
if (body.positionImpulse.x !== 0 || body.positionImpulse.y !== 0) {
if (positionImpulseX !== 0 || positionImpulseY !== 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;
verticesTranslate(part.vertices, positionImpulse);
boundsUpdate(part.bounds, part.vertices, velocity);
part.position.x += positionImpulseX;
part.position.y += positionImpulseY;
}
// move the body without changing velocity
body.positionPrev.x += body.positionImpulse.x;
body.positionPrev.y += body.positionImpulse.y;
body.positionPrev.x += positionImpulseX;
body.positionPrev.y += positionImpulseY;
if (Vector.dot(body.positionImpulse, body.velocity) < 0) {
if (positionImpulseX * velocity.x + positionImpulseY * velocity.y < 0) {
// reset cached impulse if the body has velocity along it
body.positionImpulse.x = 0;
body.positionImpulse.y = 0;
positionImpulse.x = 0;
positionImpulse.y = 0;
} else {
// warm the next iteration
body.positionImpulse.x *= Resolver._positionWarming;
body.positionImpulse.y *= Resolver._positionWarming;
positionImpulse.x *= positionWarming;
positionImpulse.y *= positionWarming;
}
}
}
@ -161,61 +166,53 @@ var Bounds = require('../geometry/Bounds');
* @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];
var pairsLength = pairs.length,
i,
j;
for (i = 0; i < pairs.length; i++) {
pair = pairs[i];
for (i = 0; i < pairsLength; i++) {
var 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;
var contacts = pair.activeContacts,
contactsLength = contacts.length,
collision = pair.collision,
bodyA = collision.parentA,
bodyB = collision.parentB,
normal = collision.normal,
tangent = collision.tangent;
// resolve each contact
for (j = 0; j < contacts.length; j++) {
contact = contacts[j];
contactVertex = contact.vertex;
normalImpulse = contact.normalImpulse;
tangentImpulse = contact.tangentImpulse;
for (j = 0; j < contactsLength; j++) {
var contact = contacts[j],
contactVertex = contact.vertex,
normalImpulse = contact.normalImpulse,
tangentImpulse = contact.tangentImpulse;
if (normalImpulse !== 0 || tangentImpulse !== 0) {
// total impulse from contact
impulse.x = (normal.x * normalImpulse) + (tangent.x * tangentImpulse);
impulse.y = (normal.y * normalImpulse) + (tangent.y * tangentImpulse);
var impulseX = normal.x * normalImpulse + tangent.x * tangentImpulse,
impulseY = 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;
bodyA.positionPrev.x += impulseX * bodyA.inverseMass;
bodyA.positionPrev.y += impulseY * bodyA.inverseMass;
bodyA.anglePrev += bodyA.inverseInertia * (
(contactVertex.x - bodyA.position.x) * impulseY
- (contactVertex.y - bodyA.position.y) * impulseX
);
}
if (!(bodyB.isStatic || bodyB.isSleeping)) {
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;
bodyB.positionPrev.x -= impulseX * bodyB.inverseMass;
bodyB.positionPrev.y -= impulseY * bodyB.inverseMass;
bodyB.anglePrev -= bodyB.inverseInertia * (
(contactVertex.x - bodyB.position.x) * impulseY
- (contactVertex.y - bodyB.position.y) * impulseX
);
}
}
}
@ -237,9 +234,19 @@ var Bounds = require('../geometry/Bounds');
tempB = Vector._temp[2],
tempC = Vector._temp[3],
tempD = Vector._temp[4],
tempE = Vector._temp[5];
tempE = Vector._temp[5],
timeScaleSquared = timeScale * timeScale,
restingThresh = Resolver._restingThresh * timeScaleSquared,
frictionNormalMultiplier = Resolver._frictionNormalMultiplier,
restingThreshTangent = Resolver._restingThreshTangent * timeScaleSquared,
NumberMaxValue = Number.MAX_VALUE,
pairsLength = pairs.length,
tangentImpulse,
maxFriction,
i,
j;
for (var i = 0; i < pairs.length; i++) {
for (i = 0; i < pairsLength; i++) {
var pair = pairs[i];
if (!pair.isActive || pair.isSensor)
@ -248,56 +255,84 @@ var Bounds = require('../geometry/Bounds');
var collision = pair.collision,
bodyA = collision.parentA,
bodyB = collision.parentB,
normal = collision.normal,
tangent = collision.tangent,
bodyAVelocity = bodyA.velocity,
bodyBVelocity = bodyB.velocity,
normalX = collision.normal.x,
normalY = collision.normal.y,
tangentX = collision.tangent.x,
tangentY = collision.tangent.y,
contacts = pair.activeContacts,
contactShare = 1 / contacts.length;
contactsLength = contacts.length,
contactShare = 1 / contactsLength,
inverseMassTotal = bodyA.inverseMass + bodyB.inverseMass,
friction = pair.friction * pair.frictionStatic * frictionNormalMultiplier * timeScaleSquared;
// 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;
bodyAVelocity.x = bodyA.position.x - bodyA.positionPrev.x;
bodyAVelocity.y = bodyA.position.y - bodyA.positionPrev.y;
bodyBVelocity.x = bodyB.position.x - bodyB.positionPrev.x;
bodyBVelocity.y = bodyB.position.y - bodyB.positionPrev.y;
bodyA.angularVelocity = bodyA.angle - bodyA.anglePrev;
bodyB.angularVelocity = bodyB.angle - bodyB.anglePrev;
// resolve each contact
for (var j = 0; j < contacts.length; j++) {
for (j = 0; j < contactsLength; 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);
contactVertex = contact.vertex;
var tangentVelocity = Vector.dot(tangent, relativeVelocity),
tangentSpeed = Math.abs(tangentVelocity),
tangentVelocityDirection = Common.sign(tangentVelocity);
var offsetAX = contactVertex.x - bodyA.position.x,
offsetAY = contactVertex.y - bodyA.position.y,
offsetBX = contactVertex.x - bodyB.position.x,
offsetBY = contactVertex.y - bodyB.position.y;
// raw impulses
var normalImpulse = (1 + pair.restitution) * normalVelocity,
normalForce = Common.clamp(pair.separation + normalVelocity, 0, 1) * Resolver._frictionNormalMultiplier;
var velocityPointAX = bodyAVelocity.x - offsetAY * bodyA.angularVelocity,
velocityPointAY = bodyAVelocity.y + offsetAX * bodyA.angularVelocity,
velocityPointBX = bodyBVelocity.x - offsetBY * bodyB.angularVelocity,
velocityPointBY = bodyBVelocity.y + offsetBX * bodyB.angularVelocity;
var relativeVelocityX = velocityPointAX - velocityPointBX,
relativeVelocityY = velocityPointAY - velocityPointBY;
var normalVelocity = normalX * relativeVelocityX + normalY * relativeVelocityY,
tangentVelocity = tangentX * relativeVelocityX + tangentY * relativeVelocityY;
// coulomb friction
var tangentImpulse = tangentVelocity,
maxFriction = Infinity;
// var tangentImpulse = tangentVelocity,
// maxFriction = Infinity;
if (tangentSpeed > pair.friction * pair.frictionStatic * normalForce * timeScale3) {
maxFriction = tangentSpeed * timeScale;
tangentImpulse = Common.clamp(
pair.friction * tangentVelocityDirection * timeScale3,
-maxFriction, maxFriction
);
// if (tangentSpeed > pair.friction * pair.frictionStatic * normalForce * timeScale3) {
// maxFriction = tangentSpeed * timeScale;
// tangentImpulse = Common.clamp(
// pair.friction * tangentVelocityDirection * timeScale3,
// -maxFriction, maxFriction
// );
var normalOverlap = pair.separation + normalVelocity;
var normalForce = Math.min(normalOverlap, 1) * timeScale3;
normalForce = normalOverlap < 0 ? 0 : normalForce;
var frictionLimit = normalForce * friction;
if (tangentVelocity > frictionLimit || -tangentVelocity > frictionLimit) {
maxFriction = (tangentVelocity > 0 ? tangentVelocity : -tangentVelocity) * timeScale;
tangentImpulse = pair.friction * (tangentVelocity > 0 ? 1 : -1) * timeScale3;
if (tangentImpulse < -maxFriction) {
tangentImpulse = -maxFriction;
} else if (tangentImpulse > maxFriction) {
tangentImpulse = maxFriction;
}
} else {
tangentImpulse = tangentVelocity;
maxFriction = NumberMaxValue;
}
// 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);
// account for mass, inertia and contact offset
var oAcN = offsetAX * normalY - offsetAY * normalX,
oBcN = offsetBX * normalY - offsetBY * normalX,
share = contactShare / (inverseMassTotal + bodyA.inverseInertia * oAcN * oAcN + bodyB.inverseInertia * oBcN * oBcN);
normalImpulse *= share;
// raw impulses
var normalImpulse = (1 + pair.restitution) * normalVelocity * share;
tangentImpulse *= share;
// handle high velocity and resting collisions separately
@ -308,7 +343,8 @@ var Bounds = require('../geometry/Bounds');
// 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);
contact.normalImpulse += normalImpulse;
contact.normalImpulse = Math.min(contact.normalImpulse, 0);
normalImpulse = contact.normalImpulse - contactNormalImpulse;
}
@ -320,25 +356,27 @@ var Bounds = require('../geometry/Bounds');
// 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);
contact.tangentImpulse += tangentImpulse;
if (contact.tangentImpulse < -maxFriction) contact.tangentImpulse = -maxFriction;
if (contact.tangentImpulse > maxFriction) contact.tangentImpulse = maxFriction;
tangentImpulse = contact.tangentImpulse - contactTangentImpulse;
}
// total impulse from contact
impulse.x = (normal.x * normalImpulse) + (tangent.x * tangentImpulse);
impulse.y = (normal.y * normalImpulse) + (tangent.y * tangentImpulse);
var impulseX = normalX * normalImpulse + tangentX * tangentImpulse,
impulseY = normalY * normalImpulse + tangentY * 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;
bodyA.positionPrev.x += impulseX * bodyA.inverseMass;
bodyA.positionPrev.y += impulseY * bodyA.inverseMass;
bodyA.anglePrev += (offsetAX * impulseY - offsetAY * impulseX) * bodyA.inverseInertia;
}
if (!(bodyB.isStatic || bodyB.isSleeping)) {
bodyB.positionPrev.x -= impulse.x * bodyB.inverseMass;
bodyB.positionPrev.y -= impulse.y * bodyB.inverseMass;
bodyB.anglePrev -= Vector.cross(offsetB, impulse) * bodyB.inverseInertia;
bodyB.positionPrev.x -= impulseX * bodyB.inverseMass;
bodyB.positionPrev.y -= impulseY * bodyB.inverseMass;
bodyB.anglePrev -= (offsetBX * impulseY - offsetBY * impulseX) * bodyB.inverseInertia;
}
}
}

View file

@ -1,18 +1,22 @@
/**
* This module has now been replaced by `Matter.Collision`.
*
* All usage should be migrated to `Matter.Collision`.
* For back-compatibility purposes this module will remain for a short term and then later removed in a future release.
*
* The `Matter.SAT` module contains methods for detecting collisions using the Separating Axis Theorem.
*
* @class SAT
* @deprecated
*/
// TODO: true circles and curves
var SAT = {};
module.exports = SAT;
var Vertices = require('../geometry/Vertices');
var Vector = require('../geometry/Vector');
var Collision = require('./Collision');
var Common = require('../core/Common');
var deprecated = Common.deprecated;
(function() {
@ -20,258 +24,16 @@ var Common = require('../core/Common');
/**
* Detect collision between two bodies using the Separating Axis Theorem.
* @deprecated replaced by Collision.collides
* @method collides
* @param {body} bodyA
* @param {body} bodyB
* @param {collision} previousCollision
* @param {number} [delta=0]
* @return {collision} collision
*/
SAT.collides = function(bodyA, bodyB, previousCollision, delta) {
var overlapAB,
overlapBA,
minOverlap,
collision,
canReusePrevCol = false,
timeScale = delta / Common._timeUnit;
delta = typeof delta !== 'undefined' ? delta : 0;
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 < SAT._reuseMotionThresh * timeScale * timeScale;
// 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;
SAT.collides = function(bodyA, bodyB) {
return Collision.collides(bodyA, bodyB);
};
/**
* 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];
};
deprecated(SAT, 'collides', 'SAT.collides ➤ replaced by Collision.collides');
})();

View file

@ -14,6 +14,8 @@ module.exports = Common;
Common._nextId = 0;
Common._seed = 0;
Common._nowStartTime = +(new Date());
Common._warnedOnce = {};
Common._decomp = null;
/**
* Extends the object in the first argument using the object in the second argument.
@ -253,9 +255,9 @@ module.exports = Common;
/**
* Returns the current timestamp since the time origin (e.g. from page load).
* The result will be high-resolution including decimal places if available.
* The result is in milliseconds and will use high-resolution timing if available.
* @method now
* @return {number} the current timestamp
* @return {number} the current timestamp in milliseconds
*/
Common.now = function() {
if (typeof window !== 'undefined' && window.performance) {
@ -266,6 +268,10 @@ module.exports = Common;
}
}
if (Date.now) {
return Date.now();
}
return (new Date()) - Common._nowStartTime;
};
@ -359,6 +365,35 @@ module.exports = Common;
}
};
/**
* Uses `Common.warn` to log the given message one time only.
* @method warnOnce
* @param ...objs {} The objects to log.
*/
Common.warnOnce = function() {
var message = Array.prototype.slice.call(arguments).join(' ');
if (!Common._warnedOnce[message]) {
Common.warn(message);
Common._warnedOnce[message] = true;
}
};
/**
* Shows a deprecated console warning when the function on the given object is called.
* The target function will be replaced with a new function that first shows the warning
* and then calls the original function.
* @method deprecated
* @param {object} obj The object or module
* @param {string} name The property name of the function on obj
* @param {string} warning The one-time message to show if the function is called
*/
Common.deprecated = function(obj, prop, warning) {
obj[prop] = Common.chain(function() {
Common.warnOnce('🔅 deprecated 🔅', warning);
}, obj[prop]);
};
/**
* Returns the next unique sequential ID.
* @method nextId
@ -536,4 +571,42 @@ module.exports = Common;
func
));
};
/**
* Provide the [poly-decomp](https://github.com/schteppe/poly-decomp.js) library module to enable
* concave vertex decomposition support when using `Bodies.fromVertices` e.g. `Common.setDecomp(require('poly-decomp'))`.
* @method setDecomp
* @param {} decomp The [poly-decomp](https://github.com/schteppe/poly-decomp.js) library module.
*/
Common.setDecomp = function(decomp) {
Common._decomp = decomp;
};
/**
* Returns the [poly-decomp](https://github.com/schteppe/poly-decomp.js) library module provided through `Common.setDecomp`,
* otherwise returns the global `decomp` if set.
* @method getDecomp
* @return {} The [poly-decomp](https://github.com/schteppe/poly-decomp.js) library module if provided.
*/
Common.getDecomp = function() {
// get user provided decomp if set
var decomp = Common._decomp;
try {
// otherwise from window global
if (!decomp && typeof window !== 'undefined') {
decomp = window.decomp;
}
// otherwise from node global
if (!decomp && typeof global !== 'undefined') {
decomp = global.decomp;
}
} catch (e) {
// decomp not available
decomp = null;
}
return decomp;
};
})();

View file

@ -12,13 +12,10 @@ var Engine = {};
module.exports = Engine;
var World = require('../body/World');
var Sleeping = require('./Sleeping');
var Resolver = require('../collision/Resolver');
var Render = require('../render/Render');
var Detector = require('../collision/Detector');
var Pairs = require('../collision/Pairs');
var Metrics = require('./Metrics');
var Grid = require('../collision/Grid');
var Events = require('./Events');
var Composite = require('../body/Composite');
var Constraint = require('../constraint/Constraint');
@ -35,16 +32,9 @@ var Body = require('../body/Body');
* @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;
Engine.create = function(options) {
options = options || {};
if (element || options.render) {
Common.warn('Engine.create: engine.render is deprecated (see docs)');
}
var defaults = {
positionIterations: 6,
velocityIterations: 4,
@ -52,45 +42,30 @@ var Body = require('../body/Body');
enableSleeping: false,
events: [],
plugin: {},
gravity: {
x: 0,
y: 1,
scale: 0.001
},
timing: {
timestamp: 0,
timeScale: 1
},
broadphase: {
controller: Grid
timeScale: 1,
lastDelta: 0,
lastElapsed: 0
}
};
var engine = Common.extend(defaults, options);
// @deprecated
if (element || engine.render) {
var renderDefaults = {
element: element,
controller: Render
};
engine.world = options.world || Composite.create({ label: 'World' });
engine.pairs = options.pairs || Pairs.create();
engine.detector = options.detector || Detector.create();
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
// for temporary back compatibility only
engine.grid = { buckets: [] };
engine.world.gravity = engine.gravity;
engine.broadphase = engine.grid;
engine.metrics = {};
return engine;
};
@ -104,17 +79,21 @@ var Body = require('../body/Body');
* @param {number} [delta=16.666]
*/
Engine.update = function(engine, delta) {
var startTime = Common.now();
var world = engine.world,
detector = engine.detector,
pairs = engine.pairs,
timing = engine.timing,
broadphase = engine.broadphase,
broadphasePairs,
timestamp = timing.timestamp,
i;
delta = typeof delta !== 'undefined' ? delta : Common._timeUnit;
delta *= timing.timeScale;
// increment timestamp
timing.timestamp += delta;
timing.timestamp += delta * timing.timeScale;
timing.lastDelta = delta * timing.timeScale;
// create an event object
var event = {
@ -124,21 +103,26 @@ var Body = require('../body/Body');
Events.trigger(engine, 'beforeUpdate', event);
// get lists of all bodies and constraints, no matter what composites they are in
// get all bodies and all constraints in the world
var allBodies = Composite.allBodies(world),
allConstraints = Composite.allConstraints(world);
// @if DEBUG
// reset metrics logging
Metrics.reset(engine.metrics);
// @endif
// update the detector bodies if they have changed
if (world.isModified) {
Detector.setBodies(detector, allBodies);
}
// if sleeping enabled, call the sleeping controller
// reset all composite modified flags
if (world.isModified) {
Composite.setModified(world, false, false, true);
}
// update sleeping if enabled
if (engine.enableSleeping)
Sleeping.update(allBodies, delta);
// applies gravity to all bodies
Engine._bodiesApplyGravity(allBodies, world.gravity);
// apply gravity to all bodies
Engine._bodiesApplyGravity(allBodies, engine.gravity);
// update all body position and rotation by integration
if (delta > 0) {
@ -152,33 +136,12 @@ var Body = require('../body/Body');
}
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, delta);
// find all collisions
detector.pairs = engine.pairs;
var collisions = Detector.collisions(detector);
// 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)
@ -215,16 +178,14 @@ var Body = require('../body/Body');
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);
// log the time elapsed computing this update
engine.timing.lastElapsed = Common.now() - startTime;
return engine;
};
@ -253,21 +214,13 @@ var Body = require('../body/Body');
};
/**
* Clears the engine including the world, pairs and broadphase.
* Clears the engine pairs and detector.
* @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);
}
Detector.clear(engine.detector);
};
/**
@ -332,7 +285,8 @@ var Body = require('../body/Body');
};
/**
* An alias for `Runner.run`, see `Matter.Runner` for more information.
* A deprecated alias for `Runner.run`, use `Matter.Runner.run(engine)` instead and see `Matter.Runner` for more information.
* @deprecated use Matter.Runner.run(engine) instead
* @method run
* @param {engine} engine
*/
@ -341,58 +295,58 @@ var Body = require('../body/Body');
* Fired just before an update
*
* @event beforeUpdate
* @param {} event An event object
* @param {object} event An event object
* @param {number} event.timestamp The engine.timing.timestamp of the event
* @param {number} event.delta The delta time in milliseconds value used in the update
* @param {} event.source The source object of the event
* @param {} event.name The name of the event
* @param {engine} event.source The source object of the event
* @param {string} event.name The name of the event
*/
/**
* Fired after engine update and all collision events
*
* @event afterUpdate
* @param {} event An event object
* @param {object} event An event object
* @param {number} event.timestamp The engine.timing.timestamp of the event
* @param {number} event.delta The delta time in milliseconds value used in the update
* @param {} event.source The source object of the event
* @param {} event.name The name of the event
* @param {engine} event.source The source object of the event
* @param {string} event.name The name of the event
*/
/**
* Fired after engine update, provides a list of all pairs that have started to collide in the current tick (if any)
*
* @event collisionStart
* @param {} event An event object
* @param {} event.pairs List of affected pairs
* @param {object} event An event object
* @param {pair[]} event.pairs List of affected pairs
* @param {number} event.timestamp The engine.timing.timestamp of the event
* @param {number} event.delta The delta time in milliseconds value used in the update
* @param {} event.source The source object of the event
* @param {} event.name The name of the event
* @param {engine} event.source The source object of the event
* @param {string} event.name The name of the event
*/
/**
* Fired after engine update, provides a list of all pairs that are colliding in the current tick (if any)
*
* @event collisionActive
* @param {} event An event object
* @param {} event.pairs List of affected pairs
* @param {object} event An event object
* @param {pair[]} event.pairs List of affected pairs
* @param {number} event.timestamp The engine.timing.timestamp of the event
* @param {number} event.delta The delta time in milliseconds value used in the update
* @param {} event.source The source object of the event
* @param {} event.name The name of the event
* @param {engine} event.source The source object of the event
* @param {string} event.name The name of the event
*/
/**
* Fired after engine update, provides a list of all pairs that have ended collision in the current tick (if any)
*
* @event collisionEnd
* @param {} event An event object
* @param {} event.pairs List of affected pairs
* @param {object} event An event object
* @param {pair[]} event.pairs List of affected pairs
* @param {number} event.timestamp The engine.timing.timestamp of the event
* @param {number} event.delta The delta time in milliseconds value used in the update
* @param {} event.source The source object of the event
* @param {} event.name The name of the event
* @param {engine} event.source The source object of the event
* @param {string} event.name The name of the event
*/
/*
@ -466,32 +420,56 @@ var Body = require('../body/Body');
*/
/**
* 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 `Number` that represents the total execution time elapsed during the last `Engine.update` in milliseconds.
* It is updated by timing from the start of the last `Engine.update` call until it ends.
*
* 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.
* This value will also include the total execution time of all event handlers directly or indirectly triggered by the engine update.
*
* @property render
* @type render
* @deprecated see Demo.js for an example of creating a renderer
* @default a Matter.Render instance
* @property timing.lastElapsed
* @type number
* @default 0
*/
/**
* An instance of a broadphase controller. The default value is a `Matter.Grid` instance created by `Engine.create`.
* A `Number` that represents the `delta` value used in the last engine update.
*
* @property timing.lastDelta
* @type number
* @default 0
*/
/**
* A `Matter.Detector` instance.
*
* @property detector
* @type detector
* @default a Matter.Detector instance
*/
/**
* A `Matter.Grid` instance.
*
* @deprecated replaced by `engine.detector`
* @property grid
* @type grid
* @default a Matter.Grid instance
*/
/**
* Replaced by and now alias for `engine.grid`.
*
* @deprecated replaced by `engine.detector`
* @property broadphase
* @type grid
* @default a Matter.Grid instance
*/
/**
* A `World` composite object that will contain all simulated bodies and constraints.
* The root `Matter.Composite` instance that will contain all bodies, constraints and other composites to be simulated by this engine.
*
* @property world
* @type world
* @default a Matter.World instance
* @type composite
* @default a Matter.Composite instance
*/
/**
@ -501,4 +479,35 @@ var Body = require('../body/Body');
* @type {}
*/
/**
* The gravity to apply on all bodies in `engine.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
*/
})();

View file

@ -1,93 +0,0 @@
// @if DEBUG
/**
* _Internal Class_, not generally used outside of the engine's internals.
*
*/
var Metrics = {};
module.exports = Metrics;
var Composite = require('../body/Composite');
var Common = require('./Common');
(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

View file

@ -240,7 +240,7 @@ var Common = require('./Common');
*/
Plugin.dependencyParse = function(dependency) {
if (Common.isString(dependency)) {
var pattern = /^[\w-]+(@(\*|[\^~]?\d+\.\d+\.\d+(-[0-9A-Za-z-]+)?))?$/;
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.');
@ -275,7 +275,7 @@ var Common = require('./Common');
* @return {object} The version range parsed into its components.
*/
Plugin.versionParse = function(range) {
var pattern = /^(\*)|(\^|~|>=|>)?\s*((\d+)\.(\d+)\.(\d+))(-[0-9A-Za-z-]+)?$/;
var pattern = /^(\*)|(\^|~|>=|>)?\s*((\d+)\.(\d+)\.(\d+))(-[0-9A-Za-z-+]+)?$/;
if (!pattern.test(range)) {
Common.warn('Plugin.versionParse:', range, 'is not a valid version or range.');

View file

@ -99,8 +99,7 @@ var Common = require('./Common');
/**
* A game loop utility that updates the engine and renderer by one step (a 'tick').
* Features delta smoothing and fixed or dynamic timing.
* Triggers `beforeTick`, `tick` and `afterTick` events on the engine.
* Features delta smoothing, time correction and fixed or dynamic timing.
* Consider just `Engine.update(engine, delta)` if you're using your own loop.
* @method tick
* @param {runner} runner
@ -111,6 +110,13 @@ var Common = require('./Common');
var timing = engine.timing,
delta;
// create an event object
var event = {
timestamp: timing.timestamp
};
Events.trigger(runner, 'beforeTick', event);
if (runner.isFixed) {
// fixed timestep
delta = runner.delta;
@ -149,15 +155,6 @@ var Common = require('./Common');
}
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);
@ -171,20 +168,7 @@ var Common = require('./Common');
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
};
/**
@ -263,28 +247,6 @@ var Common = require('./Common');
* @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

View file

@ -176,31 +176,46 @@ var Vector = require('../geometry/Vector');
};
/**
* 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.
* Utility to create a compound body based on set(s) of vertices.
*
* _Note:_ To optionally enable automatic concave vertices decomposition the [poly-decomp](https://github.com/schteppe/poly-decomp.js)
* package must be first installed and provided see `Common.setDecomp`, otherwise the convex hull of each vertex set will be used.
*
* The resulting vertices are reorientated about their centre of mass,
* and offset such that `body.position` corresponds to this point.
*
* The resulting offset may be found if needed by subtracting `body.bounds` from the original input bounds.
* To later move the centre of mass see `Body.setCentre`.
*
* Note that automatic conconcave decomposition results are not always optimal.
* For best results, simplify the input vertices as much as possible first.
* By default this function applies some addtional simplification to help.
*
* Some outputs may also require further manual processing afterwards to be robust.
* In particular some parts may need to be overlapped to avoid collision gaps.
* Thin parts and sharp points should be avoided or removed where possible.
*
* The options parameter object specifies any `Matter.Body` properties you wish to override the defaults.
*
* See the properties section of the `Matter.Body` module for detailed information on what you can pass via the `options` object.
* @method fromVertices
* @param {number} x
* @param {number} y
* @param [[vector]] vertexSets
* @param {object} [options]
* @param {bool} [flagInternal=false]
* @param {number} [removeCollinear=0.01]
* @param {number} [minimumArea=10]
* @param {array} vertexSets One or more arrays of vertex points e.g. `[[{ x: 0, y: 0 }...], ...]`.
* @param {object} [options] The body options.
* @param {bool} [flagInternal=false] Optionally marks internal edges with `isInternal`.
* @param {number} [removeCollinear=0.01] Threshold when simplifying vertices along the same edge.
* @param {number} [minimumArea=10] Threshold when removing small parts.
* @param {number} [removeDuplicatePoints=0.01] Threshold when simplifying nearby vertices.
* @return {body}
*/
Bodies.fromVertices = function(x, y, vertexSets, options, flagInternal, removeCollinear, minimumArea) {
var globals = typeof global !== 'undefined' ? global : window,
decomp,
Bodies.fromVertices = function(x, y, vertexSets, options, flagInternal, removeCollinear, minimumArea, removeDuplicatePoints) {
var decomp = Common.getDecomp(),
canDecomp,
body,
parts,
isConvex,
isConcave,
vertices,
i,
j,
@ -208,11 +223,8 @@ var Vector = require('../geometry/Vector');
v,
z;
try {
decomp = globals.decomp || require('poly-decomp');
} catch (e) {
// decomp is undefined
}
// check decomp is as expected
canDecomp = Boolean(decomp && decomp.quickDecomp);
options = options || {};
parts = [];
@ -220,10 +232,7 @@ var Vector = require('../geometry/Vector');
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.');
}
removeDuplicatePoints = typeof removeDuplicatePoints !== 'undefined' ? removeDuplicatePoints : 0.01;
// ensure vertexSets is an array of arrays
if (!Common.isArray(vertexSets[0])) {
@ -233,8 +242,15 @@ var Vector = require('../geometry/Vector');
for (v = 0; v < vertexSets.length; v += 1) {
vertices = vertexSets[v];
isConvex = Vertices.isConvex(vertices);
isConcave = !isConvex;
if (isConvex || !decomp) {
if (isConcave && !canDecomp) {
Common.warnOnce(
'Bodies.fromVertices: Install the \'poly-decomp\' library and use Common.setDecomp or provide \'decomp\' as a global to decompose concave vertices.'
);
}
if (isConvex || !canDecomp) {
if (isConvex) {
vertices = Vertices.clockwiseSort(vertices);
} else {
@ -256,6 +272,8 @@ var Vector = require('../geometry/Vector');
decomp.makeCCW(concave);
if (removeCollinear !== false)
decomp.removeCollinearPoints(concave, removeCollinear);
if (removeDuplicatePoints !== false && decomp.removeDuplicatePoints)
decomp.removeDuplicatePoints(concave, removeDuplicatePoints);
// use the quick decomposition algorithm (Bayazit)
var decomposed = decomp.quickDecomp(concave);
@ -327,6 +345,8 @@ var Vector = require('../geometry/Vector');
if (parts.length > 1) {
// create the parent body to be returned, that contains generated compound parts
body = Body.create(Common.extend({ parts: parts.slice(0) }, options));
// offset such that body.position is at the centre off mass
Body.setPosition(body, { x: x, y: y });
return body;

View file

@ -16,6 +16,7 @@ var Constraint = require('../constraint/Constraint');
var Common = require('../core/Common');
var Body = require('../body/Body');
var Bodies = require('./Bodies');
var deprecated = Common.deprecated;
(function() {
@ -202,7 +203,8 @@ var Bodies = require('./Bodies');
};
/**
* Creates a composite with a Newton's Cradle setup of bodies and constraints.
* This has now moved to the [newtonsCradle example](https://github.com/liabru/matter-js/blob/master/examples/newtonsCradle.js), follow that instead as this function is deprecated here.
* @deprecated moved to newtonsCradle example
* @method newtonsCradle
* @param {number} xx
* @param {number} yy
@ -227,8 +229,11 @@ var Bodies = require('./Bodies');
return newtonsCradle;
};
deprecated(Composites, 'newtonsCradle', 'Composites.newtonsCradle ➤ moved to newtonsCradle example');
/**
* Creates a composite with simple car setup of bodies and constraints.
* This has now moved to the [car example](https://github.com/liabru/matter-js/blob/master/examples/car.js), follow that instead as this function is deprecated here.
* @deprecated moved to car example
* @method car
* @param {number} xx
* @param {number} yy
@ -294,8 +299,12 @@ var Bodies = require('./Bodies');
return car;
};
deprecated(Composites, 'car', 'Composites.car ➤ moved to car example');
/**
* Creates a simple soft body like object.
* This has now moved to the [softBody example](https://github.com/liabru/matter-js/blob/master/examples/softBody.js)
* and the [cloth example](https://github.com/liabru/matter-js/blob/master/examples/cloth.js), follow those instead as this function is deprecated here.
* @deprecated moved to softBody and cloth examples
* @method softBody
* @param {number} xx
* @param {number} yy
@ -324,4 +333,5 @@ var Bodies = require('./Bodies');
return softBody;
};
deprecated(Composites, 'softBody', 'Composites.softBody ➤ moved to softBody and cloth examples');
})();

View file

@ -169,17 +169,16 @@ var Common = require('../core/Common');
* @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;
}
scalar = typeof scalar !== 'undefined' ? scalar : 1;
var verticesLength = vertices.length,
translateX = vector.x * scalar,
translateY = vector.y * scalar,
i;
for (i = 0; i < verticesLength; i++) {
vertices[i].x += translateX;
vertices[i].y += translateY;
}
return vertices;
@ -197,15 +196,21 @@ var Common = require('../core/Common');
return;
var cos = Math.cos(angle),
sin = Math.sin(angle);
sin = Math.sin(angle),
pointX = point.x,
pointY = point.y,
verticesLength = vertices.length,
vertex,
dx,
dy,
i;
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);
for (i = 0; i < verticesLength; i++) {
vertex = vertices[i];
dx = vertex.x - pointX;
dy = vertex.y - pointY;
vertex.x = pointX + (dx * cos - dy * sin);
vertex.y = pointY + (dx * sin + dy * cos);
}
return vertices;
@ -219,12 +224,21 @@ var Common = require('../core/Common');
* @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) {
var pointX = point.x,
pointY = point.y,
verticesLength = vertices.length,
vertex = vertices[verticesLength - 1],
nextVertex;
for (var i = 0; i < verticesLength; i++) {
nextVertex = vertices[i];
if ((pointX - vertex.x) * (nextVertex.y - vertex.y)
+ (pointY - vertex.y) * (vertex.x - nextVertex.x) > 0) {
return false;
}
vertex = nextVertex;
}
return true;

View file

@ -1,51 +1,35 @@
var Matter = module.exports = require('../core/Matter');
Matter.Axes = require('../geometry/Axes');
Matter.Bodies = require('../factory/Bodies');
Matter.Body = require('../body/Body');
Matter.Bounds = require('../geometry/Bounds');
Matter.Collision = require('../collision/Collision');
Matter.Common = require('../core/Common');
Matter.Composite = require('../body/Composite');
Matter.World = require('../body/World');
Matter.Composites = require('../factory/Composites');
Matter.Constraint = require('../constraint/Constraint');
Matter.Contact = require('../collision/Contact');
Matter.Detector = require('../collision/Detector');
Matter.Grid = require('../collision/Grid');
Matter.Pairs = require('../collision/Pairs');
Matter.Pair = require('../collision/Pair');
Matter.Query = require('../collision/Query');
Matter.Resolver = require('../collision/Resolver');
Matter.SAT = require('../collision/SAT');
Matter.Constraint = require('../constraint/Constraint');
Matter.MouseConstraint = require('../constraint/MouseConstraint');
Matter.Common = require('../core/Common');
Matter.Engine = require('../core/Engine');
Matter.Events = require('../core/Events');
Matter.Grid = require('../collision/Grid');
Matter.Mouse = require('../core/Mouse');
Matter.Runner = require('../core/Runner');
Matter.Sleeping = require('../core/Sleeping');
Matter.MouseConstraint = require('../constraint/MouseConstraint');
Matter.Pair = require('../collision/Pair');
Matter.Pairs = require('../collision/Pairs');
Matter.Plugin = require('../core/Plugin');
// @if DEBUG
Matter.Metrics = require('../core/Metrics');
// @endif
Matter.Bodies = require('../factory/Bodies');
Matter.Composites = require('../factory/Composites');
Matter.Axes = require('../geometry/Axes');
Matter.Bounds = require('../geometry/Bounds');
Matter.Query = require('../collision/Query');
Matter.Render = require('../render/Render');
Matter.Resolver = require('../collision/Resolver');
Matter.Runner = require('../core/Runner');
Matter.SAT = require('../collision/SAT');
Matter.Sleeping = require('../core/Sleeping');
Matter.Svg = require('../geometry/Svg');
Matter.Vector = require('../geometry/Vector');
Matter.Vertices = require('../geometry/Vertices');
Matter.World = require('../body/World');
Matter.Render = require('../render/Render');
Matter.RenderPixi = require('../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;
// temporary back compatibility
Matter.Engine.run = Matter.Runner.run;
Matter.Common.deprecated(Matter.Engine, 'run', 'Engine.run ➤ use Matter.Runner.run(engine) instead');

View file

@ -1,5 +1,5 @@
/**
* The `Matter.Render` module is a simple HTML5 canvas based renderer for visualising instances of `Matter.Engine`.
* The `Matter.Render` module is a simple canvas based renderer for visualising instances of `Matter.Engine`.
* It is intended for development and debugging purposes, but may also be suitable for simple games.
* It includes a number of drawing options including wireframe, vector with support for sprites and viewports.
*
@ -14,7 +14,6 @@ var Common = require('../core/Common');
var Composite = require('../body/Composite');
var Bounds = require('../geometry/Bounds');
var Events = require('../core/Events');
var Grid = require('../collision/Grid');
var Vector = require('../geometry/Vector');
var Mouse = require('../core/Mouse');
@ -32,6 +31,9 @@ var Mouse = require('../core/Mouse');
|| window.webkitCancelAnimationFrame || window.msCancelAnimationFrame;
}
Render._goodFps = 30;
Render._goodDelta = 1000 / 60;
/**
* Creates a new renderer. The options parameter is an object that specifies any properties you wish to override the defaults.
* All properties have default values, and many are pre-calculated automatically based on other properties.
@ -48,6 +50,19 @@ var Mouse = require('../core/Mouse');
canvas: null,
mouse: null,
frameRequestId: null,
timing: {
historySize: 60,
delta: 0,
deltaHistory: [],
lastTime: 0,
lastTimestamp: 0,
lastElapsed: 0,
timestampElapsed: 0,
timestampElapsedHistory: [],
engineDeltaHistory: [],
engineElapsedHistory: [],
elapsedHistory: []
},
options: {
width: 800,
height: 600,
@ -59,7 +74,8 @@ var Mouse = require('../core/Mouse');
wireframes: true,
showSleeping: true,
showDebug: false,
showBroadphase: false,
showStats: false,
showPerformance: false,
showBounds: false,
showVelocity: false,
showCollisions: false,
@ -68,7 +84,6 @@ var Mouse = require('../core/Mouse');
showPositions: false,
showAngleIndicator: false,
showIds: false,
showShadows: false,
showVertexNumbers: false,
showConvexHulls: false,
showInternalEdges: false,
@ -100,6 +115,9 @@ var Mouse = require('../core/Mouse');
}
};
// for temporary back compatibility only
render.options.showBroadphase = false;
if (render.options.pixelRatio !== 1) {
Render.setPixelRatio(render, render.options.pixelRatio);
}
@ -121,7 +139,18 @@ var Mouse = require('../core/Mouse');
Render.run = function(render) {
(function loop(time){
render.frameRequestId = _requestAnimationFrame(loop);
Render.world(render);
_updateTiming(render, time);
Render.world(render, time);
if (render.options.showStats || render.options.showDebug) {
Render.stats(render, render.context, time);
}
if (render.options.showPerformance || render.options.showDebug) {
Render.performance(render, render.context, time);
}
})();
};
@ -289,13 +318,16 @@ var Mouse = require('../core/Mouse');
* @method world
* @param {render} render
*/
Render.world = function(render) {
var engine = render.engine,
Render.world = function(render, time) {
var startTime = Common.now(),
engine = render.engine,
world = engine.world,
canvas = render.canvas,
context = render.context,
options = render.options,
allBodies = Composite.allBodies(world),
timing = render.timing;
var allBodies = Composite.allBodies(world),
allConstraints = Composite.allConstraints(world),
background = options.wireframes ? options.wireframeBackground : options.background,
bodies = [],
@ -406,84 +438,188 @@ var Mouse = require('../core/Mouse');
Render.constraints(constraints, context);
if (options.showBroadphase && engine.broadphase.controller === Grid)
Render.grid(render, engine.broadphase, context);
if (options.showDebug)
Render.debug(render, context);
if (options.hasBounds) {
// revert view transforms
Render.endViewTransform(render);
}
Events.trigger(render, 'afterRender', event);
// log the time elapsed computing this update
timing.lastElapsed = Common.now() - startTime;
};
/**
* Description
* Renders statistics about the engine and world useful for debugging.
* @private
* @method debug
* @method stats
* @param {render} render
* @param {RenderingContext} context
* @param {Number} time
*/
Render.stats = function(render, context, time) {
var engine = render.engine,
world = engine.world,
bodies = Composite.allBodies(world),
parts = 0,
width = 55,
height = 44,
x = 0,
y = 0;
// count parts
for (var i = 0; i < bodies.length; i += 1) {
parts += bodies[i].parts.length;
}
// sections
var sections = {
'Part': parts,
'Body': bodies.length,
'Cons': Composite.allConstraints(world).length,
'Comp': Composite.allComposites(world).length,
'Pair': engine.pairs.list.length
};
// background
context.fillStyle = '#0e0f19';
context.fillRect(x, y, width * 5.5, height);
context.font = '12px Arial';
context.textBaseline = 'top';
context.textAlign = 'right';
// sections
for (var key in sections) {
var section = sections[key];
// label
context.fillStyle = '#aaa';
context.fillText(key, x + width, y + 8);
// value
context.fillStyle = '#eee';
context.fillText(section, x + width, y + 26);
x += width;
}
};
/**
* Renders engine and render performance information.
* @private
* @method performance
* @param {render} render
* @param {RenderingContext} context
*/
Render.debug = function(render, context) {
var c = context,
engine = render.engine,
world = engine.world,
metrics = engine.metrics,
options = render.options,
bodies = Composite.allBodies(world),
space = " ";
Render.performance = function(render, context) {
var engine = render.engine,
timing = render.timing,
deltaHistory = timing.deltaHistory,
elapsedHistory = timing.elapsedHistory,
timestampElapsedHistory = timing.timestampElapsedHistory,
engineDeltaHistory = timing.engineDeltaHistory,
engineElapsedHistory = timing.engineElapsedHistory,
lastEngineDelta = engine.timing.lastDelta;
if (engine.timing.timestamp - (render.debugTimestamp || 0) >= 500) {
var text = "";
var deltaMean = _mean(deltaHistory),
elapsedMean = _mean(elapsedHistory),
engineDeltaMean = _mean(engineDeltaHistory),
engineElapsedMean = _mean(engineElapsedHistory),
timestampElapsedMean = _mean(timestampElapsedHistory),
rateMean = (timestampElapsedMean / deltaMean) || 0,
fps = (1000 / deltaMean) || 0;
if (metrics.timing) {
text += "fps: " + Math.round(metrics.timing.fps) + space;
}
var graphHeight = 4,
gap = 12,
width = 60,
height = 34,
x = 10,
y = 69;
// @if DEBUG
if (metrics.extended) {
if (metrics.timing) {
text += "delta: " + metrics.timing.delta.toFixed(3) + space;
text += "correction: " + metrics.timing.correction.toFixed(3) + space;
}
// background
context.fillStyle = '#0e0f19';
context.fillRect(0, 50, gap * 4 + width * 5 + 22, height);
text += "bodies: " + bodies.length + space;
// show FPS
Render.status(
context, x, y, width, graphHeight, deltaHistory.length,
Math.round(fps) + ' fps',
fps / Render._goodFps,
function(i) { return (deltaHistory[i] / deltaMean) - 1; }
);
if (engine.broadphase.controller === Grid)
text += "buckets: " + metrics.buckets + space;
// show engine delta
Render.status(
context, x + gap + width, y, width, graphHeight, engineDeltaHistory.length,
lastEngineDelta.toFixed(2) + ' dt',
Render._goodDelta / lastEngineDelta,
function(i) { return (engineDeltaHistory[i] / engineDeltaMean) - 1; }
);
text += "\n";
// show engine update time
Render.status(
context, x + (gap + width) * 2, y, width, graphHeight, engineElapsedHistory.length,
engineElapsedMean.toFixed(2) + ' ut',
1 - (engineElapsedMean / Render._goodFps),
function(i) { return (engineElapsedHistory[i] / engineElapsedMean) - 1; }
);
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
// show render time
Render.status(
context, x + (gap + width) * 3, y, width, graphHeight, elapsedHistory.length,
elapsedMean.toFixed(2) + ' rt',
1 - (elapsedMean / Render._goodFps),
function(i) { return (elapsedHistory[i] / elapsedMean) - 1; }
);
render.debugString = text;
render.debugTimestamp = engine.timing.timestamp;
// show effective speed
Render.status(
context, x + (gap + width) * 4, y, width, graphHeight, timestampElapsedHistory.length,
rateMean.toFixed(2) + ' x',
rateMean * rateMean * rateMean,
function(i) { return (((timestampElapsedHistory[i] / deltaHistory[i]) / rateMean) || 0) - 1; }
);
};
/**
* Renders a label, indicator and a chart.
* @private
* @method status
* @param {RenderingContext} context
* @param {number} x
* @param {number} y
* @param {number} width
* @param {number} height
* @param {number} count
* @param {string} label
* @param {string} indicator
* @param {function} plotY
*/
Render.status = function(context, x, y, width, height, count, label, indicator, plotY) {
// background
context.strokeStyle = '#888';
context.fillStyle = '#444';
context.lineWidth = 1;
context.fillRect(x, y + 7, width, 1);
// chart
context.beginPath();
context.moveTo(x, y + 7 - height * Common.clamp(0.4 * plotY(0), -2, 2));
for (var i = 0; i < width; i += 1) {
context.lineTo(x + i, y + 7 - (i < count ? height * Common.clamp(0.4 * plotY(i), -2, 2) : 0));
}
context.stroke();
if (render.debugString) {
c.font = "12px Arial";
// indicator
context.fillStyle = 'hsl(' + Common.clamp(25 + 95 * indicator, 0, 120) + ',100%,60%)';
context.fillRect(x, y - 7, 4, 4);
if (options.wireframes) {
c.fillStyle = 'rgba(255,255,255,0.5)';
} else {
c.fillStyle = 'rgba(0,0,0,0.5)';
}
var split = render.debugString.split('\n');
for (var i = 0; i < split.length; i++) {
c.fillText(split[i], 50, 50 + i * 18);
}
}
// label
context.font = '12px Arial';
context.textBaseline = 'middle';
context.textAlign = 'right';
context.fillStyle = '#eee';
context.fillText(label, x + width, y - 5);
};
/**
@ -563,55 +699,6 @@ var Mouse = require('../core/Mouse');
}
};
/**
* Description
* @private
* @method bodyShadows
* @param {render} render
* @param {body[]} bodies
* @param {RenderingContext} context
*/
Render.bodyShadows = function(render, bodies, context) {
var c = context,
engine = render.engine;
for (var i = 0; i < bodies.length; i++) {
var body = bodies[i];
if (!body.render.visible)
continue;
if (body.circleRadius) {
c.beginPath();
c.arc(body.position.x, body.position.y, body.circleRadius, 0, 2 * Math.PI);
c.closePath();
} else {
c.beginPath();
c.moveTo(body.vertices[0].x, body.vertices[0].y);
for (var j = 1; j < body.vertices.length; j++) {
c.lineTo(body.vertices[j].x, body.vertices[j].y);
}
c.closePath();
}
var distanceX = body.position.x - render.options.width * 0.5,
distanceY = body.position.y - render.options.height * 0.2,
distance = Math.abs(distanceX) + Math.abs(distanceY);
c.shadowColor = 'rgba(0,0,0,0.15)';
c.shadowOffsetX = 0.05 * distanceX;
c.shadowOffsetY = 0.05 * distanceY;
c.shadowBlur = 1 + 12 * Math.min(1, distance / 1000);
c.fill();
c.shadowColor = null;
c.shadowOffsetX = null;
c.shadowOffsetY = null;
c.shadowBlur = null;
}
};
/**
* Description
* @private
@ -1197,45 +1284,6 @@ var Mouse = require('../core/Mouse');
c.stroke();
};
/**
* Description
* @private
* @method grid
* @param {render} render
* @param {grid} grid
* @param {RenderingContext} context
*/
Render.grid = function(render, grid, context) {
var c = context,
options = render.options;
if (options.wireframes) {
c.strokeStyle = 'rgba(255,180,0,0.1)';
} else {
c.strokeStyle = 'rgba(255,180,0,0.5)';
}
c.beginPath();
var bucketKeys = Common.keys(grid.buckets);
for (var i = 0; i < bucketKeys.length; i++) {
var bucketId = bucketKeys[i];
if (grid.buckets[bucketId].length < 2)
continue;
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);
}
c.lineWidth = 1;
c.stroke();
};
/**
* Description
* @private
@ -1322,7 +1370,56 @@ var Mouse = require('../core/Mouse');
};
/**
* Description
* Updates render timing.
* @method _updateTiming
* @private
* @param {render} render
* @param {number} time
*/
var _updateTiming = function(render, time) {
var engine = render.engine,
timing = render.timing,
historySize = timing.historySize,
timestamp = engine.timing.timestamp;
timing.delta = time - timing.lastTime || Render._goodDelta;
timing.lastTime = time;
timing.timestampElapsed = timestamp - timing.lastTimestamp || 0;
timing.lastTimestamp = timestamp;
timing.deltaHistory.unshift(timing.delta);
timing.deltaHistory.length = Math.min(timing.deltaHistory.length, historySize);
timing.engineDeltaHistory.unshift(engine.timing.lastDelta);
timing.engineDeltaHistory.length = Math.min(timing.engineDeltaHistory.length, historySize);
timing.timestampElapsedHistory.unshift(timing.timestampElapsed);
timing.timestampElapsedHistory.length = Math.min(timing.timestampElapsedHistory.length, historySize);
timing.engineElapsedHistory.unshift(engine.timing.lastElapsed);
timing.engineElapsedHistory.length = Math.min(timing.engineElapsedHistory.length, historySize);
timing.elapsedHistory.unshift(timing.lastElapsed);
timing.elapsedHistory.length = Math.min(timing.elapsedHistory.length, historySize);
};
/**
* Returns the mean value of the given numbers.
* @method _mean
* @private
* @param {Number[]} values
* @return {Number} the mean of given values
*/
var _mean = function(values) {
var result = 0;
for (var i = 0; i < values.length; i += 1) {
result += values[i];
}
return (result / values.length) || 0;
};
/**
* @method _createCanvas
* @private
* @param {} width
@ -1455,37 +1552,6 @@ var Mouse = require('../core/Mouse');
* @default null
*/
/**
* The configuration options of the renderer.
*
* @property options
* @type {}
*/
/**
* The target width in pixels of the `render.canvas` to be created.
*
* @property options.width
* @type number
* @default 800
*/
/**
* The target height in pixels of the `render.canvas` to be created.
*
* @property options.height
* @type number
* @default 600
*/
/**
* A flag that specifies if `render.bounds` should be used when rendering.
*
* @property options.hasBounds
* @type boolean
* @default false
*/
/**
* A `Bounds` object that specifies the drawing view region.
* Rendering will be automatically transformed and scaled to fit within the canvas size (`render.options.width` and `render.options.height`).
@ -1510,4 +1576,255 @@ var Mouse = require('../core/Mouse');
* @type {}
*/
/**
* The mouse to render if `render.options.showMousePosition` is enabled.
*
* @property mouse
* @type mouse
* @default null
*/
/**
* The configuration options of the renderer.
*
* @property options
* @type {}
*/
/**
* The target width in pixels of the `render.canvas` to be created.
* See also the `options.pixelRatio` property to change render quality.
*
* @property options.width
* @type number
* @default 800
*/
/**
* The target height in pixels of the `render.canvas` to be created.
* See also the `options.pixelRatio` property to change render quality.
*
* @property options.height
* @type number
* @default 600
*/
/**
* The [pixel ratio](https://developer.mozilla.org/en-US/docs/Web/API/Window/devicePixelRatio) to use when rendering.
*
* @property options.pixelRatio
* @type number
* @default 1
*/
/**
* A CSS background color string to use when `render.options.wireframes` is disabled.
* This may be also set to `'transparent'` or equivalent.
*
* @property options.background
* @type string
* @default '#14151f'
*/
/**
* A CSS background color string to use when `render.options.wireframes` is enabled.
* This may be also set to `'transparent'` or equivalent.
*
* @property options.wireframeBackground
* @type string
* @default '#14151f'
*/
/**
* A flag that specifies if `render.bounds` should be used when rendering.
*
* @property options.hasBounds
* @type boolean
* @default false
*/
/**
* A flag to enable or disable all debug information overlays together.
* This includes and has priority over the values of:
*
* - `render.options.showStats`
* - `render.options.showPerformance`
*
* @property options.showDebug
* @type boolean
* @default false
*/
/**
* A flag to enable or disable the engine stats info overlay.
* From left to right, the values shown are:
*
* - body parts total
* - body total
* - constraints total
* - composites total
* - collision pairs total
*
* @property options.showStats
* @type boolean
* @default false
*/
/**
* A flag to enable or disable performance charts.
* From left to right, the values shown are:
*
* - average render frequency (e.g. 60 fps)
* - exact engine delta time used for last update (e.g. 16.66ms)
* - average engine execution duration (e.g. 5.00ms)
* - average render execution duration (e.g. 0.40ms)
* - average effective play speed (e.g. '1.00x' is 'real-time')
*
* Each value is recorded over a fixed sample of past frames (60 frames).
*
* A chart shown below each value indicates the variance from the average over the sample.
* The more stable or fixed the value is the flatter the chart will appear.
*
* @property options.showPerformance
* @type boolean
* @default false
*/
/**
* A flag to enable or disable rendering entirely.
*
* @property options.enabled
* @type boolean
* @default false
*/
/**
* A flag to toggle wireframe rendering otherwise solid fill rendering is used.
*
* @property options.wireframes
* @type boolean
* @default true
*/
/**
* A flag to enable or disable sleeping bodies indicators.
*
* @property options.showSleeping
* @type boolean
* @default true
*/
/**
* A flag to enable or disable the debug information overlay.
*
* @property options.showDebug
* @type boolean
* @default false
*/
/**
* A flag to enable or disable the collision broadphase debug overlay.
*
* @deprecated no longer implemented
* @property options.showBroadphase
* @type boolean
* @default false
*/
/**
* A flag to enable or disable the body bounds debug overlay.
*
* @property options.showBounds
* @type boolean
* @default false
*/
/**
* A flag to enable or disable the body velocity debug overlay.
*
* @property options.showVelocity
* @type boolean
* @default false
*/
/**
* A flag to enable or disable the body collisions debug overlay.
*
* @property options.showCollisions
* @type boolean
* @default false
*/
/**
* A flag to enable or disable the collision resolver separations debug overlay.
*
* @property options.showSeparations
* @type boolean
* @default false
*/
/**
* A flag to enable or disable the body axes debug overlay.
*
* @property options.showAxes
* @type boolean
* @default false
*/
/**
* A flag to enable or disable the body positions debug overlay.
*
* @property options.showPositions
* @type boolean
* @default false
*/
/**
* A flag to enable or disable the body angle debug overlay.
*
* @property options.showAngleIndicator
* @type boolean
* @default false
*/
/**
* A flag to enable or disable the body and part ids debug overlay.
*
* @property options.showIds
* @type boolean
* @default false
*/
/**
* A flag to enable or disable the body vertex numbers debug overlay.
*
* @property options.showVertexNumbers
* @type boolean
* @default false
*/
/**
* A flag to enable or disable the body convex hulls debug overlay.
*
* @property options.showConvexHulls
* @type boolean
* @default false
*/
/**
* A flag to enable or disable the body internal edges debug overlay.
*
* @property options.showInternalEdges
* @type boolean
* @default false
*/
/**
* A flag to enable or disable the mouse position debug overlay.
*
* @property options.showMousePosition
* @type boolean
* @default false
*/
})();

View file

@ -1,515 +0,0 @@
/**
* The `Matter.RenderPixi` module is an example renderer using pixi.js.
* See also `Matter.Render` for a canvas based renderer.
*
* @class RenderPixi
* @deprecated the Matter.RenderPixi module will soon be removed from the Matter.js core.
* It will likely be moved to its own repository (but maintenance will be limited).
*/
var RenderPixi = {};
module.exports = RenderPixi;
var Bounds = require('../geometry/Bounds');
var Composite = require('../body/Composite');
var Common = require('../core/Common');
var Events = require('../core/Events');
var Vector = require('../geometry/Vector');
(function() {
var _requestAnimationFrame,
_cancelAnimationFrame;
if (typeof window !== 'undefined') {
_requestAnimationFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame
|| window.mozRequestAnimationFrame || window.msRequestAnimationFrame
|| function(callback){ window.setTimeout(function() { callback(Common.now()); }, 1000 / 60); };
_cancelAnimationFrame = window.cancelAnimationFrame || window.mozCancelAnimationFrame
|| window.webkitCancelAnimationFrame || window.msCancelAnimationFrame;
}
/**
* Creates a new Pixi.js WebGL renderer
* @method create
* @param {object} options
* @return {RenderPixi} A new renderer
* @deprecated
*/
RenderPixi.create = function(options) {
Common.warn('RenderPixi.create: Matter.RenderPixi is deprecated (see docs)');
var defaults = {
controller: RenderPixi,
engine: null,
element: null,
frameRequestId: null,
canvas: null,
renderer: null,
container: null,
spriteContainer: null,
pixiOptions: null,
options: {
width: 800,
height: 600,
background: '#fafafa',
wireframeBackground: '#222',
hasBounds: false,
enabled: true,
wireframes: true,
showSleeping: true,
showDebug: false,
showBroadphase: false,
showBounds: false,
showVelocity: false,
showCollisions: false,
showAxes: false,
showPositions: false,
showAngleIndicator: false,
showIds: false,
showShadows: false
}
};
var render = Common.extend(defaults, options),
transparent = !render.options.wireframes && render.options.background === 'transparent';
// init pixi
render.pixiOptions = render.pixiOptions || {
view: render.canvas,
transparent: transparent,
antialias: true,
backgroundColor: options.background
};
render.mouse = options.mouse;
render.engine = options.engine;
render.renderer = render.renderer || new PIXI.WebGLRenderer(render.options.width, render.options.height, render.pixiOptions);
render.container = render.container || new PIXI.Container();
render.spriteContainer = render.spriteContainer || new PIXI.Container();
render.canvas = render.canvas || render.renderer.view;
render.bounds = render.bounds || {
min: {
x: 0,
y: 0
},
max: {
x: render.options.width,
y: render.options.height
}
};
// event listeners
Events.on(render.engine, 'beforeUpdate', function() {
RenderPixi.clear(render);
});
// caches
render.textures = {};
render.sprites = {};
render.primitives = {};
// use a sprite batch for performance
render.container.addChild(render.spriteContainer);
// insert canvas
if (Common.isElement(render.element)) {
render.element.appendChild(render.canvas);
} else {
Common.warn('No "render.element" passed, "render.canvas" was not inserted into document.');
}
// prevent menus on canvas
render.canvas.oncontextmenu = function() { return false; };
render.canvas.onselectstart = function() { return false; };
return render;
};
/**
* Continuously updates the render canvas on the `requestAnimationFrame` event.
* @method run
* @param {render} render
* @deprecated
*/
RenderPixi.run = function(render) {
(function loop(time){
render.frameRequestId = _requestAnimationFrame(loop);
RenderPixi.world(render);
})();
};
/**
* Ends execution of `Render.run` on the given `render`, by canceling the animation frame request event loop.
* @method stop
* @param {render} render
* @deprecated
*/
RenderPixi.stop = function(render) {
_cancelAnimationFrame(render.frameRequestId);
};
/**
* Clears the scene graph
* @method clear
* @param {RenderPixi} render
* @deprecated
*/
RenderPixi.clear = function(render) {
var container = render.container,
spriteContainer = render.spriteContainer;
// clear stage container
while (container.children[0]) {
container.removeChild(container.children[0]);
}
// clear sprite batch
while (spriteContainer.children[0]) {
spriteContainer.removeChild(spriteContainer.children[0]);
}
var bgSprite = render.sprites['bg-0'];
// clear caches
render.textures = {};
render.sprites = {};
render.primitives = {};
// set background sprite
render.sprites['bg-0'] = bgSprite;
if (bgSprite)
container.addChildAt(bgSprite, 0);
// add sprite batch back into container
render.container.addChild(render.spriteContainer);
// reset background state
render.currentBackground = null;
// reset bounds transforms
container.scale.set(1, 1);
container.position.set(0, 0);
};
/**
* Sets the background of the canvas
* @method setBackground
* @param {RenderPixi} render
* @param {string} background
* @deprecated
*/
RenderPixi.setBackground = function(render, background) {
if (render.currentBackground !== background) {
var isColor = background.indexOf && background.indexOf('#') !== -1,
bgSprite = render.sprites['bg-0'];
if (isColor) {
// if solid background color
var color = Common.colorToNumber(background);
render.renderer.backgroundColor = color;
// remove background sprite if existing
if (bgSprite)
render.container.removeChild(bgSprite);
} else {
// initialise background sprite if needed
if (!bgSprite) {
var texture = _getTexture(render, background);
bgSprite = render.sprites['bg-0'] = new PIXI.Sprite(texture);
bgSprite.position.x = 0;
bgSprite.position.y = 0;
render.container.addChildAt(bgSprite, 0);
}
}
render.currentBackground = background;
}
};
/**
* Description
* @method world
* @param {engine} engine
* @deprecated
*/
RenderPixi.world = function(render) {
var engine = render.engine,
world = engine.world,
renderer = render.renderer,
container = render.container,
options = render.options,
bodies = Composite.allBodies(world),
allConstraints = Composite.allConstraints(world),
constraints = [],
i;
if (options.wireframes) {
RenderPixi.setBackground(render, options.wireframeBackground);
} else {
RenderPixi.setBackground(render, options.background);
}
// handle bounds
var boundsWidth = render.bounds.max.x - render.bounds.min.x,
boundsHeight = render.bounds.max.y - render.bounds.min.y,
boundsScaleX = boundsWidth / render.options.width,
boundsScaleY = boundsHeight / render.options.height;
if (options.hasBounds) {
// Hide bodies that are not in view
for (i = 0; i < bodies.length; i++) {
var body = bodies[i];
body.render.sprite.visible = Bounds.overlaps(body.bounds, render.bounds);
}
// filter out constraints that are not in view
for (i = 0; i < allConstraints.length; i++) {
var constraint = allConstraints[i],
bodyA = constraint.bodyA,
bodyB = constraint.bodyB,
pointAWorld = constraint.pointA,
pointBWorld = constraint.pointB;
if (bodyA) pointAWorld = Vector.add(bodyA.position, constraint.pointA);
if (bodyB) pointBWorld = Vector.add(bodyB.position, constraint.pointB);
if (!pointAWorld || !pointBWorld)
continue;
if (Bounds.contains(render.bounds, pointAWorld) || Bounds.contains(render.bounds, pointBWorld))
constraints.push(constraint);
}
// transform the view
container.scale.set(1 / boundsScaleX, 1 / boundsScaleY);
container.position.set(-render.bounds.min.x * (1 / boundsScaleX), -render.bounds.min.y * (1 / boundsScaleY));
} else {
constraints = allConstraints;
}
for (i = 0; i < bodies.length; i++)
RenderPixi.body(render, bodies[i]);
for (i = 0; i < constraints.length; i++)
RenderPixi.constraint(render, constraints[i]);
renderer.render(container);
};
/**
* Description
* @method constraint
* @param {engine} engine
* @param {constraint} constraint
* @deprecated
*/
RenderPixi.constraint = function(render, constraint) {
var engine = render.engine,
bodyA = constraint.bodyA,
bodyB = constraint.bodyB,
pointA = constraint.pointA,
pointB = constraint.pointB,
container = render.container,
constraintRender = constraint.render,
primitiveId = 'c-' + constraint.id,
primitive = render.primitives[primitiveId];
// initialise constraint primitive if not existing
if (!primitive)
primitive = render.primitives[primitiveId] = new PIXI.Graphics();
// don't render if constraint does not have two end points
if (!constraintRender.visible || !constraint.pointA || !constraint.pointB) {
primitive.clear();
return;
}
// add to scene graph if not already there
if (Common.indexOf(container.children, primitive) === -1)
container.addChild(primitive);
// render the constraint on every update, since they can change dynamically
primitive.clear();
primitive.beginFill(0, 0);
primitive.lineStyle(constraintRender.lineWidth, Common.colorToNumber(constraintRender.strokeStyle), 1);
if (bodyA) {
primitive.moveTo(bodyA.position.x + pointA.x, bodyA.position.y + pointA.y);
} else {
primitive.moveTo(pointA.x, pointA.y);
}
if (bodyB) {
primitive.lineTo(bodyB.position.x + pointB.x, bodyB.position.y + pointB.y);
} else {
primitive.lineTo(pointB.x, pointB.y);
}
primitive.endFill();
};
/**
* Description
* @method body
* @param {engine} engine
* @param {body} body
* @deprecated
*/
RenderPixi.body = function(render, body) {
var engine = render.engine,
bodyRender = body.render;
if (!bodyRender.visible)
return;
if (bodyRender.sprite && bodyRender.sprite.texture) {
var spriteId = 'b-' + body.id,
sprite = render.sprites[spriteId],
spriteContainer = render.spriteContainer;
// initialise body sprite if not existing
if (!sprite)
sprite = render.sprites[spriteId] = _createBodySprite(render, body);
// add to scene graph if not already there
if (Common.indexOf(spriteContainer.children, sprite) === -1)
spriteContainer.addChild(sprite);
// update body sprite
sprite.position.x = body.position.x;
sprite.position.y = body.position.y;
sprite.rotation = body.angle;
sprite.scale.x = bodyRender.sprite.xScale || 1;
sprite.scale.y = bodyRender.sprite.yScale || 1;
} else {
var primitiveId = 'b-' + body.id,
primitive = render.primitives[primitiveId],
container = render.container;
// initialise body primitive if not existing
if (!primitive) {
primitive = render.primitives[primitiveId] = _createBodyPrimitive(render, body);
primitive.initialAngle = body.angle;
}
// add to scene graph if not already there
if (Common.indexOf(container.children, primitive) === -1)
container.addChild(primitive);
// update body primitive
primitive.position.x = body.position.x;
primitive.position.y = body.position.y;
primitive.rotation = body.angle - primitive.initialAngle;
}
};
/**
* Creates a body sprite
* @method _createBodySprite
* @private
* @param {RenderPixi} render
* @param {body} body
* @return {PIXI.Sprite} sprite
* @deprecated
*/
var _createBodySprite = function(render, body) {
var bodyRender = body.render,
texturePath = bodyRender.sprite.texture,
texture = _getTexture(render, texturePath),
sprite = new PIXI.Sprite(texture);
sprite.anchor.x = body.render.sprite.xOffset;
sprite.anchor.y = body.render.sprite.yOffset;
return sprite;
};
/**
* Creates a body primitive
* @method _createBodyPrimitive
* @private
* @param {RenderPixi} render
* @param {body} body
* @return {PIXI.Graphics} graphics
* @deprecated
*/
var _createBodyPrimitive = function(render, body) {
var bodyRender = body.render,
options = render.options,
primitive = new PIXI.Graphics(),
fillStyle = Common.colorToNumber(bodyRender.fillStyle),
strokeStyle = Common.colorToNumber(bodyRender.strokeStyle),
strokeStyleIndicator = Common.colorToNumber(bodyRender.strokeStyle),
strokeStyleWireframe = Common.colorToNumber('#bbb'),
strokeStyleWireframeIndicator = Common.colorToNumber('#CD5C5C'),
part;
primitive.clear();
// handle compound parts
for (var k = body.parts.length > 1 ? 1 : 0; k < body.parts.length; k++) {
part = body.parts[k];
if (!options.wireframes) {
primitive.beginFill(fillStyle, 1);
primitive.lineStyle(bodyRender.lineWidth, strokeStyle, 1);
} else {
primitive.beginFill(0, 0);
primitive.lineStyle(1, strokeStyleWireframe, 1);
}
primitive.moveTo(part.vertices[0].x - body.position.x, part.vertices[0].y - body.position.y);
for (var j = 1; j < part.vertices.length; j++) {
primitive.lineTo(part.vertices[j].x - body.position.x, part.vertices[j].y - body.position.y);
}
primitive.lineTo(part.vertices[0].x - body.position.x, part.vertices[0].y - body.position.y);
primitive.endFill();
// angle indicator
if (options.showAngleIndicator || options.showAxes) {
primitive.beginFill(0, 0);
if (options.wireframes) {
primitive.lineStyle(1, strokeStyleWireframeIndicator, 1);
} else {
primitive.lineStyle(1, strokeStyleIndicator);
}
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));
primitive.endFill();
}
}
return primitive;
};
/**
* Gets the requested texture (a PIXI.Texture) via its path
* @method _getTexture
* @private
* @param {RenderPixi} render
* @param {string} imagePath
* @return {PIXI.Texture} texture
* @deprecated
*/
var _getTexture = function(render, imagePath) {
var texture = render.textures[imagePath];
if (!texture)
texture = render.textures[imagePath] = PIXI.Texture.fromImage(imagePath);
return texture;
};
})();

Some files were not shown because too many files have changed in this diff Show more