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:
commit
7fce5d861c
107 changed files with 26980 additions and 18446 deletions
|
@ -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
3
.gitignore
vendored
|
@ -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
|
||||
|
|
|
@ -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
|
124
CHANGELOG.md
124
CHANGELOG.md
|
@ -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))
|
||||
|
|
|
@ -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**
|
||||
|
|
|
@ -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.
|
||||
|
|
155
RELEASE.md
155
RELEASE.md
|
@ -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.
|
||||
|
|
7611
build/matter.js
7611
build/matter.js
File diff suppressed because it is too large
Load diff
4
build/matter.min.js
vendored
4
build/matter.min.js
vendored
File diff suppressed because one or more lines are too long
|
@ -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>
|
|
@ -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);
|
||||
})();
|
107
demo/js/Demo.js
107
demo/js/Demo.js
|
@ -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);
|
||||
})();
|
5699
demo/js/Examples.js
5699
demo/js/Examples.js
File diff suppressed because it is too large
Load diff
|
@ -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
6
demo/js/matter-demo.a280d3.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
5
demo/js/matter-demo.main.5754e1.min.js
vendored
Normal file
5
demo/js/matter-demo.main.5754e1.min.js
vendored
Normal 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()}([]);
|
117
demo/js/matter-demo.matter-tools.97f38a.min.js
vendored
Normal file
117
demo/js/matter-demo.matter-tools.97f38a.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
12
demo/js/matter-demo.matter-wrap.dbda1f.min.js
vendored
Normal file
12
demo/js/matter-demo.matter-wrap.dbda1f.min.js
vendored
Normal 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"))}}]);
|
6
demo/js/matter-demo.pathseg.cf21c2.min.js
vendored
Normal file
6
demo/js/matter-demo.pathseg.cf21c2.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
6
demo/js/matter-demo.poly-decomp.c3d015.min.js
vendored
Normal file
6
demo/js/matter-demo.poly-decomp.c3d015.min.js
vendored
Normal 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)}}}]);
|
|
@ -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
|
@ -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
|
||||
*/
|
||||
|
||||
/***/ })
|
||||
/******/ ]);
|
||||
});
|
|
@ -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
173
demo/src/Compare.js
Normal 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
65
demo/src/Demo.js
Normal 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
55
demo/src/index.ejs
Normal 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
39
demo/src/index.js
Normal 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);
|
||||
}
|
|
@ -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') {
|
||||
|
|
|
@ -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') {
|
||||
|
|
|
@ -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') {
|
||||
|
|
|
@ -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') {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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') {
|
||||
|
|
|
@ -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') {
|
||||
|
|
|
@ -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') {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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') {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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') {
|
||||
|
|
|
@ -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') {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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') {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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') {
|
||||
|
|
|
@ -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') {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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') {
|
||||
|
|
|
@ -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'),
|
||||
|
|
|
@ -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') {
|
||||
|
|
|
@ -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') {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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') {
|
||||
|
|
|
@ -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') {
|
||||
|
|
|
@ -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
138
examples/remove.js
Normal 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;
|
||||
}
|
|
@ -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') {
|
||||
|
|
|
@ -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') {
|
||||
|
|
|
@ -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') {
|
||||
|
|
|
@ -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') {
|
||||
|
|
|
@ -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') {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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') {
|
||||
|
|
|
@ -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') {
|
||||
|
|
|
@ -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') {
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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') {
|
||||
|
|
|
@ -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
111
examples/stress3.js
Normal 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;
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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') {
|
||||
|
|
|
@ -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') {
|
||||
|
|
|
@ -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
20857
package-lock.json
generated
File diff suppressed because it is too large
Load diff
39
package.json
39
package.json
|
@ -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",
|
||||
|
|
|
@ -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 {}
|
||||
*/
|
||||
|
||||
})();
|
||||
|
|
|
@ -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
408
src/collision/Collision.js
Normal 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 []
|
||||
*/
|
||||
|
||||
})();
|
|
@ -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;
|
||||
};
|
||||
|
||||
})();
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
||||
})();
|
||||
|
|
|
@ -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]];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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');
|
||||
|
||||
})();
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
})();
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
||||
})();
|
||||
|
|
|
@ -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
|
|
@ -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.');
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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');
|
||||
})();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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');
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
||||
})();
|
||||
|
|
|
@ -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
Loading…
Reference in a new issue