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,
|
"process": false,
|
||||||
"HTMLElement": false,
|
"HTMLElement": false,
|
||||||
"require": false,
|
"require": false,
|
||||||
"PIXI": false,
|
|
||||||
"$": false,
|
"$": false,
|
||||||
"Image": false,
|
"Image": false,
|
||||||
"navigator": false,
|
"navigator": false,
|
||||||
|
@ -59,14 +58,13 @@
|
||||||
"Vector": false,
|
"Vector": false,
|
||||||
"Vertices": false,
|
"Vertices": false,
|
||||||
"Render": false,
|
"Render": false,
|
||||||
"RenderPixi": false,
|
|
||||||
"Events": false,
|
"Events": false,
|
||||||
"Query": false,
|
"Query": false,
|
||||||
"Runner": false,
|
"Runner": false,
|
||||||
"Svg": false,
|
"Svg": false,
|
||||||
"Metrics": false,
|
|
||||||
"Example": false,
|
"Example": false,
|
||||||
"__MATTER_VERSION__": false,
|
"__MATTER_VERSION__": false,
|
||||||
|
"__MATTER_IS_DEV__": false,
|
||||||
"jest": false,
|
"jest": false,
|
||||||
"test": false,
|
"test": false,
|
||||||
"expect": false,
|
"expect": false,
|
||||||
|
|
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -1,10 +1,13 @@
|
||||||
.idea
|
.idea
|
||||||
|
*.map
|
||||||
node_modules
|
node_modules
|
||||||
npm-debug.log
|
npm-debug.log
|
||||||
docs
|
docs
|
||||||
matter-doc-theme
|
matter-doc-theme
|
||||||
build/matter-dev.js
|
build/matter-dev.js
|
||||||
build/matter-dev.min.js
|
build/matter-dev.min.js
|
||||||
|
build/matter.dev.js
|
||||||
|
build/matter.dev.min.js
|
||||||
demo/js/lib/matter-dev.js
|
demo/js/lib/matter-dev.js
|
||||||
demo/js/Examples.min.js
|
demo/js/Examples.min.js
|
||||||
examples/build
|
examples/build
|
||||||
|
|
|
@ -3,8 +3,10 @@ sudo: false
|
||||||
node_js:
|
node_js:
|
||||||
- "node"
|
- "node"
|
||||||
install:
|
install:
|
||||||
- npm install
|
- npm ci
|
||||||
script:
|
script:
|
||||||
- npm run lint
|
- npm run lint
|
||||||
|
- npm run benchmark
|
||||||
- npm run test
|
- npm run test
|
||||||
- npm run build
|
- 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)
|
## 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))
|
* 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
|
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.
|
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
|
The following development commands can be run at the terminal
|
||||||
|
|
||||||
- **npm run dev**
|
- **npm start**
|
||||||
runs development server
|
runs development server and opens demo page
|
||||||
- **npm run build**
|
- **npm run build**
|
||||||
creates a release build
|
creates a release build
|
||||||
|
- **npm run build-demo**
|
||||||
|
builds the demo
|
||||||
- **npm run lint**
|
- **npm run lint**
|
||||||
runs the linter
|
runs the linter
|
||||||
- **npm run test**
|
- **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/#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/#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/#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/#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/#stress">Stress 1</a></li>
|
||||||
<li><a href="https://brm.io/matter-js/demo/#stress2">Stress 2</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>
|
<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
|
### 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.
|
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`
|
## ▲.● 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.
|
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.
|
||||||
|
|
7647
build/matter.js
7647
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-capable" content="yes">
|
||||||
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
|
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
|
||||||
<meta name="robots" content="noindex">
|
<meta name="robots" content="noindex">
|
||||||
|
|
||||||
<title>Matter.js Demo</title>
|
<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">
|
<style type="text/css">
|
||||||
* {
|
* {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
@ -41,7 +21,13 @@
|
||||||
padding: 0;
|
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;
|
position: absolute;
|
||||||
background: none;
|
background: none;
|
||||||
top: 0;
|
top: 0;
|
||||||
|
@ -53,21 +39,22 @@
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.matter-js-compare-build .matter-header-outer {
|
.matter-js-compare-build.matter-demo .matter-header-outer {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.matter-js-compare-build canvas {
|
.matter-js-compare-build.matter-demo canvas {
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
background: transparent !important;
|
background: transparent !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.matter-demo canvas {
|
|
||||||
border: 1px solid rgba(255, 255, 255, 0.07);
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<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>
|
</body>
|
||||||
</html>
|
</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,
|
Runner = Matter.Runner,
|
||||||
MouseConstraint = Matter.MouseConstraint,
|
MouseConstraint = Matter.MouseConstraint,
|
||||||
Mouse = Matter.Mouse,
|
Mouse = Matter.Mouse,
|
||||||
World = Matter.World,
|
Composite = Matter.Composite,
|
||||||
Bodies = Matter.Bodies;
|
Bodies = Matter.Bodies;
|
||||||
|
|
||||||
// create engine
|
// create engine
|
||||||
|
@ -31,7 +31,7 @@ Example.airFriction = function() {
|
||||||
Runner.run(runner, engine);
|
Runner.run(runner, engine);
|
||||||
|
|
||||||
// add bodies
|
// add bodies
|
||||||
World.add(world, [
|
Composite.add(world, [
|
||||||
// falling blocks
|
// falling blocks
|
||||||
Bodies.rectangle(200, 100, 60, 60, { frictionAir: 0.001 }),
|
Bodies.rectangle(200, 100, 60, 60, { frictionAir: 0.001 }),
|
||||||
Bodies.rectangle(400, 100, 60, 60, { frictionAir: 0.05 }),
|
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
|
// keep the mouse in sync with rendering
|
||||||
render.mouse = mouse;
|
render.mouse = mouse;
|
||||||
|
@ -80,6 +80,7 @@ Example.airFriction = function() {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Example.airFriction.title = 'Air Friction';
|
||||||
Example.airFriction.for = '>=0.14.2';
|
Example.airFriction.for = '>=0.14.2';
|
||||||
|
|
||||||
if (typeof module !== 'undefined') {
|
if (typeof module !== 'undefined') {
|
||||||
|
|
|
@ -1,9 +1,17 @@
|
||||||
var Example = Example || {};
|
var Example = Example || {};
|
||||||
|
|
||||||
Example.avalanche = function() {
|
Example.avalanche = function() {
|
||||||
Matter.use(
|
try {
|
||||||
'matter-wrap'
|
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,
|
var Engine = Matter.Engine,
|
||||||
Render = Matter.Render,
|
Render = Matter.Render,
|
||||||
|
@ -13,7 +21,6 @@ Example.avalanche = function() {
|
||||||
Common = Matter.Common,
|
Common = Matter.Common,
|
||||||
MouseConstraint = Matter.MouseConstraint,
|
MouseConstraint = Matter.MouseConstraint,
|
||||||
Mouse = Matter.Mouse,
|
Mouse = Matter.Mouse,
|
||||||
World = Matter.World,
|
|
||||||
Bodies = Matter.Bodies;
|
Bodies = Matter.Bodies;
|
||||||
|
|
||||||
// create engine
|
// 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 });
|
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(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(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' } })
|
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
|
// keep the mouse in sync with rendering
|
||||||
render.mouse = mouse;
|
render.mouse = mouse;
|
||||||
|
@ -91,6 +98,7 @@ Example.avalanche = function() {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Example.avalanche.title = 'Avalanche';
|
||||||
Example.avalanche.for = '>=0.14.2';
|
Example.avalanche.for = '>=0.14.2';
|
||||||
|
|
||||||
if (typeof module !== 'undefined') {
|
if (typeof module !== 'undefined') {
|
||||||
|
|
|
@ -1,9 +1,17 @@
|
||||||
var Example = Example || {};
|
var Example = Example || {};
|
||||||
|
|
||||||
Example.ballPool = function() {
|
Example.ballPool = function() {
|
||||||
Matter.use(
|
try {
|
||||||
'matter-wrap'
|
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,
|
var Engine = Matter.Engine,
|
||||||
Render = Matter.Render,
|
Render = Matter.Render,
|
||||||
|
@ -13,7 +21,6 @@ Example.ballPool = function() {
|
||||||
Common = Matter.Common,
|
Common = Matter.Common,
|
||||||
MouseConstraint = Matter.MouseConstraint,
|
MouseConstraint = Matter.MouseConstraint,
|
||||||
Mouse = Matter.Mouse,
|
Mouse = Matter.Mouse,
|
||||||
World = Matter.World,
|
|
||||||
Bodies = Matter.Bodies;
|
Bodies = Matter.Bodies;
|
||||||
|
|
||||||
// create engine
|
// create engine
|
||||||
|
@ -38,7 +45,7 @@ Example.ballPool = function() {
|
||||||
Runner.run(runner, engine);
|
Runner.run(runner, engine);
|
||||||
|
|
||||||
// add bodies
|
// add bodies
|
||||||
World.add(world, [
|
Composite.add(world, [
|
||||||
Bodies.rectangle(400, 600, 1200, 50.5, { isStatic: true, render: { fillStyle: '#060a19' } })
|
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 });
|
return Bodies.circle(x, y, Common.random(15, 30), { restitution: 0.6, friction: 0.1 });
|
||||||
});
|
});
|
||||||
|
|
||||||
World.add(world, [
|
Composite.add(world, [
|
||||||
stack,
|
stack,
|
||||||
Bodies.polygon(200, 460, 3, 60),
|
Bodies.polygon(200, 460, 3, 60),
|
||||||
Bodies.polygon(400, 460, 5, 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
|
// keep the mouse in sync with rendering
|
||||||
render.mouse = mouse;
|
render.mouse = mouse;
|
||||||
|
@ -99,6 +106,7 @@ Example.ballPool = function() {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Example.ballPool.title = 'Ball Pool';
|
||||||
Example.ballPool.for = '>=0.14.2';
|
Example.ballPool.for = '>=0.14.2';
|
||||||
|
|
||||||
if (typeof module !== 'undefined') {
|
if (typeof module !== 'undefined') {
|
||||||
|
|
|
@ -10,7 +10,7 @@ Example.bridge = function() {
|
||||||
Constraint = Matter.Constraint,
|
Constraint = Matter.Constraint,
|
||||||
MouseConstraint = Matter.MouseConstraint,
|
MouseConstraint = Matter.MouseConstraint,
|
||||||
Mouse = Matter.Mouse,
|
Mouse = Matter.Mouse,
|
||||||
World = Matter.World,
|
Composite = Matter.Composite,
|
||||||
Bodies = Matter.Bodies;
|
Bodies = Matter.Bodies;
|
||||||
|
|
||||||
// create engine
|
// create engine
|
||||||
|
@ -61,7 +61,7 @@ Example.bridge = function() {
|
||||||
return Bodies.rectangle(x, y, 50, 50, Common.random(20, 40));
|
return Bodies.rectangle(x, y, 50, 50, Common.random(20, 40));
|
||||||
});
|
});
|
||||||
|
|
||||||
World.add(world, [
|
Composite.add(world, [
|
||||||
bridge,
|
bridge,
|
||||||
stack,
|
stack,
|
||||||
Bodies.rectangle(30, 490, 220, 380, {
|
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
|
// keep the mouse in sync with rendering
|
||||||
render.mouse = mouse;
|
render.mouse = mouse;
|
||||||
|
@ -124,6 +124,7 @@ Example.bridge = function() {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Example.bridge.title = 'Bridge';
|
||||||
Example.bridge.for = '>=0.14.2';
|
Example.bridge.for = '>=0.14.2';
|
||||||
|
|
||||||
if (typeof module !== 'undefined') {
|
if (typeof module !== 'undefined') {
|
||||||
|
|
|
@ -7,7 +7,7 @@ Example.car = function() {
|
||||||
Composites = Matter.Composites,
|
Composites = Matter.Composites,
|
||||||
MouseConstraint = Matter.MouseConstraint,
|
MouseConstraint = Matter.MouseConstraint,
|
||||||
Mouse = Matter.Mouse,
|
Mouse = Matter.Mouse,
|
||||||
World = Matter.World,
|
Composite = Matter.Composite,
|
||||||
Bodies = Matter.Bodies;
|
Bodies = Matter.Bodies;
|
||||||
|
|
||||||
// create engine
|
// create engine
|
||||||
|
@ -33,7 +33,7 @@ Example.car = function() {
|
||||||
Runner.run(runner, engine);
|
Runner.run(runner, engine);
|
||||||
|
|
||||||
// add bodies
|
// add bodies
|
||||||
World.add(world, [
|
Composite.add(world, [
|
||||||
// walls
|
// walls
|
||||||
Bodies.rectangle(400, 0, 800, 50, { isStatic: true }),
|
Bodies.rectangle(400, 0, 800, 50, { isStatic: true }),
|
||||||
Bodies.rectangle(400, 600, 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 })
|
Bodies.rectangle(0, 300, 50, 600, { isStatic: true })
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
// see car function defined later in this file
|
||||||
var scale = 0.9;
|
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;
|
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(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(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' }})
|
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
|
// keep the mouse in sync with rendering
|
||||||
render.mouse = mouse;
|
render.mouse = mouse;
|
||||||
|
@ -89,8 +90,81 @@ Example.car = function() {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Example.car.title = 'Car';
|
||||||
Example.car.for = '>=0.14.2';
|
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') {
|
if (typeof module !== 'undefined') {
|
||||||
module.exports = Example.car;
|
module.exports = Example.car;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ Example.catapult = function() {
|
||||||
Constraint = Matter.Constraint,
|
Constraint = Matter.Constraint,
|
||||||
MouseConstraint = Matter.MouseConstraint,
|
MouseConstraint = Matter.MouseConstraint,
|
||||||
Mouse = Matter.Mouse,
|
Mouse = Matter.Mouse,
|
||||||
World = Matter.World,
|
Composite = Matter.Composite,
|
||||||
Bodies = Matter.Bodies,
|
Bodies = Matter.Bodies,
|
||||||
Body = Matter.Body,
|
Body = Matter.Body,
|
||||||
Vector = Matter.Vector;
|
Vector = Matter.Vector;
|
||||||
|
@ -45,7 +45,7 @@ Example.catapult = function() {
|
||||||
|
|
||||||
var catapult = Bodies.rectangle(400, 520, 320, 20, { collisionFilter: { group: group } });
|
var catapult = Bodies.rectangle(400, 520, 320, 20, { collisionFilter: { group: group } });
|
||||||
|
|
||||||
World.add(world, [
|
Composite.add(world, [
|
||||||
stack,
|
stack,
|
||||||
catapult,
|
catapult,
|
||||||
Bodies.rectangle(400, 600, 800, 50.5, { isStatic: true, render: { fillStyle: '#060a19' } }),
|
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
|
// keep the mouse in sync with rendering
|
||||||
render.mouse = mouse;
|
render.mouse = mouse;
|
||||||
|
@ -96,6 +96,7 @@ Example.catapult = function() {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Example.catapult.title = 'Catapult';
|
||||||
Example.catapult.for = '>=0.14.2';
|
Example.catapult.for = '>=0.14.2';
|
||||||
|
|
||||||
if (typeof module !== 'undefined') {
|
if (typeof module !== 'undefined') {
|
||||||
|
|
|
@ -10,7 +10,6 @@ Example.chains = function() {
|
||||||
Constraint = Matter.Constraint,
|
Constraint = Matter.Constraint,
|
||||||
MouseConstraint = Matter.MouseConstraint,
|
MouseConstraint = Matter.MouseConstraint,
|
||||||
Mouse = Matter.Mouse,
|
Mouse = Matter.Mouse,
|
||||||
World = Matter.World,
|
|
||||||
Bodies = Matter.Bodies;
|
Bodies = Matter.Bodies;
|
||||||
|
|
||||||
// create engine
|
// create engine
|
||||||
|
@ -79,7 +78,7 @@ Example.chains = function() {
|
||||||
stiffness: 0.5
|
stiffness: 0.5
|
||||||
}));
|
}));
|
||||||
|
|
||||||
World.add(world, [
|
Composite.add(world, [
|
||||||
ropeA,
|
ropeA,
|
||||||
ropeB,
|
ropeB,
|
||||||
ropeC,
|
ropeC,
|
||||||
|
@ -98,7 +97,7 @@ Example.chains = function() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
World.add(world, mouseConstraint);
|
Composite.add(world, mouseConstraint);
|
||||||
|
|
||||||
// keep the mouse in sync with rendering
|
// keep the mouse in sync with rendering
|
||||||
render.mouse = mouse;
|
render.mouse = mouse;
|
||||||
|
@ -122,6 +121,7 @@ Example.chains = function() {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Example.chains.title = 'Chains';
|
||||||
Example.chains.for = '>=0.14.2';
|
Example.chains.for = '>=0.14.2';
|
||||||
|
|
||||||
if (typeof module !== 'undefined') {
|
if (typeof module !== 'undefined') {
|
||||||
|
|
|
@ -7,7 +7,7 @@ Example.circleStack = function() {
|
||||||
Composites = Matter.Composites,
|
Composites = Matter.Composites,
|
||||||
MouseConstraint = Matter.MouseConstraint,
|
MouseConstraint = Matter.MouseConstraint,
|
||||||
Mouse = Matter.Mouse,
|
Mouse = Matter.Mouse,
|
||||||
World = Matter.World,
|
Composite = Matter.Composite,
|
||||||
Bodies = Matter.Bodies;
|
Bodies = Matter.Bodies;
|
||||||
|
|
||||||
// create engine
|
// create engine
|
||||||
|
@ -32,11 +32,11 @@ Example.circleStack = function() {
|
||||||
Runner.run(runner, engine);
|
Runner.run(runner, engine);
|
||||||
|
|
||||||
// add bodies
|
// 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);
|
return Bodies.circle(x, y, 20);
|
||||||
});
|
});
|
||||||
|
|
||||||
World.add(world, [
|
Composite.add(world, [
|
||||||
// walls
|
// walls
|
||||||
Bodies.rectangle(400, 0, 800, 50, { isStatic: true }),
|
Bodies.rectangle(400, 0, 800, 50, { isStatic: true }),
|
||||||
Bodies.rectangle(400, 600, 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
|
// keep the mouse in sync with rendering
|
||||||
render.mouse = mouse;
|
render.mouse = mouse;
|
||||||
|
@ -81,6 +81,7 @@ Example.circleStack = function() {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Example.circleStack.title = 'Circle Stack';
|
||||||
Example.circleStack.for = '>=0.14.2';
|
Example.circleStack.for = '>=0.14.2';
|
||||||
|
|
||||||
if (typeof module !== 'undefined') {
|
if (typeof module !== 'undefined') {
|
||||||
|
|
|
@ -8,7 +8,7 @@ Example.cloth = function() {
|
||||||
Composites = Matter.Composites,
|
Composites = Matter.Composites,
|
||||||
MouseConstraint = Matter.MouseConstraint,
|
MouseConstraint = Matter.MouseConstraint,
|
||||||
Mouse = Matter.Mouse,
|
Mouse = Matter.Mouse,
|
||||||
World = Matter.World,
|
Composite = Matter.Composite,
|
||||||
Bodies = Matter.Bodies;
|
Bodies = Matter.Bodies;
|
||||||
|
|
||||||
// create engine
|
// create engine
|
||||||
|
@ -31,17 +31,14 @@ Example.cloth = function() {
|
||||||
var runner = Runner.create();
|
var runner = Runner.create();
|
||||||
Runner.run(runner, engine);
|
Runner.run(runner, engine);
|
||||||
|
|
||||||
// add bodies
|
// see cloth function defined later in this file
|
||||||
var group = Body.nextGroup(true),
|
var cloth = Example.cloth.cloth(200, 200, 20, 12, 5, 5, false, 8);
|
||||||
particleOptions = { friction: 0.00001, collisionFilter: { group: group }, render: { visible: false }},
|
|
||||||
constraintOptions = { stiffness: 0.06 },
|
|
||||||
cloth = Composites.softBody(200, 200, 20, 12, 5, 5, false, 8, particleOptions, constraintOptions);
|
|
||||||
|
|
||||||
for (var i = 0; i < 20; i++) {
|
for (var i = 0; i < 20; i++) {
|
||||||
cloth.bodies[i].isStatic = true;
|
cloth.bodies[i].isStatic = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
World.add(world, [
|
Composite.add(world, [
|
||||||
cloth,
|
cloth,
|
||||||
Bodies.circle(300, 500, 80, { isStatic: true, render: { fillStyle: '#060a19' }}),
|
Bodies.circle(300, 500, 80, { isStatic: true, render: { fillStyle: '#060a19' }}),
|
||||||
Bodies.rectangle(500, 480, 80, 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
|
// keep the mouse in sync with rendering
|
||||||
render.mouse = mouse;
|
render.mouse = mouse;
|
||||||
|
@ -84,8 +81,45 @@ Example.cloth = function() {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Example.cloth.title = 'Cloth';
|
||||||
Example.cloth.for = '>=0.14.2';
|
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') {
|
if (typeof module !== 'undefined') {
|
||||||
module.exports = Example.cloth;
|
module.exports = Example.cloth;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,6 @@ Example.collisionFiltering = function() {
|
||||||
Common = Matter.Common,
|
Common = Matter.Common,
|
||||||
MouseConstraint = Matter.MouseConstraint,
|
MouseConstraint = Matter.MouseConstraint,
|
||||||
Mouse = Matter.Mouse,
|
Mouse = Matter.Mouse,
|
||||||
World = Matter.World,
|
|
||||||
Bodies = Matter.Bodies;
|
Bodies = Matter.Bodies;
|
||||||
|
|
||||||
// create engine
|
// create engine
|
||||||
|
@ -44,7 +43,7 @@ Example.collisionFiltering = function() {
|
||||||
colorC = '#f5d259';
|
colorC = '#f5d259';
|
||||||
|
|
||||||
// add floor
|
// add floor
|
||||||
World.add(world, Bodies.rectangle(400, 600, 900, 50, {
|
Composite.add(world, Bodies.rectangle(400, 600, 900, 50, {
|
||||||
isStatic: true,
|
isStatic: true,
|
||||||
render: {
|
render: {
|
||||||
fillStyle: 'transparent',
|
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)
|
// 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) {
|
Composites.stack(275, 100, 5, 9, 10, 10, function(x, y, column, row) {
|
||||||
var category = redCategory,
|
var category = redCategory,
|
||||||
color = colorA;
|
color = colorA;
|
||||||
|
@ -80,7 +79,7 @@ Example.collisionFiltering = function() {
|
||||||
);
|
);
|
||||||
|
|
||||||
// this body will only collide with the walls and the green bodies
|
// this body will only collide with the walls and the green bodies
|
||||||
World.add(world,
|
Composite.add(world,
|
||||||
Bodies.circle(310, 40, 30, {
|
Bodies.circle(310, 40, 30, {
|
||||||
collisionFilter: {
|
collisionFilter: {
|
||||||
mask: defaultCategory | greenCategory
|
mask: defaultCategory | greenCategory
|
||||||
|
@ -92,7 +91,7 @@ Example.collisionFiltering = function() {
|
||||||
);
|
);
|
||||||
|
|
||||||
// this body will only collide with the walls and the red bodies
|
// this body will only collide with the walls and the red bodies
|
||||||
World.add(world,
|
Composite.add(world,
|
||||||
Bodies.circle(400, 40, 30, {
|
Bodies.circle(400, 40, 30, {
|
||||||
collisionFilter: {
|
collisionFilter: {
|
||||||
mask: defaultCategory | redCategory
|
mask: defaultCategory | redCategory
|
||||||
|
@ -104,7 +103,7 @@ Example.collisionFiltering = function() {
|
||||||
);
|
);
|
||||||
|
|
||||||
// this body will only collide with the walls and the blue bodies
|
// this body will only collide with the walls and the blue bodies
|
||||||
World.add(world,
|
Composite.add(world,
|
||||||
Bodies.circle(480, 40, 30, {
|
Bodies.circle(480, 40, 30, {
|
||||||
collisionFilter: {
|
collisionFilter: {
|
||||||
mask: defaultCategory | blueCategory
|
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
|
// keep the mouse in sync with rendering
|
||||||
render.mouse = mouse;
|
render.mouse = mouse;
|
||||||
|
@ -154,6 +153,7 @@ Example.collisionFiltering = function() {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Example.collisionFiltering.title = 'Collision Filtering';
|
||||||
Example.collisionFiltering.for = '>=0.14.2';
|
Example.collisionFiltering.for = '>=0.14.2';
|
||||||
|
|
||||||
if (typeof module !== 'undefined') {
|
if (typeof module !== 'undefined') {
|
||||||
|
|
|
@ -9,7 +9,6 @@ Example.compositeManipulation = function() {
|
||||||
Composites = Matter.Composites,
|
Composites = Matter.Composites,
|
||||||
MouseConstraint = Matter.MouseConstraint,
|
MouseConstraint = Matter.MouseConstraint,
|
||||||
Mouse = Matter.Mouse,
|
Mouse = Matter.Mouse,
|
||||||
World = Matter.World,
|
|
||||||
Bodies = Matter.Bodies;
|
Bodies = Matter.Bodies;
|
||||||
|
|
||||||
// create engine
|
// create engine
|
||||||
|
@ -34,7 +33,7 @@ Example.compositeManipulation = function() {
|
||||||
Runner.run(runner, engine);
|
Runner.run(runner, engine);
|
||||||
|
|
||||||
// add bodies
|
// add bodies
|
||||||
World.add(world, [
|
Composite.add(world, [
|
||||||
// walls
|
// walls
|
||||||
Bodies.rectangle(400, 0, 800, 50, { isStatic: true }),
|
Bodies.rectangle(400, 0, 800, 50, { isStatic: true }),
|
||||||
Bodies.rectangle(400, 600, 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);
|
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) {
|
Events.on(engine, 'afterUpdate', function(event) {
|
||||||
var time = engine.timing.timestamp,
|
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
|
// keep the mouse in sync with rendering
|
||||||
render.mouse = mouse;
|
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') {
|
if (typeof module !== 'undefined') {
|
||||||
module.exports = Example.compositeManipulation;
|
module.exports = Example.compositeManipulation;
|
||||||
|
|
|
@ -6,9 +6,9 @@ Example.compound = function() {
|
||||||
Runner = Matter.Runner,
|
Runner = Matter.Runner,
|
||||||
Body = Matter.Body,
|
Body = Matter.Body,
|
||||||
Constraint = Matter.Constraint,
|
Constraint = Matter.Constraint,
|
||||||
|
Composite = Matter.Composite,
|
||||||
MouseConstraint = Matter.MouseConstraint,
|
MouseConstraint = Matter.MouseConstraint,
|
||||||
Mouse = Matter.Mouse,
|
Mouse = Matter.Mouse,
|
||||||
World = Matter.World,
|
|
||||||
Bodies = Matter.Bodies;
|
Bodies = Matter.Bodies;
|
||||||
|
|
||||||
// create engine
|
// create engine
|
||||||
|
@ -63,7 +63,7 @@ Example.compound = function() {
|
||||||
pointB: { x: 0, y: 0 }
|
pointB: { x: 0, y: 0 }
|
||||||
});
|
});
|
||||||
|
|
||||||
World.add(world, [
|
Composite.add(world, [
|
||||||
compoundBodyA,
|
compoundBodyA,
|
||||||
compoundBodyB,
|
compoundBodyB,
|
||||||
constraint,
|
constraint,
|
||||||
|
@ -82,7 +82,7 @@ Example.compound = function() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
World.add(world, mouseConstraint);
|
Composite.add(world, mouseConstraint);
|
||||||
|
|
||||||
// keep the mouse in sync with rendering
|
// keep the mouse in sync with rendering
|
||||||
render.mouse = mouse;
|
render.mouse = mouse;
|
||||||
|
@ -106,6 +106,7 @@ Example.compound = function() {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Example.compound.title = 'Compound Bodies';
|
||||||
Example.compound.for = '>=0.14.2';
|
Example.compound.for = '>=0.14.2';
|
||||||
|
|
||||||
if (typeof module !== 'undefined') {
|
if (typeof module !== 'undefined') {
|
||||||
|
|
|
@ -8,7 +8,7 @@ Example.compoundStack = function() {
|
||||||
Composites = Matter.Composites,
|
Composites = Matter.Composites,
|
||||||
MouseConstraint = Matter.MouseConstraint,
|
MouseConstraint = Matter.MouseConstraint,
|
||||||
Mouse = Matter.Mouse,
|
Mouse = Matter.Mouse,
|
||||||
World = Matter.World,
|
Composite = Matter.Composite,
|
||||||
Bodies = Matter.Bodies;
|
Bodies = Matter.Bodies;
|
||||||
|
|
||||||
// create engine
|
// create engine
|
||||||
|
@ -35,7 +35,7 @@ Example.compoundStack = function() {
|
||||||
// add bodies
|
// add bodies
|
||||||
var size = 50;
|
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),
|
var partA = Bodies.rectangle(x, y, size, size / 5),
|
||||||
partB = Bodies.rectangle(x, y, size / 5, size, { render: partA.render });
|
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,
|
stack,
|
||||||
// walls
|
// walls
|
||||||
Bodies.rectangle(400, 0, 800, 50, { isStatic: true }),
|
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
|
// keep the mouse in sync with rendering
|
||||||
render.mouse = mouse;
|
render.mouse = mouse;
|
||||||
|
@ -89,6 +89,7 @@ Example.compoundStack = function() {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Example.compoundStack.title = 'Compound Stack';
|
||||||
Example.compoundStack.for = '>=0.14.2';
|
Example.compoundStack.for = '>=0.14.2';
|
||||||
|
|
||||||
if (typeof module !== 'undefined') {
|
if (typeof module !== 'undefined') {
|
||||||
|
|
|
@ -8,10 +8,13 @@ Example.concave = function() {
|
||||||
Common = Matter.Common,
|
Common = Matter.Common,
|
||||||
MouseConstraint = Matter.MouseConstraint,
|
MouseConstraint = Matter.MouseConstraint,
|
||||||
Mouse = Matter.Mouse,
|
Mouse = Matter.Mouse,
|
||||||
World = Matter.World,
|
Composite = Matter.Composite,
|
||||||
Vertices = Matter.Vertices,
|
Vertices = Matter.Vertices,
|
||||||
Bodies = Matter.Bodies;
|
Bodies = Matter.Bodies;
|
||||||
|
|
||||||
|
// provide concave decomposition support library
|
||||||
|
Common.setDecomp(require('poly-decomp'));
|
||||||
|
|
||||||
// create engine
|
// create engine
|
||||||
var engine = Engine.create(),
|
var engine = Engine.create(),
|
||||||
world = engine.world;
|
world = engine.world;
|
||||||
|
@ -33,7 +36,7 @@ Example.concave = function() {
|
||||||
Runner.run(runner, engine);
|
Runner.run(runner, engine);
|
||||||
|
|
||||||
// add bodies
|
// add bodies
|
||||||
World.add(world, [
|
Composite.add(world, [
|
||||||
// walls
|
// walls
|
||||||
Bodies.rectangle(400, 0, 800, 50, { isStatic: true }),
|
Bodies.rectangle(400, 0, 800, 50, { isStatic: true }),
|
||||||
Bodies.rectangle(400, 600, 800, 50, { isStatic: true }),
|
Bodies.rectangle(400, 600, 800, 50, { isStatic: true }),
|
||||||
|
@ -57,7 +60,7 @@ Example.concave = function() {
|
||||||
}, true);
|
}, true);
|
||||||
});
|
});
|
||||||
|
|
||||||
World.add(world, stack);
|
Composite.add(world, stack);
|
||||||
|
|
||||||
// add mouse control
|
// add mouse control
|
||||||
var mouse = Mouse.create(render.canvas),
|
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
|
// keep the mouse in sync with rendering
|
||||||
render.mouse = mouse;
|
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') {
|
if (typeof module !== 'undefined') {
|
||||||
module.exports = Example.concave;
|
module.exports = Example.concave;
|
||||||
|
|
|
@ -9,7 +9,7 @@ Example.constraints = function() {
|
||||||
Constraint = Matter.Constraint,
|
Constraint = Matter.Constraint,
|
||||||
MouseConstraint = Matter.MouseConstraint,
|
MouseConstraint = Matter.MouseConstraint,
|
||||||
Mouse = Matter.Mouse,
|
Mouse = Matter.Mouse,
|
||||||
World = Matter.World,
|
Composite = Matter.Composite,
|
||||||
Bodies = Matter.Bodies;
|
Bodies = Matter.Bodies;
|
||||||
|
|
||||||
// create engine
|
// create engine
|
||||||
|
@ -42,7 +42,7 @@ Example.constraints = function() {
|
||||||
pointB: { x: -10, y: -10 }
|
pointB: { x: -10, y: -10 }
|
||||||
});
|
});
|
||||||
|
|
||||||
World.add(world, [body, constraint]);
|
Composite.add(world, [body, constraint]);
|
||||||
|
|
||||||
// add soft global constraint
|
// add soft global constraint
|
||||||
var body = Bodies.polygon(280, 100, 3, 30);
|
var body = Bodies.polygon(280, 100, 3, 30);
|
||||||
|
@ -54,7 +54,7 @@ Example.constraints = function() {
|
||||||
stiffness: 0.001
|
stiffness: 0.001
|
||||||
});
|
});
|
||||||
|
|
||||||
World.add(world, [body, constraint]);
|
Composite.add(world, [body, constraint]);
|
||||||
|
|
||||||
// add damped soft global constraint
|
// add damped soft global constraint
|
||||||
var body = Bodies.polygon(400, 100, 4, 30);
|
var body = Bodies.polygon(400, 100, 4, 30);
|
||||||
|
@ -67,7 +67,7 @@ Example.constraints = function() {
|
||||||
damping: 0.05
|
damping: 0.05
|
||||||
});
|
});
|
||||||
|
|
||||||
World.add(world, [body, constraint]);
|
Composite.add(world, [body, constraint]);
|
||||||
|
|
||||||
// add revolute constraint
|
// add revolute constraint
|
||||||
var body = Bodies.rectangle(600, 200, 200, 20);
|
var body = Bodies.rectangle(600, 200, 200, 20);
|
||||||
|
@ -79,7 +79,7 @@ Example.constraints = function() {
|
||||||
length: 0
|
length: 0
|
||||||
});
|
});
|
||||||
|
|
||||||
World.add(world, [body, ball, constraint]);
|
Composite.add(world, [body, ball, constraint]);
|
||||||
|
|
||||||
// add revolute multi-body constraint
|
// add revolute multi-body constraint
|
||||||
var body = Bodies.rectangle(500, 400, 100, 20, { collisionFilter: { group: -1 } });
|
var body = Bodies.rectangle(500, 400, 100, 20, { collisionFilter: { group: -1 } });
|
||||||
|
@ -90,7 +90,7 @@ Example.constraints = function() {
|
||||||
bodyB: ball
|
bodyB: ball
|
||||||
});
|
});
|
||||||
|
|
||||||
World.add(world, [body, ball, constraint]);
|
Composite.add(world, [body, ball, constraint]);
|
||||||
|
|
||||||
// add stiff multi-body constraint
|
// add stiff multi-body constraint
|
||||||
var bodyA = Bodies.polygon(100, 400, 6, 20);
|
var bodyA = Bodies.polygon(100, 400, 6, 20);
|
||||||
|
@ -103,7 +103,7 @@ Example.constraints = function() {
|
||||||
pointB: { x: -10, y: -10 }
|
pointB: { x: -10, y: -10 }
|
||||||
});
|
});
|
||||||
|
|
||||||
World.add(world, [bodyA, bodyB, constraint]);
|
Composite.add(world, [bodyA, bodyB, constraint]);
|
||||||
|
|
||||||
// add soft global constraint
|
// add soft global constraint
|
||||||
var bodyA = Bodies.polygon(300, 400, 4, 20);
|
var bodyA = Bodies.polygon(300, 400, 4, 20);
|
||||||
|
@ -117,7 +117,7 @@ Example.constraints = function() {
|
||||||
stiffness: 0.001
|
stiffness: 0.001
|
||||||
});
|
});
|
||||||
|
|
||||||
World.add(world, [bodyA, bodyB, constraint]);
|
Composite.add(world, [bodyA, bodyB, constraint]);
|
||||||
|
|
||||||
// add damped soft global constraint
|
// add damped soft global constraint
|
||||||
var bodyA = Bodies.polygon(500, 400, 6, 30);
|
var bodyA = Bodies.polygon(500, 400, 6, 30);
|
||||||
|
@ -132,9 +132,9 @@ Example.constraints = function() {
|
||||||
damping: 0.1
|
damping: 0.1
|
||||||
});
|
});
|
||||||
|
|
||||||
World.add(world, [bodyA, bodyB, constraint]);
|
Composite.add(world, [bodyA, bodyB, constraint]);
|
||||||
|
|
||||||
World.add(world, [
|
Composite.add(world, [
|
||||||
// walls
|
// walls
|
||||||
Bodies.rectangle(400, 0, 800, 50, { isStatic: true }),
|
Bodies.rectangle(400, 0, 800, 50, { isStatic: true }),
|
||||||
Bodies.rectangle(400, 600, 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
|
// keep the mouse in sync with rendering
|
||||||
render.mouse = mouse;
|
render.mouse = mouse;
|
||||||
|
@ -179,6 +179,7 @@ Example.constraints = function() {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Example.constraints.title = 'Constraints';
|
||||||
Example.constraints.for = '>=0.14.2';
|
Example.constraints.for = '>=0.14.2';
|
||||||
|
|
||||||
if (typeof module !== 'undefined') {
|
if (typeof module !== 'undefined') {
|
||||||
|
|
|
@ -11,7 +11,6 @@ Example.doublePendulum = function() {
|
||||||
Constraint = Matter.Constraint,
|
Constraint = Matter.Constraint,
|
||||||
MouseConstraint = Matter.MouseConstraint,
|
MouseConstraint = Matter.MouseConstraint,
|
||||||
Mouse = Matter.Mouse,
|
Mouse = Matter.Mouse,
|
||||||
World = Matter.World,
|
|
||||||
Bodies = Matter.Bodies,
|
Bodies = Matter.Bodies,
|
||||||
Vector = Matter.Vector;
|
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, {
|
Composites.chain(pendulum, 0.45, 0, -0.45, 0, {
|
||||||
stiffness: 0.9,
|
stiffness: 0.9,
|
||||||
|
@ -82,7 +81,7 @@ Example.doublePendulum = function() {
|
||||||
y: lowerArm.position.y
|
y: lowerArm.position.y
|
||||||
});
|
});
|
||||||
|
|
||||||
World.add(world, pendulum);
|
Composite.add(world, pendulum);
|
||||||
|
|
||||||
var trail = [];
|
var trail = [];
|
||||||
|
|
||||||
|
@ -124,7 +123,7 @@ Example.doublePendulum = function() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
World.add(world, mouseConstraint);
|
Composite.add(world, mouseConstraint);
|
||||||
|
|
||||||
// keep the mouse in sync with rendering
|
// keep the mouse in sync with rendering
|
||||||
render.mouse = mouse;
|
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') {
|
if (typeof module !== 'undefined') {
|
||||||
module.exports = Example.doublePendulum;
|
module.exports = Example.doublePendulum;
|
||||||
|
|
|
@ -11,7 +11,6 @@ Example.events = function() {
|
||||||
Common = Matter.Common,
|
Common = Matter.Common,
|
||||||
MouseConstraint = Matter.MouseConstraint,
|
MouseConstraint = Matter.MouseConstraint,
|
||||||
Mouse = Matter.Mouse,
|
Mouse = Matter.Mouse,
|
||||||
World = Matter.World,
|
|
||||||
Bodies = Matter.Bodies;
|
Bodies = Matter.Bodies;
|
||||||
|
|
||||||
// create engine
|
// create engine
|
||||||
|
@ -37,7 +36,7 @@ Example.events = function() {
|
||||||
|
|
||||||
// an example of using composite events on the world
|
// an example of using composite events on the world
|
||||||
Events.on(world, 'afterAdd', function(event) {
|
Events.on(world, 'afterAdd', function(event) {
|
||||||
console.log('added to world:', event.object);
|
// do something with event.object
|
||||||
});
|
});
|
||||||
|
|
||||||
var lastTime = Common.now();
|
var lastTime = Common.now();
|
||||||
|
@ -95,7 +94,7 @@ Example.events = function() {
|
||||||
var bodyStyle = { fillStyle: '#222' };
|
var bodyStyle = { fillStyle: '#222' };
|
||||||
|
|
||||||
// scene code
|
// scene code
|
||||||
World.add(world, [
|
Composite.add(world, [
|
||||||
Bodies.rectangle(400, 0, 800, 50, { isStatic: true, render: bodyStyle }),
|
Bodies.rectangle(400, 0, 800, 50, { isStatic: true, render: bodyStyle }),
|
||||||
Bodies.rectangle(400, 600, 800, 50, { isStatic: true, render: bodyStyle }),
|
Bodies.rectangle(400, 600, 800, 50, { isStatic: true, render: bodyStyle }),
|
||||||
Bodies.rectangle(800, 300, 50, 600, { isStatic: true, render: bodyStyle }),
|
Bodies.rectangle(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 });
|
return Bodies.circle(x, y, 15, { restitution: 1, render: bodyStyle });
|
||||||
});
|
});
|
||||||
|
|
||||||
World.add(world, stack);
|
Composite.add(world, stack);
|
||||||
|
|
||||||
var shakeScene = function(engine, delta) {
|
var shakeScene = function(engine, delta) {
|
||||||
var timeScale = delta / 1000;
|
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
|
// keep the mouse in sync with rendering
|
||||||
render.mouse = mouse;
|
render.mouse = mouse;
|
||||||
|
@ -186,6 +185,7 @@ Example.events = function() {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Example.events.title = 'Events';
|
||||||
Example.events.for = '>=0.14.2';
|
Example.events.for = '>=0.14.2';
|
||||||
|
|
||||||
if (typeof module !== 'undefined') {
|
if (typeof module !== 'undefined') {
|
||||||
|
|
|
@ -6,7 +6,7 @@ Example.friction = function() {
|
||||||
Runner = Matter.Runner,
|
Runner = Matter.Runner,
|
||||||
MouseConstraint = Matter.MouseConstraint,
|
MouseConstraint = Matter.MouseConstraint,
|
||||||
Mouse = Matter.Mouse,
|
Mouse = Matter.Mouse,
|
||||||
World = Matter.World,
|
Composite = Matter.Composite,
|
||||||
Bodies = Matter.Bodies;
|
Bodies = Matter.Bodies;
|
||||||
|
|
||||||
// create engine
|
// create engine
|
||||||
|
@ -31,7 +31,7 @@ Example.friction = function() {
|
||||||
Runner.run(runner, engine);
|
Runner.run(runner, engine);
|
||||||
|
|
||||||
// add bodies
|
// add bodies
|
||||||
World.add(world, [
|
Composite.add(world, [
|
||||||
// walls
|
// walls
|
||||||
Bodies.rectangle(400, 0, 800, 50, { isStatic: true }),
|
Bodies.rectangle(400, 0, 800, 50, { isStatic: true }),
|
||||||
Bodies.rectangle(400, 600, 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 })
|
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, 180, 700, 20, { isStatic: true, angle: Math.PI * 0.06, render: { fillStyle: '#060a19' } }),
|
||||||
Bodies.rectangle(300, 70, 40, 40, { friction: 0.001 })
|
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, 350, 700, 20, { isStatic: true, angle: Math.PI * 0.06, render: { fillStyle: '#060a19' } }),
|
||||||
Bodies.rectangle(300, 250, 40, 40, { friction: 0.0005 })
|
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, 520, 700, 20, { isStatic: true, angle: Math.PI * 0.06, render: { fillStyle: '#060a19' } }),
|
||||||
Bodies.rectangle(300, 430, 40, 40, { friction: 0 })
|
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
|
// keep the mouse in sync with rendering
|
||||||
render.mouse = mouse;
|
render.mouse = mouse;
|
||||||
|
@ -90,6 +90,7 @@ Example.friction = function() {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Example.friction.title = 'Friction';
|
||||||
Example.friction.for = '>=0.14.2';
|
Example.friction.for = '>=0.14.2';
|
||||||
|
|
||||||
if (typeof module !== 'undefined') {
|
if (typeof module !== 'undefined') {
|
||||||
|
|
|
@ -8,7 +8,7 @@ Example.gravity = function() {
|
||||||
Common = Matter.Common,
|
Common = Matter.Common,
|
||||||
MouseConstraint = Matter.MouseConstraint,
|
MouseConstraint = Matter.MouseConstraint,
|
||||||
Mouse = Matter.Mouse,
|
Mouse = Matter.Mouse,
|
||||||
World = Matter.World,
|
Composite = Matter.Composite,
|
||||||
Bodies = Matter.Bodies;
|
Bodies = Matter.Bodies;
|
||||||
|
|
||||||
// create engine
|
// create engine
|
||||||
|
@ -34,14 +34,14 @@ Example.gravity = function() {
|
||||||
Runner.run(runner, engine);
|
Runner.run(runner, engine);
|
||||||
|
|
||||||
// add bodies
|
// add bodies
|
||||||
World.add(world, [
|
Composite.add(world, [
|
||||||
Bodies.rectangle(400, 0, 800, 50, { isStatic: true }),
|
Bodies.rectangle(400, 0, 800, 50, { isStatic: true }),
|
||||||
Bodies.rectangle(400, 600, 800, 50.5, { isStatic: true }),
|
Bodies.rectangle(400, 600, 800, 50.5, { isStatic: true }),
|
||||||
Bodies.rectangle(800, 300, 50, 600, { isStatic: true }),
|
Bodies.rectangle(800, 300, 50, 600, { isStatic: true }),
|
||||||
Bodies.rectangle(0, 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) {
|
var stack = Composites.stack(50, 120, 11, 5, 0, 0, function(x, y) {
|
||||||
switch (Math.round(Common.random(0, 1))) {
|
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
|
// add mouse control
|
||||||
var mouse = Mouse.create(render.canvas),
|
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
|
// keep the mouse in sync with rendering
|
||||||
render.mouse = mouse;
|
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') {
|
if (typeof module !== 'undefined') {
|
||||||
module.exports = Example.gravity;
|
module.exports = Example.gravity;
|
||||||
|
|
|
@ -8,7 +8,7 @@ Example.gyro = function() {
|
||||||
Common = Matter.Common,
|
Common = Matter.Common,
|
||||||
MouseConstraint = Matter.MouseConstraint,
|
MouseConstraint = Matter.MouseConstraint,
|
||||||
Mouse = Matter.Mouse,
|
Mouse = Matter.Mouse,
|
||||||
World = Matter.World,
|
Composite = Matter.Composite,
|
||||||
Bodies = Matter.Bodies;
|
Bodies = Matter.Bodies;
|
||||||
|
|
||||||
// create engine
|
// create engine
|
||||||
|
@ -36,9 +36,6 @@ Example.gyro = function() {
|
||||||
var stack = Composites.stack(20, 20, 10, 5, 0, 0, function(x, y) {
|
var stack = Composites.stack(20, 20, 10, 5, 0, 0, function(x, y) {
|
||||||
var sides = Math.round(Common.random(1, 8));
|
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
|
// round the edges of some bodies
|
||||||
var chamfer = null;
|
var chamfer = null;
|
||||||
if (sides > 2 && Common.random() > 0.7) {
|
if (sides > 2 && Common.random() > 0.7) {
|
||||||
|
@ -59,7 +56,7 @@ Example.gyro = function() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
World.add(world, [
|
Composite.add(world, [
|
||||||
stack,
|
stack,
|
||||||
Bodies.rectangle(400, 0, 800, 50, { isStatic: true }),
|
Bodies.rectangle(400, 0, 800, 50, { isStatic: true }),
|
||||||
Bodies.rectangle(400, 600, 800, 50, { isStatic: true }),
|
Bodies.rectangle(400, 600, 800, 50, { isStatic: true }),
|
||||||
|
@ -71,7 +68,7 @@ Example.gyro = function() {
|
||||||
if (typeof window !== 'undefined') {
|
if (typeof window !== 'undefined') {
|
||||||
var updateGravity = function(event) {
|
var updateGravity = function(event) {
|
||||||
var orientation = typeof window.orientation !== 'undefined' ? window.orientation : 0,
|
var orientation = typeof window.orientation !== 'undefined' ? window.orientation : 0,
|
||||||
gravity = engine.world.gravity;
|
gravity = engine.gravity;
|
||||||
|
|
||||||
if (orientation === 0) {
|
if (orientation === 0) {
|
||||||
gravity.x = Common.clamp(event.gamma, -90, 90) / 90;
|
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
|
// keep the mouse in sync with rendering
|
||||||
render.mouse = mouse;
|
render.mouse = mouse;
|
||||||
|
@ -130,6 +127,7 @@ Example.gyro = function() {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Example.gyro.title = 'Gyroscope';
|
||||||
Example.gyro.for = '>=0.14.2';
|
Example.gyro.for = '>=0.14.2';
|
||||||
|
|
||||||
if (typeof module !== 'undefined') {
|
if (typeof module !== 'undefined') {
|
||||||
|
|
|
@ -3,7 +3,6 @@ module.exports = {
|
||||||
avalanche: require('./avalanche.js'),
|
avalanche: require('./avalanche.js'),
|
||||||
ballPool: require('./ballPool.js'),
|
ballPool: require('./ballPool.js'),
|
||||||
bridge: require('./bridge.js'),
|
bridge: require('./bridge.js'),
|
||||||
broadphase: require('./broadphase.js'),
|
|
||||||
car: require('./car.js'),
|
car: require('./car.js'),
|
||||||
catapult: require('./catapult.js'),
|
catapult: require('./catapult.js'),
|
||||||
chains: require('./chains.js'),
|
chains: require('./chains.js'),
|
||||||
|
@ -28,6 +27,7 @@ module.exports = {
|
||||||
raycasting: require('./raycasting.js'),
|
raycasting: require('./raycasting.js'),
|
||||||
restitution: require('./restitution.js'),
|
restitution: require('./restitution.js'),
|
||||||
rounded: require('./rounded.js'),
|
rounded: require('./rounded.js'),
|
||||||
|
remove: require('./remove.js'),
|
||||||
sensors: require('./sensors.js'),
|
sensors: require('./sensors.js'),
|
||||||
sleeping: require('./sleeping.js'),
|
sleeping: require('./sleeping.js'),
|
||||||
slingshot: require('./slingshot.js'),
|
slingshot: require('./slingshot.js'),
|
||||||
|
@ -35,8 +35,10 @@ module.exports = {
|
||||||
sprites: require('./sprites.js'),
|
sprites: require('./sprites.js'),
|
||||||
stack: require('./stack.js'),
|
stack: require('./stack.js'),
|
||||||
staticFriction: require('./staticFriction.js'),
|
staticFriction: require('./staticFriction.js'),
|
||||||
|
stats: require('./stats.js'),
|
||||||
stress: require('./stress.js'),
|
stress: require('./stress.js'),
|
||||||
stress2: require('./stress2.js'),
|
stress2: require('./stress2.js'),
|
||||||
|
stress3: require('./stress3.js'),
|
||||||
svg: require('./svg.js'),
|
svg: require('./svg.js'),
|
||||||
terrain: require('./terrain.js'),
|
terrain: require('./terrain.js'),
|
||||||
timescale: require('./timescale.js'),
|
timescale: require('./timescale.js'),
|
||||||
|
|
|
@ -9,7 +9,7 @@ Example.manipulation = function() {
|
||||||
Events = Matter.Events,
|
Events = Matter.Events,
|
||||||
MouseConstraint = Matter.MouseConstraint,
|
MouseConstraint = Matter.MouseConstraint,
|
||||||
Mouse = Matter.Mouse,
|
Mouse = Matter.Mouse,
|
||||||
World = Matter.World,
|
Composite = Matter.Composite,
|
||||||
Bodies = Matter.Bodies;
|
Bodies = Matter.Bodies;
|
||||||
|
|
||||||
// create engine
|
// create engine
|
||||||
|
@ -50,9 +50,9 @@ Example.manipulation = function() {
|
||||||
isStatic: true
|
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
|
// walls
|
||||||
Bodies.rectangle(400, 0, 800, 50, { isStatic: true }),
|
Bodies.rectangle(400, 0, 800, 50, { isStatic: true }),
|
||||||
Bodies.rectangle(400, 600, 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
|
// keep the mouse in sync with rendering
|
||||||
render.mouse = mouse;
|
render.mouse = mouse;
|
||||||
|
@ -139,6 +139,7 @@ Example.manipulation = function() {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Example.manipulation.title = 'Manipulation';
|
||||||
Example.manipulation.for = '>=0.14.2';
|
Example.manipulation.for = '>=0.14.2';
|
||||||
|
|
||||||
if (typeof module !== 'undefined') {
|
if (typeof module !== 'undefined') {
|
||||||
|
|
|
@ -8,7 +8,7 @@ Example.mixed = function() {
|
||||||
Common = Matter.Common,
|
Common = Matter.Common,
|
||||||
MouseConstraint = Matter.MouseConstraint,
|
MouseConstraint = Matter.MouseConstraint,
|
||||||
Mouse = Matter.Mouse,
|
Mouse = Matter.Mouse,
|
||||||
World = Matter.World,
|
Composite = Matter.Composite,
|
||||||
Bodies = Matter.Bodies;
|
Bodies = Matter.Bodies;
|
||||||
|
|
||||||
// create engine
|
// create engine
|
||||||
|
@ -36,9 +36,6 @@ Example.mixed = function() {
|
||||||
var stack = Composites.stack(20, 20, 10, 5, 0, 0, function(x, y) {
|
var stack = Composites.stack(20, 20, 10, 5, 0, 0, function(x, y) {
|
||||||
var sides = Math.round(Common.random(1, 8));
|
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
|
// round the edges of some bodies
|
||||||
var chamfer = null;
|
var chamfer = null;
|
||||||
if (sides > 2 && Common.random() > 0.7) {
|
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
|
// walls
|
||||||
Bodies.rectangle(400, 0, 800, 50, { isStatic: true }),
|
Bodies.rectangle(400, 0, 800, 50, { isStatic: true }),
|
||||||
Bodies.rectangle(400, 600, 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
|
// keep the mouse in sync with rendering
|
||||||
render.mouse = mouse;
|
render.mouse = mouse;
|
||||||
|
@ -105,6 +102,7 @@ Example.mixed = function() {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Example.mixed.title = 'Mixed Shapes';
|
||||||
Example.mixed.for = '>=0.14.2';
|
Example.mixed.for = '>=0.14.2';
|
||||||
|
|
||||||
if (typeof module !== 'undefined') {
|
if (typeof module !== 'undefined') {
|
||||||
|
|
|
@ -8,7 +8,7 @@ Example.newtonsCradle = function() {
|
||||||
Composites = Matter.Composites,
|
Composites = Matter.Composites,
|
||||||
MouseConstraint = Matter.MouseConstraint,
|
MouseConstraint = Matter.MouseConstraint,
|
||||||
Mouse = Matter.Mouse,
|
Mouse = Matter.Mouse,
|
||||||
World = Matter.World;
|
Composite = Matter.Composite;
|
||||||
|
|
||||||
// create engine
|
// create engine
|
||||||
var engine = Engine.create(),
|
var engine = Engine.create(),
|
||||||
|
@ -31,13 +31,13 @@ Example.newtonsCradle = function() {
|
||||||
var runner = Runner.create();
|
var runner = Runner.create();
|
||||||
Runner.run(runner, engine);
|
Runner.run(runner, engine);
|
||||||
|
|
||||||
// add bodies
|
// see newtonsCradle function defined later in this file
|
||||||
var cradle = Composites.newtonsCradle(280, 100, 5, 30, 200);
|
var cradle = Example.newtonsCradle.newtonsCradle(280, 100, 5, 30, 200);
|
||||||
World.add(world, cradle);
|
Composite.add(world, cradle);
|
||||||
Body.translate(cradle.bodies[0], { x: -180, y: -100 });
|
Body.translate(cradle.bodies[0], { x: -180, y: -100 });
|
||||||
|
|
||||||
cradle = Composites.newtonsCradle(280, 380, 7, 20, 140);
|
cradle = Example.newtonsCradle.newtonsCradle(280, 380, 7, 20, 140);
|
||||||
World.add(world, cradle);
|
Composite.add(world, cradle);
|
||||||
Body.translate(cradle.bodies[0], { x: -140, y: -100 });
|
Body.translate(cradle.bodies[0], { x: -140, y: -100 });
|
||||||
|
|
||||||
// add mouse control
|
// 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
|
// keep the mouse in sync with rendering
|
||||||
render.mouse = mouse;
|
render.mouse = mouse;
|
||||||
|
@ -76,8 +76,39 @@ Example.newtonsCradle = function() {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Example.newtonsCradle.title = 'Newton\'s Cradle';
|
||||||
Example.newtonsCradle.for = '>=0.14.2';
|
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') {
|
if (typeof module !== 'undefined') {
|
||||||
module.exports = Example.newtonsCradle;
|
module.exports = Example.newtonsCradle;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ Example.pyramid = function() {
|
||||||
Composites = Matter.Composites,
|
Composites = Matter.Composites,
|
||||||
MouseConstraint = Matter.MouseConstraint,
|
MouseConstraint = Matter.MouseConstraint,
|
||||||
Mouse = Matter.Mouse,
|
Mouse = Matter.Mouse,
|
||||||
World = Matter.World,
|
Composite = Matter.Composite,
|
||||||
Bodies = Matter.Bodies;
|
Bodies = Matter.Bodies;
|
||||||
|
|
||||||
// create engine
|
// create engine
|
||||||
|
@ -32,11 +32,11 @@ Example.pyramid = function() {
|
||||||
Runner.run(runner, engine);
|
Runner.run(runner, engine);
|
||||||
|
|
||||||
// add bodies
|
// 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);
|
return Bodies.rectangle(x, y, 40, 40);
|
||||||
});
|
});
|
||||||
|
|
||||||
World.add(world, [
|
Composite.add(world, [
|
||||||
stack,
|
stack,
|
||||||
// walls
|
// walls
|
||||||
Bodies.rectangle(400, 0, 800, 50, { isStatic: true }),
|
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
|
// keep the mouse in sync with rendering
|
||||||
render.mouse = mouse;
|
render.mouse = mouse;
|
||||||
|
@ -81,6 +81,7 @@ Example.pyramid = function() {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Example.pyramid.title = 'Pyramid';
|
||||||
Example.pyramid.for = '>=0.14.2';
|
Example.pyramid.for = '>=0.14.2';
|
||||||
|
|
||||||
if (typeof module !== 'undefined') {
|
if (typeof module !== 'undefined') {
|
||||||
|
|
|
@ -11,7 +11,6 @@ Example.ragdoll = function() {
|
||||||
Composites = Matter.Composites,
|
Composites = Matter.Composites,
|
||||||
MouseConstraint = Matter.MouseConstraint,
|
MouseConstraint = Matter.MouseConstraint,
|
||||||
Mouse = Matter.Mouse,
|
Mouse = Matter.Mouse,
|
||||||
World = Matter.World,
|
|
||||||
Bodies = Matter.Bodies;
|
Bodies = Matter.Bodies;
|
||||||
|
|
||||||
// create engine
|
// create engine
|
||||||
|
@ -78,7 +77,7 @@ Example.ragdoll = function() {
|
||||||
Composite.add(ragdolls, ragdoll);
|
Composite.add(ragdolls, ragdoll);
|
||||||
}
|
}
|
||||||
|
|
||||||
World.add(world, [stack, obstacles, ragdolls]);
|
Composite.add(world, [stack, obstacles, ragdolls]);
|
||||||
|
|
||||||
var timeScaleTarget = 1,
|
var timeScaleTarget = 1,
|
||||||
lastTime = Common.now();
|
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
|
// keep the mouse in sync with rendering
|
||||||
render.mouse = mouse;
|
render.mouse = mouse;
|
||||||
|
@ -496,6 +495,7 @@ Example.ragdoll.ragdoll = function(x, y, scale, options) {
|
||||||
return person;
|
return person;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Example.ragdoll.title = 'Ragdoll';
|
||||||
Example.ragdoll.for = '>=0.14.2';
|
Example.ragdoll.for = '>=0.14.2';
|
||||||
|
|
||||||
if (typeof module !== 'undefined') {
|
if (typeof module !== 'undefined') {
|
||||||
|
|
|
@ -11,7 +11,6 @@ Example.raycasting = function() {
|
||||||
MouseConstraint = Matter.MouseConstraint,
|
MouseConstraint = Matter.MouseConstraint,
|
||||||
Mouse = Matter.Mouse,
|
Mouse = Matter.Mouse,
|
||||||
Events = Matter.Events,
|
Events = Matter.Events,
|
||||||
World = Matter.World,
|
|
||||||
Vertices = Matter.Vertices,
|
Vertices = Matter.Vertices,
|
||||||
Bodies = Matter.Bodies;
|
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'),
|
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);
|
concave = Bodies.fromVertices(200, 200, star);
|
||||||
|
|
||||||
World.add(world, [
|
Composite.add(world, [
|
||||||
stack,
|
stack,
|
||||||
concave,
|
concave,
|
||||||
// walls
|
// walls
|
||||||
|
@ -66,14 +68,21 @@ Example.raycasting = function() {
|
||||||
Bodies.rectangle(0, 300, 50, 600, { isStatic: true })
|
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() {
|
Events.on(render, 'afterRender', function() {
|
||||||
var mouse = mouseConstraint.mouse,
|
var mouse = mouseConstraint.mouse,
|
||||||
context = render.context,
|
context = render.context,
|
||||||
bodies = Composite.allBodies(engine.world),
|
endPoint = mouse.position || { x: 100, y: 600 };
|
||||||
startPoint = { x: 400, y: 100 },
|
|
||||||
endPoint = mouse.position;
|
|
||||||
|
|
||||||
var collisions = Query.ray(bodies, startPoint, endPoint);
|
|
||||||
|
|
||||||
Render.startViewTransform(render);
|
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
|
// keep the mouse in sync with rendering
|
||||||
render.mouse = mouse;
|
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') {
|
if (typeof module !== 'undefined') {
|
||||||
module.exports = Example.raycasting;
|
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,
|
Runner = Matter.Runner,
|
||||||
MouseConstraint = Matter.MouseConstraint,
|
MouseConstraint = Matter.MouseConstraint,
|
||||||
Mouse = Matter.Mouse,
|
Mouse = Matter.Mouse,
|
||||||
World = Matter.World,
|
Composite = Matter.Composite,
|
||||||
Bodies = Matter.Bodies;
|
Bodies = Matter.Bodies;
|
||||||
|
|
||||||
// create engine
|
// create engine
|
||||||
|
@ -36,7 +36,7 @@ Example.restitution = function() {
|
||||||
var rest = 0.9,
|
var rest = 0.9,
|
||||||
space = 600 / 5;
|
space = 600 / 5;
|
||||||
|
|
||||||
World.add(world, [
|
Composite.add(world, [
|
||||||
Bodies.rectangle(100 + space * 0, 150, 50, 50, { restitution: rest }),
|
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 * 1, 150, 50, 50, { restitution: rest, angle: -Math.PI * 0.15 }),
|
||||||
Bodies.rectangle(100 + space * 2, 150, 50, 50, { restitution: rest, angle: -Math.PI * 0.25 }),
|
Bodies.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
|
// keep the mouse in sync with rendering
|
||||||
render.mouse = mouse;
|
render.mouse = mouse;
|
||||||
|
@ -85,6 +85,7 @@ Example.restitution = function() {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Example.restitution.title = 'Restitution';
|
||||||
Example.restitution.for = '>=0.14.2';
|
Example.restitution.for = '>=0.14.2';
|
||||||
|
|
||||||
if (typeof module !== 'undefined') {
|
if (typeof module !== 'undefined') {
|
||||||
|
|
|
@ -6,7 +6,7 @@ Example.rounded = function() {
|
||||||
Runner = Matter.Runner,
|
Runner = Matter.Runner,
|
||||||
MouseConstraint = Matter.MouseConstraint,
|
MouseConstraint = Matter.MouseConstraint,
|
||||||
Mouse = Matter.Mouse,
|
Mouse = Matter.Mouse,
|
||||||
World = Matter.World,
|
Composite = Matter.Composite,
|
||||||
Bodies = Matter.Bodies;
|
Bodies = Matter.Bodies;
|
||||||
|
|
||||||
// create engine
|
// create engine
|
||||||
|
@ -31,7 +31,7 @@ Example.rounded = function() {
|
||||||
Runner.run(runner, engine);
|
Runner.run(runner, engine);
|
||||||
|
|
||||||
// add bodies
|
// add bodies
|
||||||
World.add(world, [
|
Composite.add(world, [
|
||||||
// walls
|
// walls
|
||||||
Bodies.rectangle(400, 0, 800, 50, { isStatic: true }),
|
Bodies.rectangle(400, 0, 800, 50, { isStatic: true }),
|
||||||
Bodies.rectangle(400, 600, 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 })
|
Bodies.rectangle(0, 300, 50, 600, { isStatic: true })
|
||||||
]);
|
]);
|
||||||
|
|
||||||
World.add(world, [
|
Composite.add(world, [
|
||||||
Bodies.rectangle(200, 200, 100, 100, {
|
Bodies.rectangle(200, 200, 100, 100, {
|
||||||
chamfer: { radius: 20 }
|
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
|
// keep the mouse in sync with rendering
|
||||||
render.mouse = mouse;
|
render.mouse = mouse;
|
||||||
|
@ -109,6 +109,7 @@ Example.rounded = function() {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Example.rounded.title = 'Rounded Corners (Chamfering)';
|
||||||
Example.rounded.for = '>=0.14.2';
|
Example.rounded.for = '>=0.14.2';
|
||||||
|
|
||||||
if (typeof module !== 'undefined') {
|
if (typeof module !== 'undefined') {
|
||||||
|
|
|
@ -7,7 +7,7 @@ Example.sensors = function() {
|
||||||
Events = Matter.Events,
|
Events = Matter.Events,
|
||||||
MouseConstraint = Matter.MouseConstraint,
|
MouseConstraint = Matter.MouseConstraint,
|
||||||
Mouse = Matter.Mouse,
|
Mouse = Matter.Mouse,
|
||||||
World = Matter.World,
|
Composite = Matter.Composite,
|
||||||
Bodies = Matter.Bodies;
|
Bodies = Matter.Bodies;
|
||||||
|
|
||||||
// create engine
|
// create engine
|
||||||
|
@ -45,7 +45,7 @@ Example.sensors = function() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
World.add(world, [
|
Composite.add(world, [
|
||||||
collider,
|
collider,
|
||||||
Bodies.rectangle(400, 600, 800, 50, {
|
Bodies.rectangle(400, 600, 800, 50, {
|
||||||
isStatic: true,
|
isStatic: true,
|
||||||
|
@ -56,7 +56,7 @@ Example.sensors = function() {
|
||||||
})
|
})
|
||||||
]);
|
]);
|
||||||
|
|
||||||
World.add(world,
|
Composite.add(world,
|
||||||
Bodies.circle(400, 40, 30, {
|
Bodies.circle(400, 40, 30, {
|
||||||
render: {
|
render: {
|
||||||
strokeStyle: colorB,
|
strokeStyle: colorB,
|
||||||
|
@ -106,7 +106,7 @@ Example.sensors = function() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
World.add(world, mouseConstraint);
|
Composite.add(world, mouseConstraint);
|
||||||
|
|
||||||
// keep the mouse in sync with rendering
|
// keep the mouse in sync with rendering
|
||||||
render.mouse = mouse;
|
render.mouse = mouse;
|
||||||
|
@ -130,6 +130,7 @@ Example.sensors = function() {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Example.sensors.title = 'Sensors';
|
||||||
Example.sensors.for = '>=0.14.2';
|
Example.sensors.for = '>=0.14.2';
|
||||||
|
|
||||||
if (typeof module !== 'undefined') {
|
if (typeof module !== 'undefined') {
|
||||||
|
|
|
@ -9,7 +9,7 @@ Example.sleeping = function() {
|
||||||
Events = Matter.Events,
|
Events = Matter.Events,
|
||||||
MouseConstraint = Matter.MouseConstraint,
|
MouseConstraint = Matter.MouseConstraint,
|
||||||
Mouse = Matter.Mouse,
|
Mouse = Matter.Mouse,
|
||||||
World = Matter.World,
|
Composite = Matter.Composite,
|
||||||
Bodies = Matter.Bodies;
|
Bodies = Matter.Bodies;
|
||||||
|
|
||||||
// create engine
|
// create engine
|
||||||
|
@ -36,7 +36,7 @@ Example.sleeping = function() {
|
||||||
Runner.run(runner, engine);
|
Runner.run(runner, engine);
|
||||||
|
|
||||||
// add bodies
|
// add bodies
|
||||||
World.add(world, [
|
Composite.add(world, [
|
||||||
// walls
|
// walls
|
||||||
Bodies.rectangle(400, 0, 800, 50, { isStatic: true }),
|
Bodies.rectangle(400, 0, 800, 50, { isStatic: true }),
|
||||||
Bodies.rectangle(400, 600, 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++) {
|
for (var i = 0; i < stack.bodies.length; i++) {
|
||||||
Events.on(stack.bodies[i], 'sleepStart sleepEnd', function(event) {
|
Events.on(stack.bodies[i], 'sleepStart sleepEnd', function(event) {
|
||||||
var body = this;
|
var body = this;
|
||||||
console.log('body id', body.id, 'sleeping:', body.isSleeping);
|
console.log('body id', body.id, 'sleeping:', body.isSleeping);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
// add mouse control
|
// add mouse control
|
||||||
var mouse = Mouse.create(render.canvas),
|
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
|
// keep the mouse in sync with rendering
|
||||||
render.mouse = mouse;
|
render.mouse = mouse;
|
||||||
|
@ -104,6 +107,7 @@ Example.sleeping = function() {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Example.sleeping.title = 'Sleeping';
|
||||||
Example.sleeping.for = '>=0.14.2';
|
Example.sleeping.for = '>=0.14.2';
|
||||||
|
|
||||||
if (typeof module !== 'undefined') {
|
if (typeof module !== 'undefined') {
|
||||||
|
|
|
@ -9,8 +9,8 @@ Example.slingshot = function() {
|
||||||
Constraint = Matter.Constraint,
|
Constraint = Matter.Constraint,
|
||||||
MouseConstraint = Matter.MouseConstraint,
|
MouseConstraint = Matter.MouseConstraint,
|
||||||
Mouse = Matter.Mouse,
|
Mouse = Matter.Mouse,
|
||||||
World = Matter.World,
|
|
||||||
Body = Matter.Body,
|
Body = Matter.Body,
|
||||||
|
Composite = Matter.Composite,
|
||||||
Bodies = Matter.Bodies;
|
Bodies = Matter.Bodies;
|
||||||
|
|
||||||
// create engine
|
// create engine
|
||||||
|
@ -55,7 +55,7 @@ Example.slingshot = function() {
|
||||||
return Bodies.rectangle(x, y, 25, 40);
|
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() {
|
Events.on(engine, 'afterUpdate', function() {
|
||||||
if (mouseConstraint.mouse.button === -1 && (rock.position.x > 190 || rock.position.y < 430)) {
|
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.
|
// Release current rock and add a new one.
|
||||||
rock = Bodies.polygon(170, 450, 7, 20, rockOptions);
|
rock = Bodies.polygon(170, 450, 7, 20, rockOptions);
|
||||||
World.add(engine.world, rock);
|
Composite.add(engine.world, rock);
|
||||||
elastic.bodyB = 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
|
// keep the mouse in sync with rendering
|
||||||
render.mouse = mouse;
|
render.mouse = mouse;
|
||||||
|
@ -107,6 +107,7 @@ Example.slingshot = function() {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Example.slingshot.title = 'Slingshot';
|
||||||
Example.slingshot.for = '>=0.14.2';
|
Example.slingshot.for = '>=0.14.2';
|
||||||
|
|
||||||
if (typeof module !== 'undefined') {
|
if (typeof module !== 'undefined') {
|
||||||
|
|
|
@ -7,7 +7,7 @@ Example.softBody = function() {
|
||||||
Composites = Matter.Composites,
|
Composites = Matter.Composites,
|
||||||
MouseConstraint = Matter.MouseConstraint,
|
MouseConstraint = Matter.MouseConstraint,
|
||||||
Mouse = Matter.Mouse,
|
Mouse = Matter.Mouse,
|
||||||
World = Matter.World,
|
Composite = Matter.Composite,
|
||||||
Bodies = Matter.Bodies;
|
Bodies = Matter.Bodies;
|
||||||
|
|
||||||
// create engine
|
// create engine
|
||||||
|
@ -38,10 +38,11 @@ Example.softBody = function() {
|
||||||
render: { visible: true }
|
render: { visible: true }
|
||||||
};
|
};
|
||||||
|
|
||||||
World.add(world, [
|
Composite.add(world, [
|
||||||
Composites.softBody(250, 100, 5, 5, 0, 0, true, 18, particleOptions),
|
// see softBody function defined later in this file
|
||||||
Composites.softBody(400, 300, 8, 3, 0, 0, true, 15, particleOptions),
|
Example.softBody.softBody(250, 100, 5, 5, 0, 0, true, 18, particleOptions),
|
||||||
Composites.softBody(250, 400, 4, 4, 0, 0, true, 15, 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
|
// walls
|
||||||
Bodies.rectangle(400, 0, 800, 50, { isStatic: true }),
|
Bodies.rectangle(400, 0, 800, 50, { isStatic: true }),
|
||||||
Bodies.rectangle(400, 600, 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
|
// keep the mouse in sync with rendering
|
||||||
render.mouse = mouse;
|
render.mouse = mouse;
|
||||||
|
@ -85,8 +86,43 @@ Example.softBody = function() {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Example.softBody.title = 'Soft Body';
|
||||||
Example.softBody.for = '>=0.14.2';
|
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') {
|
if (typeof module !== 'undefined') {
|
||||||
module.exports = Example.softBody;
|
module.exports = Example.softBody;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ Example.sprites = function() {
|
||||||
Common = Matter.Common,
|
Common = Matter.Common,
|
||||||
MouseConstraint = Matter.MouseConstraint,
|
MouseConstraint = Matter.MouseConstraint,
|
||||||
Mouse = Matter.Mouse,
|
Mouse = Matter.Mouse,
|
||||||
World = Matter.World,
|
Composite = Matter.Composite,
|
||||||
Bodies = Matter.Bodies;
|
Bodies = Matter.Bodies;
|
||||||
|
|
||||||
// create engine
|
// create engine
|
||||||
|
@ -42,7 +42,7 @@ Example.sprites = function() {
|
||||||
world.bodies = [];
|
world.bodies = [];
|
||||||
|
|
||||||
// these static walls will not be rendered in this sprites example, see options
|
// 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, -offset, 800.5 + 2 * offset, 50.5, options),
|
||||||
Bodies.rectangle(400, 600 + offset, 800.5 + 2 * offset, 50.5, options),
|
Bodies.rectangle(400, 600 + offset, 800.5 + 2 * offset, 50.5, options),
|
||||||
Bodies.rectangle(800 + offset, 300, 50.5, 600.5 + 2 * offset, options),
|
Bodies.rectangle(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
|
// add mouse control
|
||||||
var mouse = Mouse.create(render.canvas),
|
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
|
// keep the mouse in sync with rendering
|
||||||
render.mouse = mouse;
|
render.mouse = mouse;
|
||||||
|
@ -112,6 +112,7 @@ Example.sprites = function() {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Example.sprites.title = 'Sprites';
|
||||||
Example.sprites.for = '>=0.14.2';
|
Example.sprites.for = '>=0.14.2';
|
||||||
|
|
||||||
if (typeof module !== 'undefined') {
|
if (typeof module !== 'undefined') {
|
||||||
|
|
|
@ -7,7 +7,7 @@ Example.stack = function() {
|
||||||
Composites = Matter.Composites,
|
Composites = Matter.Composites,
|
||||||
MouseConstraint = Matter.MouseConstraint,
|
MouseConstraint = Matter.MouseConstraint,
|
||||||
Mouse = Matter.Mouse,
|
Mouse = Matter.Mouse,
|
||||||
World = Matter.World,
|
Composite = Matter.Composite,
|
||||||
Bodies = Matter.Bodies;
|
Bodies = Matter.Bodies;
|
||||||
|
|
||||||
// create engine
|
// create engine
|
||||||
|
@ -32,11 +32,11 @@ Example.stack = function() {
|
||||||
Runner.run(runner, engine);
|
Runner.run(runner, engine);
|
||||||
|
|
||||||
// add bodies
|
// 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);
|
return Bodies.rectangle(x, y, 40, 40);
|
||||||
});
|
});
|
||||||
|
|
||||||
World.add(world, [
|
Composite.add(world, [
|
||||||
stack,
|
stack,
|
||||||
// walls
|
// walls
|
||||||
Bodies.rectangle(400, 0, 800, 50, { isStatic: true }),
|
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
|
// keep the mouse in sync with rendering
|
||||||
render.mouse = mouse;
|
render.mouse = mouse;
|
||||||
|
@ -81,6 +81,7 @@ Example.stack = function() {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Example.stack.title = 'Stack';
|
||||||
Example.stack.for = '>=0.14.2';
|
Example.stack.for = '>=0.14.2';
|
||||||
|
|
||||||
if (typeof module !== 'undefined') {
|
if (typeof module !== 'undefined') {
|
||||||
|
|
|
@ -9,7 +9,7 @@ Example.staticFriction = function() {
|
||||||
Events = Matter.Events,
|
Events = Matter.Events,
|
||||||
MouseConstraint = Matter.MouseConstraint,
|
MouseConstraint = Matter.MouseConstraint,
|
||||||
Mouse = Matter.Mouse,
|
Mouse = Matter.Mouse,
|
||||||
World = Matter.World,
|
Composite = Matter.Composite,
|
||||||
Bodies = Matter.Bodies;
|
Bodies = Matter.Bodies;
|
||||||
|
|
||||||
// create engine
|
// create engine
|
||||||
|
@ -45,7 +45,7 @@ Example.staticFriction = function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
World.add(world, [
|
Composite.add(world, [
|
||||||
body,
|
body,
|
||||||
stack,
|
stack,
|
||||||
// walls
|
// walls
|
||||||
|
@ -77,7 +77,7 @@ Example.staticFriction = function() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
World.add(world, mouseConstraint);
|
Composite.add(world, mouseConstraint);
|
||||||
|
|
||||||
// keep the mouse in sync with rendering
|
// keep the mouse in sync with rendering
|
||||||
render.mouse = mouse;
|
render.mouse = mouse;
|
||||||
|
@ -101,6 +101,7 @@ Example.staticFriction = function() {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Example.staticFriction.title = 'Static Friction';
|
||||||
Example.staticFriction.for = '>=0.14.2';
|
Example.staticFriction.for = '>=0.14.2';
|
||||||
|
|
||||||
if (typeof module !== 'undefined') {
|
if (typeof module !== 'undefined') {
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
var Example = Example || {};
|
var Example = Example || {};
|
||||||
|
|
||||||
Example.broadphase = function() {
|
Example.stats = function() {
|
||||||
var Engine = Matter.Engine,
|
var Engine = Matter.Engine,
|
||||||
Render = Matter.Render,
|
Render = Matter.Render,
|
||||||
Runner = Matter.Runner,
|
Runner = Matter.Runner,
|
||||||
Composites = Matter.Composites,
|
|
||||||
Common = Matter.Common,
|
Common = Matter.Common,
|
||||||
|
Composites = Matter.Composites,
|
||||||
MouseConstraint = Matter.MouseConstraint,
|
MouseConstraint = Matter.MouseConstraint,
|
||||||
Mouse = Matter.Mouse,
|
Mouse = Matter.Mouse,
|
||||||
World = Matter.World,
|
World = Matter.World,
|
||||||
|
@ -22,8 +22,9 @@ Example.broadphase = function() {
|
||||||
options: {
|
options: {
|
||||||
width: 800,
|
width: 800,
|
||||||
height: 600,
|
height: 600,
|
||||||
showAngleIndicator: true,
|
// show stats and performance monitors
|
||||||
showBroadphase: true
|
showStats: true,
|
||||||
|
showPerformance: true
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -33,32 +34,19 @@ Example.broadphase = function() {
|
||||||
var runner = Runner.create();
|
var runner = Runner.create();
|
||||||
Runner.run(runner, engine);
|
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, [
|
World.add(world, [
|
||||||
// walls
|
stack,
|
||||||
Bodies.rectangle(400, 0, 800, 50, { isStatic: true }),
|
Bodies.rectangle(400, 0, 800, 50, { isStatic: true }),
|
||||||
Bodies.rectangle(400, 600, 800, 50, { isStatic: true }),
|
Bodies.rectangle(400, 600, 800, 50, { isStatic: true }),
|
||||||
Bodies.rectangle(800, 300, 50, 600, { isStatic: true }),
|
Bodies.rectangle(800, 300, 50, 600, { isStatic: true }),
|
||||||
Bodies.rectangle(0, 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
|
// add mouse control
|
||||||
var mouse = Mouse.create(render.canvas),
|
var mouse = Mouse.create(render.canvas),
|
||||||
mouseConstraint = MouseConstraint.create(engine, {
|
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') {
|
if (typeof module !== 'undefined') {
|
||||||
module.exports = Example.broadphase;
|
module.exports = Example.stats;
|
||||||
}
|
}
|
|
@ -7,7 +7,7 @@ Example.stress = function() {
|
||||||
Composites = Matter.Composites,
|
Composites = Matter.Composites,
|
||||||
MouseConstraint = Matter.MouseConstraint,
|
MouseConstraint = Matter.MouseConstraint,
|
||||||
Mouse = Matter.Mouse,
|
Mouse = Matter.Mouse,
|
||||||
World = Matter.World,
|
Composite = Matter.Composite,
|
||||||
Bodies = Matter.Bodies;
|
Bodies = Matter.Bodies;
|
||||||
|
|
||||||
// create engine
|
// create engine
|
||||||
|
@ -20,7 +20,9 @@ Example.stress = function() {
|
||||||
engine: engine,
|
engine: engine,
|
||||||
options: {
|
options: {
|
||||||
width: 800,
|
width: 800,
|
||||||
height: 600
|
height: 600,
|
||||||
|
showStats: true,
|
||||||
|
showPerformance: true
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -31,11 +33,11 @@ Example.stress = function() {
|
||||||
Runner.run(runner, engine);
|
Runner.run(runner, engine);
|
||||||
|
|
||||||
// scene code
|
// 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);
|
return Bodies.rectangle(x, y, 35, 35);
|
||||||
});
|
});
|
||||||
|
|
||||||
World.add(world, [
|
Composite.add(world, [
|
||||||
stack,
|
stack,
|
||||||
Bodies.rectangle(400, 0, 800, 50, { isStatic: true }),
|
Bodies.rectangle(400, 0, 800, 50, { isStatic: true }),
|
||||||
Bodies.rectangle(400, 600, 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
|
// keep the mouse in sync with rendering
|
||||||
render.mouse = mouse;
|
render.mouse = mouse;
|
||||||
|
@ -79,6 +81,7 @@ Example.stress = function() {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Example.stress.title = 'Stress';
|
||||||
Example.stress.for = '>=0.14.2';
|
Example.stress.for = '>=0.14.2';
|
||||||
|
|
||||||
if (typeof module !== 'undefined') {
|
if (typeof module !== 'undefined') {
|
||||||
|
|
|
@ -7,7 +7,7 @@ Example.stress2 = function() {
|
||||||
Composites = Matter.Composites,
|
Composites = Matter.Composites,
|
||||||
MouseConstraint = Matter.MouseConstraint,
|
MouseConstraint = Matter.MouseConstraint,
|
||||||
Mouse = Matter.Mouse,
|
Mouse = Matter.Mouse,
|
||||||
World = Matter.World,
|
Composite = Matter.Composite,
|
||||||
Bodies = Matter.Bodies;
|
Bodies = Matter.Bodies;
|
||||||
|
|
||||||
// create engine
|
// create engine
|
||||||
|
@ -20,7 +20,9 @@ Example.stress2 = function() {
|
||||||
engine: engine,
|
engine: engine,
|
||||||
options: {
|
options: {
|
||||||
width: 800,
|
width: 800,
|
||||||
height: 600
|
height: 600,
|
||||||
|
showStats: true,
|
||||||
|
showPerformance: true
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -31,11 +33,11 @@ Example.stress2 = function() {
|
||||||
Runner.run(runner, engine);
|
Runner.run(runner, engine);
|
||||||
|
|
||||||
// scene code
|
// 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);
|
return Bodies.rectangle(x, y, 25, 25);
|
||||||
});
|
});
|
||||||
|
|
||||||
World.add(world, [
|
Composite.add(world, [
|
||||||
stack,
|
stack,
|
||||||
Bodies.rectangle(400, 0, 800, 50, { isStatic: true }),
|
Bodies.rectangle(400, 0, 800, 50, { isStatic: true }),
|
||||||
Bodies.rectangle(400, 600, 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
|
// keep the mouse in sync with rendering
|
||||||
render.mouse = mouse;
|
render.mouse = mouse;
|
||||||
|
@ -79,6 +81,7 @@ Example.stress2 = function() {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Example.stress2.title = 'Stress 2';
|
||||||
Example.stress2.for = '>=0.14.2';
|
Example.stress2.for = '>=0.14.2';
|
||||||
|
|
||||||
if (typeof module !== 'undefined') {
|
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,
|
Common = Matter.Common,
|
||||||
MouseConstraint = Matter.MouseConstraint,
|
MouseConstraint = Matter.MouseConstraint,
|
||||||
Mouse = Matter.Mouse,
|
Mouse = Matter.Mouse,
|
||||||
World = Matter.World,
|
Composite = Matter.Composite,
|
||||||
Vertices = Matter.Vertices,
|
Vertices = Matter.Vertices,
|
||||||
Svg = Matter.Svg,
|
Svg = Matter.Svg,
|
||||||
Bodies = Matter.Bodies;
|
Bodies = Matter.Bodies;
|
||||||
|
|
||||||
|
// provide concave decomposition support library
|
||||||
|
Common.setDecomp(require('poly-decomp'));
|
||||||
|
|
||||||
// create engine
|
// create engine
|
||||||
var engine = Engine.create(),
|
var engine = Engine.create(),
|
||||||
world = engine.world;
|
world = engine.world;
|
||||||
|
@ -33,26 +36,30 @@ Example.svg = function() {
|
||||||
Runner.run(runner, engine);
|
Runner.run(runner, engine);
|
||||||
|
|
||||||
// add bodies
|
// add bodies
|
||||||
var svgs = [
|
if (typeof fetch !== 'undefined') {
|
||||||
'iconmonstr-check-mark-8-icon',
|
var select = function(root, selector) {
|
||||||
'iconmonstr-paperclip-2-icon',
|
return Array.prototype.slice.call(root.querySelectorAll(selector));
|
||||||
'iconmonstr-puzzle-icon',
|
};
|
||||||
'iconmonstr-user-icon'
|
|
||||||
];
|
|
||||||
|
|
||||||
if (typeof $ !== 'undefined') {
|
var loadSvg = function(url) {
|
||||||
for (var i = 0; i < svgs.length; i += 1) {
|
return fetch(url)
|
||||||
(function(i) {
|
.then(function(response) { return response.text(); })
|
||||||
$.get('./svg/' + svgs[i] + '.svg').done(function(data) {
|
.then(function(raw) { return (new window.DOMParser()).parseFromString(raw, 'image/svg+xml'); });
|
||||||
var vertexSets = [],
|
};
|
||||||
color = Common.choose(['#f19648', '#f5d259', '#f55a3c', '#063e7b', '#ececd1']);
|
|
||||||
|
|
||||||
$(data).find('path').each(function(i, path) {
|
([
|
||||||
var points = Svg.pathToVertices(path, 30);
|
'./svg/iconmonstr-check-mark-8-icon.svg',
|
||||||
vertexSets.push(Vertices.scale(points, 0.4, 0.4));
|
'./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, {
|
var vertexSets = select(root, 'path')
|
||||||
|
.map(function(path) { return Vertices.scale(Svg.pathToVertices(path, 30), 0.4, 0.4); });
|
||||||
|
|
||||||
|
Composite.add(world, Bodies.fromVertices(100 + i * 150, 200 + i * 50, vertexSets, {
|
||||||
render: {
|
render: {
|
||||||
fillStyle: color,
|
fillStyle: color,
|
||||||
strokeStyle: color,
|
strokeStyle: color,
|
||||||
|
@ -60,18 +67,15 @@ Example.svg = function() {
|
||||||
}
|
}
|
||||||
}, true));
|
}, true));
|
||||||
});
|
});
|
||||||
})(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
$.get('./svg/svg.svg').done(function(data) {
|
|
||||||
var vertexSets = [],
|
|
||||||
color = Common.choose(['#f19648', '#f5d259', '#f55a3c', '#063e7b', '#ececd1']);
|
|
||||||
|
|
||||||
$(data).find('path').each(function(i, path) {
|
|
||||||
vertexSets.push(Svg.pathToVertices(path, 30));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
World.add(world, Bodies.fromVertices(400, 80, vertexSets, {
|
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: {
|
render: {
|
||||||
fillStyle: color,
|
fillStyle: color,
|
||||||
strokeStyle: color,
|
strokeStyle: color,
|
||||||
|
@ -79,9 +83,11 @@ Example.svg = function() {
|
||||||
}
|
}
|
||||||
}, true));
|
}, 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, 0, 800, 50, { isStatic: true }),
|
||||||
Bodies.rectangle(400, 600, 800, 50, { isStatic: true }),
|
Bodies.rectangle(400, 600, 800, 50, { isStatic: true }),
|
||||||
Bodies.rectangle(800, 300, 50, 600, { 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
|
// keep the mouse in sync with rendering
|
||||||
render.mouse = mouse;
|
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') {
|
if (typeof module !== 'undefined') {
|
||||||
module.exports = Example.svg;
|
module.exports = Example.svg;
|
||||||
|
|
|
@ -8,11 +8,14 @@ Example.terrain = function() {
|
||||||
Common = Matter.Common,
|
Common = Matter.Common,
|
||||||
MouseConstraint = Matter.MouseConstraint,
|
MouseConstraint = Matter.MouseConstraint,
|
||||||
Mouse = Matter.Mouse,
|
Mouse = Matter.Mouse,
|
||||||
World = Matter.World,
|
Composite = Matter.Composite,
|
||||||
Query = Matter.Query,
|
Query = Matter.Query,
|
||||||
Svg = Matter.Svg,
|
Svg = Matter.Svg,
|
||||||
Bodies = Matter.Bodies;
|
Bodies = Matter.Bodies;
|
||||||
|
|
||||||
|
// provide concave decomposition support library
|
||||||
|
Common.setDecomp(require('poly-decomp'));
|
||||||
|
|
||||||
// create engine
|
// create engine
|
||||||
var engine = Engine.create(),
|
var engine = Engine.create(),
|
||||||
world = engine.world;
|
world = engine.world;
|
||||||
|
@ -34,17 +37,24 @@ Example.terrain = function() {
|
||||||
Runner.run(runner, engine);
|
Runner.run(runner, engine);
|
||||||
|
|
||||||
// add bodies
|
// add bodies
|
||||||
var terrain;
|
if (typeof fetch !== 'undefined') {
|
||||||
|
var select = function(root, selector) {
|
||||||
|
return Array.prototype.slice.call(root.querySelectorAll(selector));
|
||||||
|
};
|
||||||
|
|
||||||
if (typeof $ !== 'undefined') {
|
var loadSvg = function(url) {
|
||||||
$.get('./svg/terrain.svg').done(function(data) {
|
return fetch(url)
|
||||||
var vertexSets = [];
|
.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) {
|
loadSvg('./svg/terrain.svg')
|
||||||
vertexSets.push(Svg.pathToVertices(path, 30));
|
.then(function(root) {
|
||||||
});
|
var paths = select(root, 'path');
|
||||||
|
|
||||||
terrain = Bodies.fromVertices(400, 350, vertexSets, {
|
var vertexSets = paths.map(function(path) { return Svg.pathToVertices(path, 30); });
|
||||||
|
|
||||||
|
var terrain = Bodies.fromVertices(400, 350, vertexSets, {
|
||||||
isStatic: true,
|
isStatic: true,
|
||||||
render: {
|
render: {
|
||||||
fillStyle: '#060a19',
|
fillStyle: '#060a19',
|
||||||
|
@ -53,7 +63,7 @@ Example.terrain = function() {
|
||||||
}
|
}
|
||||||
}, true);
|
}, true);
|
||||||
|
|
||||||
World.add(world, terrain);
|
Composite.add(world, terrain);
|
||||||
|
|
||||||
var bodyOptions = {
|
var bodyOptions = {
|
||||||
frictionAir: 0,
|
frictionAir: 0,
|
||||||
|
@ -61,12 +71,14 @@ Example.terrain = function() {
|
||||||
restitution: 0.6
|
restitution: 0.6
|
||||||
};
|
};
|
||||||
|
|
||||||
World.add(world, Composites.stack(80, 100, 20, 20, 10, 10, function(x, y) {
|
Composite.add(world, Composites.stack(80, 100, 20, 20, 10, 10, function(x, y) {
|
||||||
if (Query.point([terrain], { x: x, y: y }).length === 0) {
|
if (Query.point([terrain], { x: x, y: y }).length === 0) {
|
||||||
return Bodies.polygon(x, y, 5, 12, bodyOptions);
|
return Bodies.polygon(x, y, 5, 12, bodyOptions);
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
Common.warn('Fetch is not available. Could not load SVG.');
|
||||||
}
|
}
|
||||||
|
|
||||||
// add mouse control
|
// 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
|
// keep the mouse in sync with rendering
|
||||||
render.mouse = mouse;
|
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') {
|
if (typeof module !== 'undefined') {
|
||||||
module.exports = Example.terrain;
|
module.exports = Example.terrain;
|
||||||
|
|
|
@ -11,7 +11,6 @@ Example.timescale = function() {
|
||||||
Common = Matter.Common,
|
Common = Matter.Common,
|
||||||
MouseConstraint = Matter.MouseConstraint,
|
MouseConstraint = Matter.MouseConstraint,
|
||||||
Mouse = Matter.Mouse,
|
Mouse = Matter.Mouse,
|
||||||
World = Matter.World,
|
|
||||||
Bodies = Matter.Bodies;
|
Bodies = Matter.Bodies;
|
||||||
|
|
||||||
// create engine
|
// create engine
|
||||||
|
@ -36,7 +35,7 @@ Example.timescale = function() {
|
||||||
Runner.run(runner, engine);
|
Runner.run(runner, engine);
|
||||||
|
|
||||||
// add bodies
|
// add bodies
|
||||||
World.add(world, [
|
Composite.add(world, [
|
||||||
Bodies.rectangle(400, 0, 800, 50, { isStatic: true }),
|
Bodies.rectangle(400, 0, 800, 50, { isStatic: true }),
|
||||||
Bodies.rectangle(400, 600, 800, 50, { isStatic: true }),
|
Bodies.rectangle(400, 600, 800, 50, { isStatic: true }),
|
||||||
Bodies.rectangle(800, 300, 50, 600, { isStatic: true }),
|
Bodies.rectangle(800, 300, 50, 600, { isStatic: true }),
|
||||||
|
@ -95,11 +94,11 @@ Example.timescale = function() {
|
||||||
restitution: 0.8
|
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);
|
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))) {
|
switch (Math.round(Common.random(0, 1))) {
|
||||||
|
|
||||||
case 0:
|
case 0:
|
||||||
|
@ -126,7 +125,7 @@ Example.timescale = function() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
World.add(world, mouseConstraint);
|
Composite.add(world, mouseConstraint);
|
||||||
|
|
||||||
// keep the mouse in sync with rendering
|
// keep the mouse in sync with rendering
|
||||||
render.mouse = mouse;
|
render.mouse = mouse;
|
||||||
|
@ -150,6 +149,7 @@ Example.timescale = function() {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Example.timescale.title = 'Time Scaling';
|
||||||
Example.timescale.for = '>=0.14.2';
|
Example.timescale.for = '>=0.14.2';
|
||||||
|
|
||||||
if (typeof module !== 'undefined') {
|
if (typeof module !== 'undefined') {
|
||||||
|
|
|
@ -9,7 +9,7 @@ Example.views = function() {
|
||||||
Common = Matter.Common,
|
Common = Matter.Common,
|
||||||
MouseConstraint = Matter.MouseConstraint,
|
MouseConstraint = Matter.MouseConstraint,
|
||||||
Mouse = Matter.Mouse,
|
Mouse = Matter.Mouse,
|
||||||
World = Matter.World,
|
Composite = Matter.Composite,
|
||||||
Vector = Matter.Vector,
|
Vector = Matter.Vector,
|
||||||
Bounds = Matter.Bounds,
|
Bounds = Matter.Bounds,
|
||||||
Bodies = Matter.Bodies;
|
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
|
// keep the mouse in sync with rendering
|
||||||
render.mouse = mouse;
|
render.mouse = mouse;
|
||||||
|
|
||||||
// add bodies
|
// 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))) {
|
switch (Math.round(Common.random(0, 1))) {
|
||||||
|
|
||||||
case 0:
|
case 0:
|
||||||
|
@ -70,7 +70,7 @@ Example.views = function() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
World.add(world, [
|
Composite.add(world, [
|
||||||
stack,
|
stack,
|
||||||
// walls
|
// walls
|
||||||
Bodies.rectangle(400, 0, 800, 50, { isStatic: true }),
|
Bodies.rectangle(400, 0, 800, 50, { isStatic: true }),
|
||||||
|
@ -85,11 +85,11 @@ Example.views = function() {
|
||||||
y: render.options.height * 0.5
|
y: render.options.height * 0.5
|
||||||
};
|
};
|
||||||
|
|
||||||
// make the world bounds a little bigger than the render bounds
|
// create limits for the viewport
|
||||||
world.bounds.min.x = -300;
|
var extents = {
|
||||||
world.bounds.min.y = -300;
|
min: { x: -300, y: -300 },
|
||||||
world.bounds.max.x = 1100;
|
max: { x: 1100, y: 900 }
|
||||||
world.bounds.max.y = 900;
|
};
|
||||||
|
|
||||||
// keep track of current bounds scale (view zoom)
|
// keep track of current bounds scale (view zoom)
|
||||||
var boundsScaleTarget = 1,
|
var boundsScaleTarget = 1,
|
||||||
|
@ -98,8 +98,8 @@ Example.views = function() {
|
||||||
y: 1
|
y: 1
|
||||||
};
|
};
|
||||||
|
|
||||||
// use the engine tick event to control our view
|
// use a render event to control our view
|
||||||
Events.on(engine, 'beforeTick', function() {
|
Events.on(render, 'beforeRender', function() {
|
||||||
var world = engine.world,
|
var world = engine.world,
|
||||||
mouse = mouseConstraint.mouse,
|
mouse = mouseConstraint.mouse,
|
||||||
translate;
|
translate;
|
||||||
|
@ -148,18 +148,18 @@ Example.views = function() {
|
||||||
|
|
||||||
translate = Vector.mult(direction, speed);
|
translate = Vector.mult(direction, speed);
|
||||||
|
|
||||||
// prevent the view moving outside the world bounds
|
// prevent the view moving outside the extents
|
||||||
if (render.bounds.min.x + translate.x < world.bounds.min.x)
|
if (render.bounds.min.x + translate.x < extents.min.x)
|
||||||
translate.x = world.bounds.min.x - render.bounds.min.x;
|
translate.x = extents.min.x - render.bounds.min.x;
|
||||||
|
|
||||||
if (render.bounds.max.x + translate.x > world.bounds.max.x)
|
if (render.bounds.max.x + translate.x > extents.max.x)
|
||||||
translate.x = world.bounds.max.x - render.bounds.max.x;
|
translate.x = extents.max.x - render.bounds.max.x;
|
||||||
|
|
||||||
if (render.bounds.min.y + translate.y < world.bounds.min.y)
|
if (render.bounds.min.y + translate.y < extents.min.y)
|
||||||
translate.y = world.bounds.min.y - render.bounds.min.y;
|
translate.y = extents.min.y - render.bounds.min.y;
|
||||||
|
|
||||||
if (render.bounds.max.y + translate.y > world.bounds.max.y)
|
if (render.bounds.max.y + translate.y > extents.max.y)
|
||||||
translate.y = world.bounds.max.y - render.bounds.max.y;
|
translate.y = extents.max.y - render.bounds.max.y;
|
||||||
|
|
||||||
// move the view
|
// move the view
|
||||||
Bounds.translate(render.bounds, translate);
|
Bounds.translate(render.bounds, translate);
|
||||||
|
@ -182,6 +182,7 @@ Example.views = function() {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Example.views.title = 'Views';
|
||||||
Example.views.for = '>=0.14.2';
|
Example.views.for = '>=0.14.2';
|
||||||
|
|
||||||
if (typeof module !== 'undefined') {
|
if (typeof module !== 'undefined') {
|
||||||
|
|
|
@ -7,7 +7,7 @@ Example.wreckingBall = function() {
|
||||||
Composites = Matter.Composites,
|
Composites = Matter.Composites,
|
||||||
MouseConstraint = Matter.MouseConstraint,
|
MouseConstraint = Matter.MouseConstraint,
|
||||||
Mouse = Matter.Mouse,
|
Mouse = Matter.Mouse,
|
||||||
World = Matter.World,
|
Composite = Matter.Composite,
|
||||||
Constraint = Matter.Constraint,
|
Constraint = Matter.Constraint,
|
||||||
Bodies = Matter.Bodies;
|
Bodies = Matter.Bodies;
|
||||||
|
|
||||||
|
@ -34,13 +34,13 @@ Example.wreckingBall = function() {
|
||||||
|
|
||||||
// add bodies
|
// add bodies
|
||||||
var rows = 10,
|
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) {
|
var stack = Composites.stack(400, yy, 5, rows, 0, 0, function(x, y) {
|
||||||
return Bodies.rectangle(x, y, 40, 40);
|
return Bodies.rectangle(x, y, 40, 40);
|
||||||
});
|
});
|
||||||
|
|
||||||
World.add(world, [
|
Composite.add(world, [
|
||||||
stack,
|
stack,
|
||||||
// walls
|
// walls
|
||||||
Bodies.rectangle(400, 0, 800, 50, { isStatic: true }),
|
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});
|
var ball = Bodies.circle(100, 400, 50, { density: 0.04, frictionAir: 0.005});
|
||||||
|
|
||||||
World.add(world, ball);
|
Composite.add(world, ball);
|
||||||
World.add(world, Constraint.create({
|
Composite.add(world, Constraint.create({
|
||||||
pointA: { x: 300, y: 100 },
|
pointA: { x: 300, y: 100 },
|
||||||
bodyB: ball
|
bodyB: ball
|
||||||
}));
|
}));
|
||||||
|
@ -69,7 +69,7 @@ Example.wreckingBall = function() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
World.add(world, mouseConstraint);
|
Composite.add(world, mouseConstraint);
|
||||||
|
|
||||||
// keep the mouse in sync with rendering
|
// keep the mouse in sync with rendering
|
||||||
render.mouse = mouse;
|
render.mouse = mouse;
|
||||||
|
@ -93,6 +93,7 @@ Example.wreckingBall = function() {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Example.wreckingBall.title = 'Wrecking Ball';
|
||||||
Example.wreckingBall.for = '>=0.14.2';
|
Example.wreckingBall.for = '>=0.14.2';
|
||||||
|
|
||||||
if (typeof module !== 'undefined') {
|
if (typeof module !== 'undefined') {
|
||||||
|
|
20827
package-lock.json
generated
20827
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",
|
"name": "matter-js",
|
||||||
"version": "0.15.0",
|
"version": "0.18.0",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"homepage": "http://brm.io/matter-js/",
|
"homepage": "http://brm.io/matter-js/",
|
||||||
"author": "Liam Brummitt <liam@brm.io> (http://brm.io/)",
|
"author": "Liam Brummitt <liam@brm.io> (http://brm.io/)",
|
||||||
|
@ -22,35 +22,46 @@
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"conventional-changelog-cli": "^2.1.1",
|
"conventional-changelog-cli": "^2.1.1",
|
||||||
"eslint": "^6.8.0",
|
"eslint": "^6.8.0",
|
||||||
|
"html-webpack-plugin": "^4.5.1",
|
||||||
"jest": "^25.1.0",
|
"jest": "^25.1.0",
|
||||||
"jest-worker": "^24.9.0",
|
"jest-worker": "^24.9.0",
|
||||||
"json-stringify-pretty-compact": "^2.0.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",
|
"puppeteer-core": "^5.5.0",
|
||||||
"run-sequence": "^2.2.1",
|
"terser-webpack-plugin": "^4.2.3",
|
||||||
"webpack": "^4.44.2",
|
"webpack": "^4.46.0",
|
||||||
|
"webpack-bundle-analyzer": "^4.4.0",
|
||||||
"webpack-cli": "^3.3.11",
|
"webpack-cli": "^3.3.11",
|
||||||
"webpack-dev-server": "^3.11.0"
|
"webpack-dev-server": "^3.11.1"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "webpack-dev-server --watch-content-base",
|
"start": "npm run dev",
|
||||||
"build": "webpack --mode=production & webpack --mode=production --env.MINIMIZE",
|
"dev": "npm run serve -- --open",
|
||||||
"build-alpha": "webpack --mode=production --env.ALPHA & webpack --mode=production --env.MINIMIZE --env.ALPHA",
|
"serve": "webpack-dev-server --no-cache --mode development --config webpack.demo.config.js",
|
||||||
"build-examples": "webpack --config webpack.examples.config.js --mode=production & webpack --config webpack.examples.config.js --mode=production --env.MINIMIZE",
|
"watch": "nodemon --watch webpack.demo.config.js --exec \"npm run serve\"",
|
||||||
"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",
|
"build": "webpack --mode=production --no-hot --no-watch & webpack --mode=production --no-hot --no-watch --env.MINIMIZE",
|
||||||
"lint": "eslint 'src/**/*.js' 'demo/js/Demo.js' 'demo/js/Compare.js' 'examples/*.js' 'webpack.*.js'",
|
"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": "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": "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-save": "SAVE=true npm run test-node",
|
||||||
"test-watch": "npm run test-node -- --watch",
|
"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",
|
"changelog": "conventional-changelog -i CHANGELOG.md -s -r",
|
||||||
"release": "npm version --no-git-tag-version",
|
"release": "npm version --no-git-tag-version",
|
||||||
"preversion": "git checkout master && npm run lint && SAVE=true npm run test-all",
|
"preversion": "git checkout master && npm run lint && SAVE=true npm run test-all",
|
||||||
"version": "git checkout -b release/$npm_package_version && npm run build"
|
"version": "git checkout -b release/$npm_package_version && npm run build"
|
||||||
},
|
},
|
||||||
"dependencies": {},
|
|
||||||
"files": [
|
"files": [
|
||||||
"src",
|
"src",
|
||||||
"build",
|
"build",
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
/**
|
/**
|
||||||
* The `Matter.Composite` module contains methods for creating and manipulating composite bodies.
|
* A composite is a collection of `Matter.Body`, `Matter.Constraint` and other `Matter.Composite` objects.
|
||||||
* 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.
|
* They are a container that can represent complex objects made of multiple parts, even if they are not physically connected.
|
||||||
* 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 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).
|
* See the included usage [examples](https://github.com/liabru/matter-js/tree/master/examples).
|
||||||
*
|
*
|
||||||
|
@ -37,7 +39,12 @@ var Body = require('./Body');
|
||||||
constraints: [],
|
constraints: [],
|
||||||
composites: [],
|
composites: [],
|
||||||
label: 'Composite',
|
label: 'Composite',
|
||||||
plugin: {}
|
plugin: {},
|
||||||
|
cache: {
|
||||||
|
allBodies: null,
|
||||||
|
allConstraints: null,
|
||||||
|
allComposites: null
|
||||||
|
}
|
||||||
}, options);
|
}, options);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -45,6 +52,7 @@ var Body = require('./Body');
|
||||||
* Sets the composite's `isModified` flag.
|
* Sets the composite's `isModified` flag.
|
||||||
* If `updateParents` is true, all parents will be set (default: false).
|
* If `updateParents` is true, all parents will be set (default: false).
|
||||||
* If `updateChildren` is true, all children will be set (default: false).
|
* If `updateChildren` is true, all children will be set (default: false).
|
||||||
|
* @private
|
||||||
* @method setModified
|
* @method setModified
|
||||||
* @param {composite} composite
|
* @param {composite} composite
|
||||||
* @param {boolean} isModified
|
* @param {boolean} isModified
|
||||||
|
@ -54,6 +62,12 @@ var Body = require('./Body');
|
||||||
Composite.setModified = function(composite, isModified, updateParents, updateChildren) {
|
Composite.setModified = function(composite, isModified, updateParents, updateChildren) {
|
||||||
composite.isModified = isModified;
|
composite.isModified = isModified;
|
||||||
|
|
||||||
|
if (isModified && composite.cache) {
|
||||||
|
composite.cache.allBodies = null;
|
||||||
|
composite.cache.allConstraints = null;
|
||||||
|
composite.cache.allComposites = null;
|
||||||
|
}
|
||||||
|
|
||||||
if (updateParents && composite.parent) {
|
if (updateParents && composite.parent) {
|
||||||
Composite.setModified(composite.parent, isModified, updateParents, updateChildren);
|
Composite.setModified(composite.parent, 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`.
|
* Triggers `beforeAdd` and `afterAdd` events on the `composite`.
|
||||||
* @method add
|
* @method add
|
||||||
* @param {composite} composite
|
* @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
|
* @return {composite} The original composite with the objects added
|
||||||
*/
|
*/
|
||||||
Composite.add = function(composite, object) {
|
Composite.add = function(composite, object) {
|
||||||
|
@ -117,7 +131,7 @@ var Body = require('./Body');
|
||||||
* Triggers `beforeRemove` and `afterRemove` events on the `composite`.
|
* Triggers `beforeRemove` and `afterRemove` events on the `composite`.
|
||||||
* @method remove
|
* @method remove
|
||||||
* @param {composite} composite
|
* @param {composite} composite
|
||||||
* @param {} object
|
* @param {object|array} object
|
||||||
* @param {boolean} [deep=false]
|
* @param {boolean} [deep=false]
|
||||||
* @return {composite} The original composite with the objects removed
|
* @return {composite} The original composite with the objects removed
|
||||||
*/
|
*/
|
||||||
|
@ -180,7 +194,6 @@ var Body = require('./Body');
|
||||||
var position = Common.indexOf(compositeA.composites, compositeB);
|
var position = Common.indexOf(compositeA.composites, compositeB);
|
||||||
if (position !== -1) {
|
if (position !== -1) {
|
||||||
Composite.removeCompositeAt(compositeA, position);
|
Composite.removeCompositeAt(compositeA, position);
|
||||||
Composite.setModified(compositeA, true, true, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (deep) {
|
if (deep) {
|
||||||
|
@ -233,7 +246,6 @@ var Body = require('./Body');
|
||||||
var position = Common.indexOf(composite.bodies, body);
|
var position = Common.indexOf(composite.bodies, body);
|
||||||
if (position !== -1) {
|
if (position !== -1) {
|
||||||
Composite.removeBodyAt(composite, position);
|
Composite.removeBodyAt(composite, position);
|
||||||
Composite.setModified(composite, true, true, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (deep) {
|
if (deep) {
|
||||||
|
@ -334,6 +346,7 @@ var Body = require('./Body');
|
||||||
|
|
||||||
composite.constraints.length = 0;
|
composite.constraints.length = 0;
|
||||||
composite.composites.length = 0;
|
composite.composites.length = 0;
|
||||||
|
|
||||||
Composite.setModified(composite, true, true, false);
|
Composite.setModified(composite, true, true, false);
|
||||||
|
|
||||||
return composite;
|
return composite;
|
||||||
|
@ -346,11 +359,19 @@ var Body = require('./Body');
|
||||||
* @return {body[]} All the bodies
|
* @return {body[]} All the bodies
|
||||||
*/
|
*/
|
||||||
Composite.allBodies = function(composite) {
|
Composite.allBodies = function(composite) {
|
||||||
|
if (composite.cache && composite.cache.allBodies) {
|
||||||
|
return composite.cache.allBodies;
|
||||||
|
}
|
||||||
|
|
||||||
var bodies = [].concat(composite.bodies);
|
var bodies = [].concat(composite.bodies);
|
||||||
|
|
||||||
for (var i = 0; i < composite.composites.length; i++)
|
for (var i = 0; i < composite.composites.length; i++)
|
||||||
bodies = bodies.concat(Composite.allBodies(composite.composites[i]));
|
bodies = bodies.concat(Composite.allBodies(composite.composites[i]));
|
||||||
|
|
||||||
|
if (composite.cache) {
|
||||||
|
composite.cache.allBodies = bodies;
|
||||||
|
}
|
||||||
|
|
||||||
return bodies;
|
return bodies;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -361,11 +382,19 @@ var Body = require('./Body');
|
||||||
* @return {constraint[]} All the constraints
|
* @return {constraint[]} All the constraints
|
||||||
*/
|
*/
|
||||||
Composite.allConstraints = function(composite) {
|
Composite.allConstraints = function(composite) {
|
||||||
|
if (composite.cache && composite.cache.allConstraints) {
|
||||||
|
return composite.cache.allConstraints;
|
||||||
|
}
|
||||||
|
|
||||||
var constraints = [].concat(composite.constraints);
|
var constraints = [].concat(composite.constraints);
|
||||||
|
|
||||||
for (var i = 0; i < composite.composites.length; i++)
|
for (var i = 0; i < composite.composites.length; i++)
|
||||||
constraints = constraints.concat(Composite.allConstraints(composite.composites[i]));
|
constraints = constraints.concat(Composite.allConstraints(composite.composites[i]));
|
||||||
|
|
||||||
|
if (composite.cache) {
|
||||||
|
composite.cache.allConstraints = constraints;
|
||||||
|
}
|
||||||
|
|
||||||
return constraints;
|
return constraints;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -376,11 +405,19 @@ var Body = require('./Body');
|
||||||
* @return {composite[]} All the composites
|
* @return {composite[]} All the composites
|
||||||
*/
|
*/
|
||||||
Composite.allComposites = function(composite) {
|
Composite.allComposites = function(composite) {
|
||||||
|
if (composite.cache && composite.cache.allComposites) {
|
||||||
|
return composite.cache.allComposites;
|
||||||
|
}
|
||||||
|
|
||||||
var composites = [].concat(composite.composites);
|
var composites = [].concat(composite.composites);
|
||||||
|
|
||||||
for (var i = 0; i < composite.composites.length; i++)
|
for (var i = 0; i < composite.composites.length; i++)
|
||||||
composites = composites.concat(Composite.allComposites(composite.composites[i]));
|
composites = composites.concat(Composite.allComposites(composite.composites[i]));
|
||||||
|
|
||||||
|
if (composite.cache) {
|
||||||
|
composite.cache.allComposites = composites;
|
||||||
|
}
|
||||||
|
|
||||||
return composites;
|
return composites;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -447,8 +484,6 @@ var Body = require('./Body');
|
||||||
objects[i].id = Common.nextId();
|
objects[i].id = Common.nextId();
|
||||||
}
|
}
|
||||||
|
|
||||||
Composite.setModified(composite, true, true, false);
|
|
||||||
|
|
||||||
return composite;
|
return composite;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -467,8 +502,6 @@ var Body = require('./Body');
|
||||||
Body.translate(bodies[i], translation);
|
Body.translate(bodies[i], translation);
|
||||||
}
|
}
|
||||||
|
|
||||||
Composite.setModified(composite, true, true, false);
|
|
||||||
|
|
||||||
return composite;
|
return composite;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -498,8 +531,6 @@ var Body = require('./Body');
|
||||||
Body.rotate(body, rotation);
|
Body.rotate(body, rotation);
|
||||||
}
|
}
|
||||||
|
|
||||||
Composite.setModified(composite, true, true, false);
|
|
||||||
|
|
||||||
return composite;
|
return composite;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -528,8 +559,6 @@ var Body = require('./Body');
|
||||||
Body.scale(body, scaleX, scaleY);
|
Body.scale(body, scaleX, scaleY);
|
||||||
}
|
}
|
||||||
|
|
||||||
Composite.setModified(composite, true, true, false);
|
|
||||||
|
|
||||||
return composite;
|
return composite;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -629,8 +658,7 @@ var Body = require('./Body');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A flag that specifies whether the composite has been modified during the current step.
|
* 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.
|
* This is automatically managed when bodies, constraints or composites are added or removed.
|
||||||
* If you need to change it manually, you should use the `Composite.setModified` method.
|
|
||||||
*
|
*
|
||||||
* @property isModified
|
* @property isModified
|
||||||
* @type boolean
|
* @type boolean
|
||||||
|
@ -682,4 +710,13 @@ var Body = require('./Body');
|
||||||
* @type {}
|
* @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.
|
* This module has now been replaced by `Matter.Composite`.
|
||||||
* A `Matter.World` is a `Matter.Composite` body, which is a collection of `Matter.Body`, `Matter.Constraint` and other `Matter.Composite`.
|
|
||||||
* A `Matter.World` has a few additional properties including `gravity` and `bounds`.
|
|
||||||
* It is important to use the functions in the `Matter.Composite` module to modify the world composite, rather than directly modifying its properties.
|
|
||||||
* There are also a few methods here that alias those in `Matter.Composite` for easier readability.
|
|
||||||
*
|
*
|
||||||
* See the included usage [examples](https://github.com/liabru/matter-js/tree/master/examples).
|
* 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
|
* @class World
|
||||||
* @extends Composite
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var World = {};
|
var World = {};
|
||||||
|
@ -16,132 +17,19 @@ var World = {};
|
||||||
module.exports = World;
|
module.exports = World;
|
||||||
|
|
||||||
var Composite = require('./Composite');
|
var Composite = require('./Composite');
|
||||||
var Constraint = require('../constraint/Constraint');
|
|
||||||
var Common = require('../core/Common');
|
var Common = require('../core/Common');
|
||||||
|
|
||||||
(function() {
|
(function() {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new world composite. The options parameter is an object that specifies any properties you wish to override the defaults.
|
* See above, aliases for back compatibility only
|
||||||
* See the properties section below for detailed information on what you can pass via the `options` object.
|
|
||||||
* @method create
|
|
||||||
* @constructor
|
|
||||||
* @param {} options
|
|
||||||
* @return {world} A new world
|
|
||||||
*/
|
|
||||||
World.create = function(options) {
|
|
||||||
var composite = Composite.create();
|
|
||||||
|
|
||||||
var defaults = {
|
|
||||||
label: 'World',
|
|
||||||
gravity: {
|
|
||||||
x: 0,
|
|
||||||
y: 1,
|
|
||||||
scale: 0.001
|
|
||||||
},
|
|
||||||
bounds: {
|
|
||||||
min: { x: -Infinity, y: -Infinity },
|
|
||||||
max: { x: Infinity, y: Infinity }
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return Common.extend(composite, defaults, options);
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
*
|
|
||||||
* Properties Documentation
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The gravity to apply on the world.
|
|
||||||
*
|
|
||||||
* @property gravity
|
|
||||||
* @type object
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The gravity x component.
|
|
||||||
*
|
|
||||||
* @property gravity.x
|
|
||||||
* @type object
|
|
||||||
* @default 0
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The gravity y component.
|
|
||||||
*
|
|
||||||
* @property gravity.y
|
|
||||||
* @type object
|
|
||||||
* @default 1
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The gravity scale factor.
|
|
||||||
*
|
|
||||||
* @property gravity.scale
|
|
||||||
* @type object
|
|
||||||
* @default 0.001
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A `Bounds` object that defines the world bounds for collision detection.
|
|
||||||
*
|
|
||||||
* @property bounds
|
|
||||||
* @type bounds
|
|
||||||
* @default { min: { x: -Infinity, y: -Infinity }, max: { x: Infinity, y: Infinity } }
|
|
||||||
*/
|
|
||||||
|
|
||||||
// World is a Composite body
|
|
||||||
// see src/module/Outro.js for these aliases:
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An alias for Composite.add
|
|
||||||
* @method add
|
|
||||||
* @param {world} world
|
|
||||||
* @param {} object
|
|
||||||
* @return {composite} The original world with the objects added
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An alias for Composite.remove
|
|
||||||
* @method remove
|
|
||||||
* @param {world} world
|
|
||||||
* @param {} object
|
|
||||||
* @param {boolean} [deep=false]
|
|
||||||
* @return {composite} The original world with the objects removed
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An alias for Composite.clear
|
|
||||||
* @method clear
|
|
||||||
* @param {world} world
|
|
||||||
* @param {boolean} keepStatic
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An alias for Composite.addComposite
|
|
||||||
* @method addComposite
|
|
||||||
* @param {world} world
|
|
||||||
* @param {composite} composite
|
|
||||||
* @return {world} The original world with the objects from composite added
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An alias for Composite.addBody
|
|
||||||
* @method addBody
|
|
||||||
* @param {world} world
|
|
||||||
* @param {body} body
|
|
||||||
* @return {world} The original world with the body added
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An alias for Composite.addConstraint
|
|
||||||
* @method addConstraint
|
|
||||||
* @param {world} world
|
|
||||||
* @param {constraint} constraint
|
|
||||||
* @return {world} The original world with the constraint added
|
|
||||||
*/
|
*/
|
||||||
|
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) {
|
Contact.create = function(vertex) {
|
||||||
return {
|
return {
|
||||||
id: Contact.id(vertex),
|
|
||||||
vertex: vertex,
|
vertex: vertex,
|
||||||
normalImpulse: 0,
|
normalImpulse: 0,
|
||||||
tangentImpulse: 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
|
* @class Detector
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// TODO: speculative contacts
|
|
||||||
|
|
||||||
var Detector = {};
|
var Detector = {};
|
||||||
|
|
||||||
module.exports = Detector;
|
module.exports = Detector;
|
||||||
|
|
||||||
var SAT = require('./SAT');
|
var Common = require('../core/Common');
|
||||||
var Pair = require('./Pair');
|
var Collision = require('./Collision');
|
||||||
var Bounds = require('../geometry/Bounds');
|
|
||||||
|
|
||||||
(function() {
|
(function() {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds all collisions given a list of pairs.
|
* Creates a new collision detector.
|
||||||
* @method collisions
|
* @method create
|
||||||
* @param {pair[]} broadphasePairs
|
* @param {} options
|
||||||
* @param {engine} engine
|
* @return {detector} A new collision detector
|
||||||
* @param {number} delta
|
|
||||||
* @return {array} collisions
|
|
||||||
*/
|
*/
|
||||||
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 = [],
|
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
|
bodies.sort(Detector._compareBoundsX);
|
||||||
var metrics = engine.metrics;
|
|
||||||
// @endif
|
|
||||||
|
|
||||||
for (var i = 0; i < broadphasePairs.length; i++) {
|
for (i = 0; i < bodiesLength; i++) {
|
||||||
var bodyA = broadphasePairs[i][0],
|
var bodyA = bodies[i],
|
||||||
bodyB = broadphasePairs[i][1];
|
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))
|
for (j = i + 1; j < bodiesLength; j++) {
|
||||||
continue;
|
var bodyB = bodies[j],
|
||||||
|
boundsB = bodyB.bounds;
|
||||||
|
|
||||||
if (!Detector.canCollide(bodyA.collisionFilter, bodyB.collisionFilter))
|
if (boundsB.min.x > boundXMax) {
|
||||||
continue;
|
break;
|
||||||
|
|
||||||
// @if DEBUG
|
|
||||||
metrics.midphaseTests += 1;
|
|
||||||
// @endif
|
|
||||||
|
|
||||||
// mid phase
|
|
||||||
if (Bounds.overlaps(bodyA.bounds, bodyB.bounds)) {
|
|
||||||
for (var j = bodyA.parts.length > 1 ? 1 : 0; j < bodyA.parts.length; j++) {
|
|
||||||
var partA = bodyA.parts[j];
|
|
||||||
|
|
||||||
for (var k = bodyB.parts.length > 1 ? 1 : 0; k < bodyB.parts.length; k++) {
|
|
||||||
var partB = bodyB.parts[k];
|
|
||||||
|
|
||||||
if ((partA === bodyA && partB === bodyB) || Bounds.overlaps(partA.bounds, partB.bounds)) {
|
|
||||||
// find a previous collision we could reuse
|
|
||||||
var pairId = Pair.id(partA, partB),
|
|
||||||
pair = pairsTable[pairId],
|
|
||||||
previousCollision;
|
|
||||||
|
|
||||||
if (pair && pair.isActive) {
|
|
||||||
previousCollision = pair.collision;
|
|
||||||
} else {
|
|
||||||
previousCollision = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// narrow phase
|
if (boundYMax < boundsB.min.y || boundYMin > boundsB.max.y) {
|
||||||
var collision = SAT.collides(partA, partB, previousCollision, delta);
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// @if DEBUG
|
if (bodyAStatic && (bodyB.isStatic || bodyB.isSleeping)) {
|
||||||
metrics.narrowphaseTests += 1;
|
continue;
|
||||||
if (collision.reused)
|
}
|
||||||
metrics.narrowReuseCount += 1;
|
|
||||||
// @endif
|
|
||||||
|
|
||||||
if (collision.collided) {
|
if (!canCollide(bodyA.collisionFilter, bodyB.collisionFilter)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var partsBLength = bodyB.parts.length;
|
||||||
|
|
||||||
|
if (partsASingle && partsBLength === 1) {
|
||||||
|
var collision = collides(bodyA, bodyB, pairs);
|
||||||
|
|
||||||
|
if (collision) {
|
||||||
|
collisions.push(collision);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
var partsAStart = partsALength > 1 ? 1 : 0,
|
||||||
|
partsBStart = partsBLength > 1 ? 1 : 0;
|
||||||
|
|
||||||
|
for (var k = partsAStart; k < partsALength; k++) {
|
||||||
|
var partA = bodyA.parts[k],
|
||||||
|
boundsA = partA.bounds;
|
||||||
|
|
||||||
|
for (var z = partsBStart; z < partsBLength; z++) {
|
||||||
|
var partB = bodyB.parts[z],
|
||||||
|
boundsB = partB.bounds;
|
||||||
|
|
||||||
|
if (boundsA.min.x > boundsB.max.x || boundsA.max.x < boundsB.min.x
|
||||||
|
|| boundsA.max.y < boundsB.min.y || boundsA.min.y > boundsB.max.y) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var collision = collides(partA, partB, pairs);
|
||||||
|
|
||||||
|
if (collision) {
|
||||||
collisions.push(collision);
|
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;
|
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.
|
* The `Matter.Grid` module contains methods for creating and manipulating collision broadphase grid structures.
|
||||||
*
|
*
|
||||||
* @class Grid
|
* @class Grid
|
||||||
|
* @deprecated
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var Grid = {};
|
var Grid = {};
|
||||||
|
@ -9,21 +15,20 @@ var Grid = {};
|
||||||
module.exports = Grid;
|
module.exports = Grid;
|
||||||
|
|
||||||
var Pair = require('./Pair');
|
var Pair = require('./Pair');
|
||||||
var Detector = require('./Detector');
|
|
||||||
var Common = require('../core/Common');
|
var Common = require('../core/Common');
|
||||||
|
var deprecated = Common.deprecated;
|
||||||
|
|
||||||
(function() {
|
(function() {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new grid.
|
* Creates a new grid.
|
||||||
|
* @deprecated replaced by Matter.Detector
|
||||||
* @method create
|
* @method create
|
||||||
* @param {} options
|
* @param {} options
|
||||||
* @return {grid} A new grid
|
* @return {grid} A new grid
|
||||||
*/
|
*/
|
||||||
Grid.create = function(options) {
|
Grid.create = function(options) {
|
||||||
var defaults = {
|
var defaults = {
|
||||||
controller: Grid,
|
|
||||||
detector: Detector.collisions,
|
|
||||||
buckets: {},
|
buckets: {},
|
||||||
pairs: {},
|
pairs: {},
|
||||||
pairsList: [],
|
pairsList: [],
|
||||||
|
@ -52,6 +57,7 @@ var Common = require('../core/Common');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the grid.
|
* Updates the grid.
|
||||||
|
* @deprecated replaced by Matter.Detector
|
||||||
* @method update
|
* @method update
|
||||||
* @param {grid} grid
|
* @param {grid} grid
|
||||||
* @param {body[]} bodies
|
* @param {body[]} bodies
|
||||||
|
@ -66,20 +72,15 @@ var Common = require('../core/Common');
|
||||||
bucketId,
|
bucketId,
|
||||||
gridChanged = false;
|
gridChanged = false;
|
||||||
|
|
||||||
// @if DEBUG
|
|
||||||
var metrics = engine.metrics;
|
|
||||||
metrics.broadphaseTests = 0;
|
|
||||||
// @endif
|
|
||||||
|
|
||||||
for (i = 0; i < bodies.length; i++) {
|
for (i = 0; i < bodies.length; i++) {
|
||||||
var body = bodies[i];
|
var body = bodies[i];
|
||||||
|
|
||||||
if (body.isSleeping && !forceUpdate)
|
if (body.isSleeping && !forceUpdate)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// don't update out of world bodies
|
// temporary back compatibility bounds check
|
||||||
if (body.bounds.max.x < world.bounds.min.x || body.bounds.min.x > world.bounds.max.x
|
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)
|
|| body.bounds.max.y < world.bounds.min.y || body.bounds.min.y > world.bounds.max.y))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var newRegion = Grid._getRegion(grid, body);
|
var newRegion = Grid._getRegion(grid, body);
|
||||||
|
@ -87,10 +88,6 @@ var Common = require('../core/Common');
|
||||||
// if the body has changed grid region
|
// if the body has changed grid region
|
||||||
if (!body.region || newRegion.id !== body.region.id || forceUpdate) {
|
if (!body.region || newRegion.id !== body.region.id || forceUpdate) {
|
||||||
|
|
||||||
// @if DEBUG
|
|
||||||
metrics.broadphaseTests += 1;
|
|
||||||
// @endif
|
|
||||||
|
|
||||||
if (!body.region || forceUpdate)
|
if (!body.region || forceUpdate)
|
||||||
body.region = newRegion;
|
body.region = newRegion;
|
||||||
|
|
||||||
|
@ -139,8 +136,11 @@ var Common = require('../core/Common');
|
||||||
grid.pairsList = Grid._createActivePairsList(grid);
|
grid.pairsList = Grid._createActivePairsList(grid);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
deprecated(Grid, 'update', 'Grid.update ➤ replaced by Matter.Detector');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clears the grid.
|
* Clears the grid.
|
||||||
|
* @deprecated replaced by Matter.Detector
|
||||||
* @method clear
|
* @method clear
|
||||||
* @param {grid} grid
|
* @param {grid} grid
|
||||||
*/
|
*/
|
||||||
|
@ -150,9 +150,12 @@ var Common = require('../core/Common');
|
||||||
grid.pairsList = [];
|
grid.pairsList = [];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
deprecated(Grid, 'clear', 'Grid.clear ➤ replaced by Matter.Detector');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds the union of two regions.
|
* Finds the union of two regions.
|
||||||
* @method _regionUnion
|
* @method _regionUnion
|
||||||
|
* @deprecated replaced by Matter.Detector
|
||||||
* @private
|
* @private
|
||||||
* @param {} regionA
|
* @param {} regionA
|
||||||
* @param {} regionB
|
* @param {} regionB
|
||||||
|
@ -170,6 +173,7 @@ var Common = require('../core/Common');
|
||||||
/**
|
/**
|
||||||
* Gets the region a given body falls in for a given grid.
|
* Gets the region a given body falls in for a given grid.
|
||||||
* @method _getRegion
|
* @method _getRegion
|
||||||
|
* @deprecated replaced by Matter.Detector
|
||||||
* @private
|
* @private
|
||||||
* @param {} grid
|
* @param {} grid
|
||||||
* @param {} body
|
* @param {} body
|
||||||
|
@ -188,6 +192,7 @@ var Common = require('../core/Common');
|
||||||
/**
|
/**
|
||||||
* Creates a region.
|
* Creates a region.
|
||||||
* @method _createRegion
|
* @method _createRegion
|
||||||
|
* @deprecated replaced by Matter.Detector
|
||||||
* @private
|
* @private
|
||||||
* @param {} startCol
|
* @param {} startCol
|
||||||
* @param {} endCol
|
* @param {} endCol
|
||||||
|
@ -208,6 +213,7 @@ var Common = require('../core/Common');
|
||||||
/**
|
/**
|
||||||
* Gets the bucket id at the given position.
|
* Gets the bucket id at the given position.
|
||||||
* @method _getBucketId
|
* @method _getBucketId
|
||||||
|
* @deprecated replaced by Matter.Detector
|
||||||
* @private
|
* @private
|
||||||
* @param {} column
|
* @param {} column
|
||||||
* @param {} row
|
* @param {} row
|
||||||
|
@ -220,6 +226,7 @@ var Common = require('../core/Common');
|
||||||
/**
|
/**
|
||||||
* Creates a bucket.
|
* Creates a bucket.
|
||||||
* @method _createBucket
|
* @method _createBucket
|
||||||
|
* @deprecated replaced by Matter.Detector
|
||||||
* @private
|
* @private
|
||||||
* @param {} buckets
|
* @param {} buckets
|
||||||
* @param {} bucketId
|
* @param {} bucketId
|
||||||
|
@ -233,14 +240,20 @@ var Common = require('../core/Common');
|
||||||
/**
|
/**
|
||||||
* Adds a body to a bucket.
|
* Adds a body to a bucket.
|
||||||
* @method _bucketAddBody
|
* @method _bucketAddBody
|
||||||
|
* @deprecated replaced by Matter.Detector
|
||||||
* @private
|
* @private
|
||||||
* @param {} grid
|
* @param {} grid
|
||||||
* @param {} bucket
|
* @param {} bucket
|
||||||
* @param {} body
|
* @param {} body
|
||||||
*/
|
*/
|
||||||
Grid._bucketAddBody = function(grid, bucket, body) {
|
Grid._bucketAddBody = function(grid, bucket, body) {
|
||||||
|
var gridPairs = grid.pairs,
|
||||||
|
pairId = Pair.id,
|
||||||
|
bucketLength = bucket.length,
|
||||||
|
i;
|
||||||
|
|
||||||
// add new pairs
|
// add new pairs
|
||||||
for (var i = 0; i < bucket.length; i++) {
|
for (i = 0; i < bucketLength; i++) {
|
||||||
var bodyB = bucket[i];
|
var bodyB = bucket[i];
|
||||||
|
|
||||||
if (body.id === bodyB.id || (body.isStatic && bodyB.isStatic))
|
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
|
// keep track of the number of buckets the pair exists in
|
||||||
// important for Grid.update to work
|
// important for Grid.update to work
|
||||||
var pairId = Pair.id(body, bodyB),
|
var id = pairId(body, bodyB),
|
||||||
pair = grid.pairs[pairId];
|
pair = gridPairs[id];
|
||||||
|
|
||||||
if (pair) {
|
if (pair) {
|
||||||
pair[2] += 1;
|
pair[2] += 1;
|
||||||
} else {
|
} 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.
|
* Removes a body from a bucket.
|
||||||
* @method _bucketRemoveBody
|
* @method _bucketRemoveBody
|
||||||
|
* @deprecated replaced by Matter.Detector
|
||||||
* @private
|
* @private
|
||||||
* @param {} grid
|
* @param {} grid
|
||||||
* @param {} bucket
|
* @param {} bucket
|
||||||
* @param {} body
|
* @param {} body
|
||||||
*/
|
*/
|
||||||
Grid._bucketRemoveBody = function(grid, bucket, body) {
|
Grid._bucketRemoveBody = function(grid, bucket, body) {
|
||||||
|
var gridPairs = grid.pairs,
|
||||||
|
pairId = Pair.id,
|
||||||
|
i;
|
||||||
|
|
||||||
// remove from bucket
|
// remove from bucket
|
||||||
bucket.splice(Common.indexOf(bucket, body), 1);
|
bucket.splice(Common.indexOf(bucket, body), 1);
|
||||||
|
|
||||||
|
var bucketLength = bucket.length;
|
||||||
|
|
||||||
// update pair counts
|
// 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
|
// keep track of the number of buckets the pair exists in
|
||||||
// important for _createActivePairsList to work
|
// important for _createActivePairsList to work
|
||||||
var bodyB = bucket[i],
|
var pair = gridPairs[pairId(body, bucket[i])];
|
||||||
pairId = Pair.id(body, bodyB),
|
|
||||||
pair = grid.pairs[pairId];
|
|
||||||
|
|
||||||
if (pair)
|
if (pair)
|
||||||
pair[2] -= 1;
|
pair[2] -= 1;
|
||||||
|
@ -290,28 +308,29 @@ var Common = require('../core/Common');
|
||||||
/**
|
/**
|
||||||
* Generates a list of the active pairs in the grid.
|
* Generates a list of the active pairs in the grid.
|
||||||
* @method _createActivePairsList
|
* @method _createActivePairsList
|
||||||
|
* @deprecated replaced by Matter.Detector
|
||||||
* @private
|
* @private
|
||||||
* @param {} grid
|
* @param {} grid
|
||||||
* @return [] pairs
|
* @return [] pairs
|
||||||
*/
|
*/
|
||||||
Grid._createActivePairsList = function(grid) {
|
Grid._createActivePairsList = function(grid) {
|
||||||
var pairKeys,
|
var pair,
|
||||||
pair,
|
gridPairs = grid.pairs,
|
||||||
pairs = [];
|
pairKeys = Common.keys(gridPairs),
|
||||||
|
pairKeysLength = pairKeys.length,
|
||||||
// grid.pairs is used as a hashmap
|
pairs = [],
|
||||||
pairKeys = Common.keys(grid.pairs);
|
k;
|
||||||
|
|
||||||
// iterate over grid.pairs
|
// iterate over grid.pairs
|
||||||
for (var k = 0; k < pairKeys.length; k++) {
|
for (k = 0; k < pairKeysLength; k++) {
|
||||||
pair = grid.pairs[pairKeys[k]];
|
pair = gridPairs[pairKeys[k]];
|
||||||
|
|
||||||
// if pair exists in at least one bucket
|
// if pair exists in at least one bucket
|
||||||
// it is a pair that needs further collision testing so push it
|
// it is a pair that needs further collision testing so push it
|
||||||
if (pair[2] > 0) {
|
if (pair[2] > 0) {
|
||||||
pairs.push(pair);
|
pairs.push(pair);
|
||||||
} else {
|
} else {
|
||||||
delete grid.pairs[pairKeys[k]];
|
delete gridPairs[pairKeys[k]];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,15 +21,14 @@ var Contact = require('./Contact');
|
||||||
*/
|
*/
|
||||||
Pair.create = function(collision, timestamp) {
|
Pair.create = function(collision, timestamp) {
|
||||||
var bodyA = collision.bodyA,
|
var bodyA = collision.bodyA,
|
||||||
bodyB = collision.bodyB,
|
bodyB = collision.bodyB;
|
||||||
parentA = collision.parentA,
|
|
||||||
parentB = collision.parentB;
|
|
||||||
|
|
||||||
var pair = {
|
var pair = {
|
||||||
id: Pair.id(bodyA, bodyB),
|
id: Pair.id(bodyA, bodyB),
|
||||||
bodyA: bodyA,
|
bodyA: bodyA,
|
||||||
bodyB: bodyB,
|
bodyB: bodyB,
|
||||||
contacts: {},
|
collision: collision,
|
||||||
|
contacts: [],
|
||||||
activeContacts: [],
|
activeContacts: [],
|
||||||
separation: 0,
|
separation: 0,
|
||||||
isActive: true,
|
isActive: true,
|
||||||
|
@ -37,11 +36,11 @@ var Contact = require('./Contact');
|
||||||
isSensor: bodyA.isSensor || bodyB.isSensor,
|
isSensor: bodyA.isSensor || bodyB.isSensor,
|
||||||
timeCreated: timestamp,
|
timeCreated: timestamp,
|
||||||
timeUpdated: timestamp,
|
timeUpdated: timestamp,
|
||||||
inverseMass: parentA.inverseMass + parentB.inverseMass,
|
inverseMass: 0,
|
||||||
friction: Math.min(parentA.friction, parentB.friction),
|
friction: 0,
|
||||||
frictionStatic: Math.max(parentA.frictionStatic, parentB.frictionStatic),
|
frictionStatic: 0,
|
||||||
restitution: Math.max(parentA.restitution, parentB.restitution),
|
restitution: 0,
|
||||||
slop: Math.max(parentA.slop, parentB.slop)
|
slop: 0
|
||||||
};
|
};
|
||||||
|
|
||||||
Pair.update(pair, collision, timestamp);
|
Pair.update(pair, collision, timestamp);
|
||||||
|
@ -61,20 +60,25 @@ var Contact = require('./Contact');
|
||||||
supports = collision.supports,
|
supports = collision.supports,
|
||||||
activeContacts = pair.activeContacts,
|
activeContacts = pair.activeContacts,
|
||||||
parentA = collision.parentA,
|
parentA = collision.parentA,
|
||||||
parentB = collision.parentB;
|
parentB = collision.parentB,
|
||||||
|
parentAVerticesLength = parentA.vertices.length;
|
||||||
|
|
||||||
|
pair.isActive = true;
|
||||||
|
pair.timeUpdated = timestamp;
|
||||||
pair.collision = collision;
|
pair.collision = collision;
|
||||||
|
pair.separation = collision.depth;
|
||||||
pair.inverseMass = parentA.inverseMass + parentB.inverseMass;
|
pair.inverseMass = parentA.inverseMass + parentB.inverseMass;
|
||||||
pair.friction = Math.min(parentA.friction, parentB.friction);
|
pair.friction = parentA.friction < parentB.friction ? parentA.friction : parentB.friction;
|
||||||
pair.frictionStatic = Math.max(parentA.frictionStatic, parentB.frictionStatic);
|
pair.frictionStatic = parentA.frictionStatic > parentB.frictionStatic ? parentA.frictionStatic : parentB.frictionStatic;
|
||||||
pair.restitution = Math.max(parentA.restitution, parentB.restitution);
|
pair.restitution = parentA.restitution > parentB.restitution ? parentA.restitution : parentB.restitution;
|
||||||
pair.slop = Math.max(parentA.slop, parentB.slop);
|
pair.slop = parentA.slop > parentB.slop ? parentA.slop : parentB.slop;
|
||||||
|
|
||||||
|
collision.pair = pair;
|
||||||
activeContacts.length = 0;
|
activeContacts.length = 0;
|
||||||
|
|
||||||
if (collision.collided) {
|
|
||||||
for (var i = 0; i < supports.length; i++) {
|
for (var i = 0; i < supports.length; i++) {
|
||||||
var support = supports[i],
|
var support = supports[i],
|
||||||
contactId = Contact.id(support),
|
contactId = support.body === parentA ? support.index : parentAVerticesLength + support.index,
|
||||||
contact = contacts[contactId];
|
contact = contacts[contactId];
|
||||||
|
|
||||||
if (contact) {
|
if (contact) {
|
||||||
|
@ -83,13 +87,6 @@ var Contact = require('./Contact');
|
||||||
activeContacts.push(contacts[contactId] = Contact.create(support));
|
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() {
|
(function() {
|
||||||
|
|
||||||
Pairs._pairMaxIdleLife = 1000;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new pairs structure.
|
* Creates a new pairs structure.
|
||||||
* @method create
|
* @method create
|
||||||
|
@ -40,12 +38,14 @@ var Common = require('../core/Common');
|
||||||
*/
|
*/
|
||||||
Pairs.update = function(pairs, collisions, timestamp) {
|
Pairs.update = function(pairs, collisions, timestamp) {
|
||||||
var pairsList = pairs.list,
|
var pairsList = pairs.list,
|
||||||
|
pairsListLength = pairsList.length,
|
||||||
pairsTable = pairs.table,
|
pairsTable = pairs.table,
|
||||||
|
collisionsLength = collisions.length,
|
||||||
collisionStart = pairs.collisionStart,
|
collisionStart = pairs.collisionStart,
|
||||||
collisionEnd = pairs.collisionEnd,
|
collisionEnd = pairs.collisionEnd,
|
||||||
collisionActive = pairs.collisionActive,
|
collisionActive = pairs.collisionActive,
|
||||||
collision,
|
collision,
|
||||||
pairId,
|
pairIndex,
|
||||||
pair,
|
pair,
|
||||||
i;
|
i;
|
||||||
|
|
||||||
|
@ -54,17 +54,13 @@ var Common = require('../core/Common');
|
||||||
collisionEnd.length = 0;
|
collisionEnd.length = 0;
|
||||||
collisionActive.length = 0;
|
collisionActive.length = 0;
|
||||||
|
|
||||||
for (i = 0; i < pairsList.length; i++) {
|
for (i = 0; i < pairsListLength; i++) {
|
||||||
pairsList[i].confirmedActive = false;
|
pairsList[i].confirmedActive = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < collisions.length; i++) {
|
for (i = 0; i < collisionsLength; i++) {
|
||||||
collision = collisions[i];
|
collision = collisions[i];
|
||||||
|
pair = collision.pair;
|
||||||
if (collision.collided) {
|
|
||||||
pairId = Pair.id(collision.bodyA, collision.bodyB);
|
|
||||||
|
|
||||||
pair = pairsTable[pairId];
|
|
||||||
|
|
||||||
if (pair) {
|
if (pair) {
|
||||||
// pair already exists (but may or may not be active)
|
// pair already exists (but may or may not be active)
|
||||||
|
@ -82,62 +78,37 @@ var Common = require('../core/Common');
|
||||||
} else {
|
} else {
|
||||||
// pair did not exist, create a new pair
|
// pair did not exist, create a new pair
|
||||||
pair = Pair.create(collision, timestamp);
|
pair = Pair.create(collision, timestamp);
|
||||||
pairsTable[pairId] = pair;
|
pairsTable[pair.id] = pair;
|
||||||
|
|
||||||
// push the new pair
|
// push the new pair
|
||||||
collisionStart.push(pair);
|
collisionStart.push(pair);
|
||||||
pairsList.push(pair);
|
pairsList.push(pair);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// deactivate previously active pairs that are now inactive
|
// find pairs that are no longer active
|
||||||
for (i = 0; i < pairsList.length; i++) {
|
var removePairIndex = [];
|
||||||
|
pairsListLength = pairsList.length;
|
||||||
|
|
||||||
|
for (i = 0; i < pairsListLength; i++) {
|
||||||
pair = pairsList[i];
|
pair = pairsList[i];
|
||||||
if (pair.isActive && !pair.confirmedActive) {
|
|
||||||
|
if (!pair.confirmedActive) {
|
||||||
Pair.setActive(pair, false, timestamp);
|
Pair.setActive(pair, false, timestamp);
|
||||||
collisionEnd.push(pair);
|
collisionEnd.push(pair);
|
||||||
|
|
||||||
|
if (!pair.collision.bodyA.isSleeping && !pair.collision.bodyB.isSleeping) {
|
||||||
|
removePairIndex.push(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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
|
// remove inactive pairs
|
||||||
for (i = 0; i < indexesToRemove.length; i++) {
|
for (i = 0; i < removePairIndex.length; i++) {
|
||||||
pairIndex = indexesToRemove[i] - i;
|
pairIndex = removePairIndex[i] - i;
|
||||||
pair = pairsList[pairIndex];
|
pair = pairsList[pairIndex];
|
||||||
delete pairsTable[pair.id];
|
|
||||||
pairsList.splice(pairIndex, 1);
|
pairsList.splice(pairIndex, 1);
|
||||||
|
delete pairsTable[pair.id];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ var Query = {};
|
||||||
module.exports = Query;
|
module.exports = Query;
|
||||||
|
|
||||||
var Vector = require('../geometry/Vector');
|
var Vector = require('../geometry/Vector');
|
||||||
var SAT = require('./SAT');
|
var Collision = require('./Collision');
|
||||||
var Bounds = require('../geometry/Bounds');
|
var Bounds = require('../geometry/Bounds');
|
||||||
var Bodies = require('../factory/Bodies');
|
var Bodies = require('../factory/Bodies');
|
||||||
var Vertices = require('../geometry/Vertices');
|
var Vertices = require('../geometry/Vertices');
|
||||||
|
@ -23,22 +23,28 @@ var Vertices = require('../geometry/Vertices');
|
||||||
* @method collides
|
* @method collides
|
||||||
* @param {body} body
|
* @param {body} body
|
||||||
* @param {body[]} bodies
|
* @param {body[]} bodies
|
||||||
* @return {object[]} Collisions
|
* @return {collision[]} Collisions
|
||||||
*/
|
*/
|
||||||
Query.collides = function(body, bodies) {
|
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++) {
|
for (var i = 0; i < bodiesLength; i++) {
|
||||||
var bodyA = bodies[i];
|
var bodyA = bodies[i],
|
||||||
|
partsALength = bodyA.parts.length,
|
||||||
|
partsAStart = partsALength === 1 ? 0 : 1;
|
||||||
|
|
||||||
if (Bounds.overlaps(bodyA.bounds, body.bounds)) {
|
if (overlaps(bodyA.bounds, bounds)) {
|
||||||
for (var j = bodyA.parts.length === 1 ? 0 : 1; j < bodyA.parts.length; j++) {
|
for (var j = partsAStart; j < partsALength; j++) {
|
||||||
var part = bodyA.parts[j];
|
var part = bodyA.parts[j];
|
||||||
|
|
||||||
if (Bounds.overlaps(part.bounds, body.bounds)) {
|
if (overlaps(part.bounds, bounds)) {
|
||||||
var collision = SAT.collides(part, body);
|
var collision = collides(part, body);
|
||||||
|
|
||||||
if (collision.collided) {
|
if (collision) {
|
||||||
collisions.push(collision);
|
collisions.push(collision);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -57,7 +63,7 @@ var Vertices = require('../geometry/Vertices');
|
||||||
* @param {vector} startPoint
|
* @param {vector} startPoint
|
||||||
* @param {vector} endPoint
|
* @param {vector} endPoint
|
||||||
* @param {number} [rayWidth]
|
* @param {number} [rayWidth]
|
||||||
* @return {object[]} Collisions
|
* @return {collision[]} Collisions
|
||||||
*/
|
*/
|
||||||
Query.ray = function(bodies, startPoint, endPoint, rayWidth) {
|
Query.ray = function(bodies, startPoint, endPoint, rayWidth) {
|
||||||
rayWidth = rayWidth || 1e-100;
|
rayWidth = rayWidth || 1e-100;
|
||||||
|
|
|
@ -29,10 +29,11 @@ var Bounds = require('../geometry/Bounds');
|
||||||
Resolver.preSolvePosition = function(pairs) {
|
Resolver.preSolvePosition = function(pairs) {
|
||||||
var i,
|
var i,
|
||||||
pair,
|
pair,
|
||||||
activeCount;
|
activeCount,
|
||||||
|
pairsLength = pairs.length;
|
||||||
|
|
||||||
// find total contacts on each body
|
// find total contacts on each body
|
||||||
for (i = 0; i < pairs.length; i++) {
|
for (i = 0; i < pairsLength; i++) {
|
||||||
pair = pairs[i];
|
pair = pairs[i];
|
||||||
|
|
||||||
if (!pair.isActive)
|
if (!pair.isActive)
|
||||||
|
@ -57,18 +58,15 @@ var Bounds = require('../geometry/Bounds');
|
||||||
bodyA,
|
bodyA,
|
||||||
bodyB,
|
bodyB,
|
||||||
normal,
|
normal,
|
||||||
bodyBtoA,
|
|
||||||
contactShare,
|
contactShare,
|
||||||
positionImpulse,
|
positionImpulse,
|
||||||
timeScale = delta / Common._timeUnit,
|
timeScale = delta / Common._timeUnit,
|
||||||
damping = Common.clamp(Resolver._positionDampen * timeScale, 0, 1),
|
damping = Common.clamp(Resolver._positionDampen * timeScale, 0, 1),
|
||||||
tempA = Vector._temp[0],
|
positionDampen = Resolver._positionDampen,
|
||||||
tempB = Vector._temp[1],
|
pairsLength = pairs.length;
|
||||||
tempC = Vector._temp[2],
|
|
||||||
tempD = Vector._temp[3];
|
|
||||||
|
|
||||||
// find impulses required to resolve penetration
|
// find impulses required to resolve penetration
|
||||||
for (i = 0; i < pairs.length; i++) {
|
for (i = 0; i < pairsLength; i++) {
|
||||||
pair = pairs[i];
|
pair = pairs[i];
|
||||||
|
|
||||||
if (!pair.isActive || pair.isSensor)
|
if (!pair.isActive || pair.isSensor)
|
||||||
|
@ -80,14 +78,12 @@ var Bounds = require('../geometry/Bounds');
|
||||||
normal = collision.normal;
|
normal = collision.normal;
|
||||||
|
|
||||||
// get current separation between body edges involved in collision
|
// get current separation between body edges involved in collision
|
||||||
bodyBtoA = Vector.sub(Vector.add(bodyB.positionImpulse, bodyB.position, tempA),
|
pair.separation =
|
||||||
Vector.add(bodyA.positionImpulse,
|
normal.x * (bodyB.positionImpulse.x + collision.penetration.x - bodyA.positionImpulse.x)
|
||||||
Vector.sub(bodyB.position, collision.penetration, tempB), tempC), tempD);
|
+ normal.y * (bodyB.positionImpulse.y + collision.penetration.y - bodyA.positionImpulse.y);
|
||||||
|
|
||||||
pair.separation = Vector.dot(normal, bodyBtoA);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < pairs.length; i++) {
|
for (i = 0; i < pairsLength; i++) {
|
||||||
pair = pairs[i];
|
pair = pairs[i];
|
||||||
|
|
||||||
if (!pair.isActive || pair.isSensor)
|
if (!pair.isActive || pair.isSensor)
|
||||||
|
@ -103,13 +99,13 @@ var Bounds = require('../geometry/Bounds');
|
||||||
positionImpulse *= 2;
|
positionImpulse *= 2;
|
||||||
|
|
||||||
if (!(bodyA.isStatic || bodyA.isSleeping)) {
|
if (!(bodyA.isStatic || bodyA.isSleeping)) {
|
||||||
contactShare = Resolver._positionDampen / bodyA.totalContacts;
|
contactShare = positionDampen / bodyA.totalContacts;
|
||||||
bodyA.positionImpulse.x += normal.x * positionImpulse * contactShare;
|
bodyA.positionImpulse.x += normal.x * positionImpulse * contactShare;
|
||||||
bodyA.positionImpulse.y += normal.y * positionImpulse * contactShare;
|
bodyA.positionImpulse.y += normal.y * positionImpulse * contactShare;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(bodyB.isStatic || bodyB.isSleeping)) {
|
if (!(bodyB.isStatic || bodyB.isSleeping)) {
|
||||||
contactShare = Resolver._positionDampen / bodyB.totalContacts;
|
contactShare = positionDampen / bodyB.totalContacts;
|
||||||
bodyB.positionImpulse.x -= normal.x * positionImpulse * contactShare;
|
bodyB.positionImpulse.x -= normal.x * positionImpulse * contactShare;
|
||||||
bodyB.positionImpulse.y -= normal.y * positionImpulse * contactShare;
|
bodyB.positionImpulse.y -= normal.y * positionImpulse * contactShare;
|
||||||
}
|
}
|
||||||
|
@ -122,34 +118,43 @@ var Bounds = require('../geometry/Bounds');
|
||||||
* @param {body[]} bodies
|
* @param {body[]} bodies
|
||||||
*/
|
*/
|
||||||
Resolver.postSolvePosition = function(bodies) {
|
Resolver.postSolvePosition = function(bodies) {
|
||||||
for (var i = 0; i < bodies.length; i++) {
|
var positionWarming = Resolver._positionWarming,
|
||||||
var body = bodies[i];
|
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
|
// reset contact count
|
||||||
body.totalContacts = 0;
|
body.totalContacts = 0;
|
||||||
|
|
||||||
if (body.positionImpulse.x !== 0 || body.positionImpulse.y !== 0) {
|
if (positionImpulseX !== 0 || positionImpulseY !== 0) {
|
||||||
// update body geometry
|
// update body geometry
|
||||||
for (var j = 0; j < body.parts.length; j++) {
|
for (var j = 0; j < body.parts.length; j++) {
|
||||||
var part = body.parts[j];
|
var part = body.parts[j];
|
||||||
Vertices.translate(part.vertices, body.positionImpulse);
|
verticesTranslate(part.vertices, positionImpulse);
|
||||||
Bounds.update(part.bounds, part.vertices, body.velocity);
|
boundsUpdate(part.bounds, part.vertices, velocity);
|
||||||
part.position.x += body.positionImpulse.x;
|
part.position.x += positionImpulseX;
|
||||||
part.position.y += body.positionImpulse.y;
|
part.position.y += positionImpulseY;
|
||||||
}
|
}
|
||||||
|
|
||||||
// move the body without changing velocity
|
// move the body without changing velocity
|
||||||
body.positionPrev.x += body.positionImpulse.x;
|
body.positionPrev.x += positionImpulseX;
|
||||||
body.positionPrev.y += body.positionImpulse.y;
|
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
|
// reset cached impulse if the body has velocity along it
|
||||||
body.positionImpulse.x = 0;
|
positionImpulse.x = 0;
|
||||||
body.positionImpulse.y = 0;
|
positionImpulse.y = 0;
|
||||||
} else {
|
} else {
|
||||||
// warm the next iteration
|
// warm the next iteration
|
||||||
body.positionImpulse.x *= Resolver._positionWarming;
|
positionImpulse.x *= positionWarming;
|
||||||
body.positionImpulse.y *= Resolver._positionWarming;
|
positionImpulse.y *= positionWarming;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -161,61 +166,53 @@ var Bounds = require('../geometry/Bounds');
|
||||||
* @param {pair[]} pairs
|
* @param {pair[]} pairs
|
||||||
*/
|
*/
|
||||||
Resolver.preSolveVelocity = function(pairs) {
|
Resolver.preSolveVelocity = function(pairs) {
|
||||||
var i,
|
var pairsLength = pairs.length,
|
||||||
j,
|
i,
|
||||||
pair,
|
j;
|
||||||
contacts,
|
|
||||||
collision,
|
|
||||||
bodyA,
|
|
||||||
bodyB,
|
|
||||||
normal,
|
|
||||||
tangent,
|
|
||||||
contact,
|
|
||||||
contactVertex,
|
|
||||||
normalImpulse,
|
|
||||||
tangentImpulse,
|
|
||||||
offset,
|
|
||||||
impulse = Vector._temp[0],
|
|
||||||
tempA = Vector._temp[1];
|
|
||||||
|
|
||||||
for (i = 0; i < pairs.length; i++) {
|
for (i = 0; i < pairsLength; i++) {
|
||||||
pair = pairs[i];
|
var pair = pairs[i];
|
||||||
|
|
||||||
if (!pair.isActive || pair.isSensor)
|
if (!pair.isActive || pair.isSensor)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
contacts = pair.activeContacts;
|
var contacts = pair.activeContacts,
|
||||||
collision = pair.collision;
|
contactsLength = contacts.length,
|
||||||
bodyA = collision.parentA;
|
collision = pair.collision,
|
||||||
bodyB = collision.parentB;
|
bodyA = collision.parentA,
|
||||||
normal = collision.normal;
|
bodyB = collision.parentB,
|
||||||
|
normal = collision.normal,
|
||||||
tangent = collision.tangent;
|
tangent = collision.tangent;
|
||||||
|
|
||||||
// resolve each contact
|
// resolve each contact
|
||||||
for (j = 0; j < contacts.length; j++) {
|
for (j = 0; j < contactsLength; j++) {
|
||||||
contact = contacts[j];
|
var contact = contacts[j],
|
||||||
contactVertex = contact.vertex;
|
contactVertex = contact.vertex,
|
||||||
normalImpulse = contact.normalImpulse;
|
normalImpulse = contact.normalImpulse,
|
||||||
tangentImpulse = contact.tangentImpulse;
|
tangentImpulse = contact.tangentImpulse;
|
||||||
|
|
||||||
if (normalImpulse !== 0 || tangentImpulse !== 0) {
|
if (normalImpulse !== 0 || tangentImpulse !== 0) {
|
||||||
// total impulse from contact
|
// total impulse from contact
|
||||||
impulse.x = (normal.x * normalImpulse) + (tangent.x * tangentImpulse);
|
var impulseX = normal.x * normalImpulse + tangent.x * tangentImpulse,
|
||||||
impulse.y = (normal.y * normalImpulse) + (tangent.y * tangentImpulse);
|
impulseY = normal.y * normalImpulse + tangent.y * tangentImpulse;
|
||||||
|
|
||||||
// apply impulse from contact
|
// apply impulse from contact
|
||||||
if (!(bodyA.isStatic || bodyA.isSleeping)) {
|
if (!(bodyA.isStatic || bodyA.isSleeping)) {
|
||||||
offset = Vector.sub(contactVertex, bodyA.position, tempA);
|
bodyA.positionPrev.x += impulseX * bodyA.inverseMass;
|
||||||
bodyA.positionPrev.x += impulse.x * bodyA.inverseMass;
|
bodyA.positionPrev.y += impulseY * bodyA.inverseMass;
|
||||||
bodyA.positionPrev.y += impulse.y * bodyA.inverseMass;
|
bodyA.anglePrev += bodyA.inverseInertia * (
|
||||||
bodyA.anglePrev += Vector.cross(offset, impulse) * bodyA.inverseInertia;
|
(contactVertex.x - bodyA.position.x) * impulseY
|
||||||
|
- (contactVertex.y - bodyA.position.y) * impulseX
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(bodyB.isStatic || bodyB.isSleeping)) {
|
if (!(bodyB.isStatic || bodyB.isSleeping)) {
|
||||||
offset = Vector.sub(contactVertex, bodyB.position, tempA);
|
bodyB.positionPrev.x -= impulseX * bodyB.inverseMass;
|
||||||
bodyB.positionPrev.x -= impulse.x * bodyB.inverseMass;
|
bodyB.positionPrev.y -= impulseY * bodyB.inverseMass;
|
||||||
bodyB.positionPrev.y -= impulse.y * bodyB.inverseMass;
|
bodyB.anglePrev -= bodyB.inverseInertia * (
|
||||||
bodyB.anglePrev -= Vector.cross(offset, impulse) * 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],
|
tempB = Vector._temp[2],
|
||||||
tempC = Vector._temp[3],
|
tempC = Vector._temp[3],
|
||||||
tempD = Vector._temp[4],
|
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];
|
var pair = pairs[i];
|
||||||
|
|
||||||
if (!pair.isActive || pair.isSensor)
|
if (!pair.isActive || pair.isSensor)
|
||||||
|
@ -248,56 +255,84 @@ var Bounds = require('../geometry/Bounds');
|
||||||
var collision = pair.collision,
|
var collision = pair.collision,
|
||||||
bodyA = collision.parentA,
|
bodyA = collision.parentA,
|
||||||
bodyB = collision.parentB,
|
bodyB = collision.parentB,
|
||||||
normal = collision.normal,
|
bodyAVelocity = bodyA.velocity,
|
||||||
tangent = collision.tangent,
|
bodyBVelocity = bodyB.velocity,
|
||||||
|
normalX = collision.normal.x,
|
||||||
|
normalY = collision.normal.y,
|
||||||
|
tangentX = collision.tangent.x,
|
||||||
|
tangentY = collision.tangent.y,
|
||||||
contacts = pair.activeContacts,
|
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
|
// update body velocities
|
||||||
bodyA.velocity.x = bodyA.position.x - bodyA.positionPrev.x;
|
bodyAVelocity.x = bodyA.position.x - bodyA.positionPrev.x;
|
||||||
bodyA.velocity.y = bodyA.position.y - bodyA.positionPrev.y;
|
bodyAVelocity.y = bodyA.position.y - bodyA.positionPrev.y;
|
||||||
bodyB.velocity.x = bodyB.position.x - bodyB.positionPrev.x;
|
bodyBVelocity.x = bodyB.position.x - bodyB.positionPrev.x;
|
||||||
bodyB.velocity.y = bodyB.position.y - bodyB.positionPrev.y;
|
bodyBVelocity.y = bodyB.position.y - bodyB.positionPrev.y;
|
||||||
bodyA.angularVelocity = bodyA.angle - bodyA.anglePrev;
|
bodyA.angularVelocity = bodyA.angle - bodyA.anglePrev;
|
||||||
bodyB.angularVelocity = bodyB.angle - bodyB.anglePrev;
|
bodyB.angularVelocity = bodyB.angle - bodyB.anglePrev;
|
||||||
|
|
||||||
// resolve each contact
|
// resolve each contact
|
||||||
for (var j = 0; j < contacts.length; j++) {
|
for (j = 0; j < contactsLength; j++) {
|
||||||
var contact = contacts[j],
|
var contact = contacts[j],
|
||||||
contactVertex = contact.vertex,
|
contactVertex = contact.vertex;
|
||||||
offsetA = Vector.sub(contactVertex, bodyA.position, tempA),
|
|
||||||
offsetB = Vector.sub(contactVertex, bodyB.position, tempB),
|
|
||||||
velocityPointA = Vector.add(bodyA.velocity, Vector.mult(Vector.perp(offsetA), bodyA.angularVelocity), tempC),
|
|
||||||
velocityPointB = Vector.add(bodyB.velocity, Vector.mult(Vector.perp(offsetB), bodyB.angularVelocity), tempD),
|
|
||||||
relativeVelocity = Vector.sub(velocityPointA, velocityPointB, tempE),
|
|
||||||
normalVelocity = Vector.dot(normal, relativeVelocity);
|
|
||||||
|
|
||||||
var tangentVelocity = Vector.dot(tangent, relativeVelocity),
|
var offsetAX = contactVertex.x - bodyA.position.x,
|
||||||
tangentSpeed = Math.abs(tangentVelocity),
|
offsetAY = contactVertex.y - bodyA.position.y,
|
||||||
tangentVelocityDirection = Common.sign(tangentVelocity);
|
offsetBX = contactVertex.x - bodyB.position.x,
|
||||||
|
offsetBY = contactVertex.y - bodyB.position.y;
|
||||||
|
|
||||||
// raw impulses
|
var velocityPointAX = bodyAVelocity.x - offsetAY * bodyA.angularVelocity,
|
||||||
var normalImpulse = (1 + pair.restitution) * normalVelocity,
|
velocityPointAY = bodyAVelocity.y + offsetAX * bodyA.angularVelocity,
|
||||||
normalForce = Common.clamp(pair.separation + normalVelocity, 0, 1) * Resolver._frictionNormalMultiplier;
|
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
|
// coulomb friction
|
||||||
var tangentImpulse = tangentVelocity,
|
// var tangentImpulse = tangentVelocity,
|
||||||
maxFriction = Infinity;
|
// maxFriction = Infinity;
|
||||||
|
|
||||||
if (tangentSpeed > pair.friction * pair.frictionStatic * normalForce * timeScale3) {
|
// if (tangentSpeed > pair.friction * pair.frictionStatic * normalForce * timeScale3) {
|
||||||
maxFriction = tangentSpeed * timeScale;
|
// maxFriction = tangentSpeed * timeScale;
|
||||||
tangentImpulse = Common.clamp(
|
// tangentImpulse = Common.clamp(
|
||||||
pair.friction * tangentVelocityDirection * timeScale3,
|
// pair.friction * tangentVelocityDirection * timeScale3,
|
||||||
-maxFriction, maxFriction
|
// -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
|
// account for mass, inertia and contact offset
|
||||||
var oAcN = Vector.cross(offsetA, normal),
|
var oAcN = offsetAX * normalY - offsetAY * normalX,
|
||||||
oBcN = Vector.cross(offsetB, normal),
|
oBcN = offsetBX * normalY - offsetBY * normalX,
|
||||||
share = contactShare / (bodyA.inverseMass + bodyB.inverseMass + bodyA.inverseInertia * oAcN * oAcN + bodyB.inverseInertia * oBcN * oBcN);
|
share = contactShare / (inverseMassTotal + bodyA.inverseInertia * oAcN * oAcN + bodyB.inverseInertia * oBcN * oBcN);
|
||||||
|
|
||||||
normalImpulse *= share;
|
// raw impulses
|
||||||
|
var normalImpulse = (1 + pair.restitution) * normalVelocity * share;
|
||||||
tangentImpulse *= share;
|
tangentImpulse *= share;
|
||||||
|
|
||||||
// handle high velocity and resting collisions separately
|
// 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)
|
// solve resting collision constraints using Erin Catto's method (GDC08)
|
||||||
// impulse constraint tends to 0
|
// impulse constraint tends to 0
|
||||||
var contactNormalImpulse = contact.normalImpulse;
|
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;
|
normalImpulse = contact.normalImpulse - contactNormalImpulse;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -320,25 +356,27 @@ var Bounds = require('../geometry/Bounds');
|
||||||
// solve resting collision constraints using Erin Catto's method (GDC08)
|
// solve resting collision constraints using Erin Catto's method (GDC08)
|
||||||
// tangent impulse tends to -tangentSpeed or +tangentSpeed
|
// tangent impulse tends to -tangentSpeed or +tangentSpeed
|
||||||
var contactTangentImpulse = contact.tangentImpulse;
|
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;
|
tangentImpulse = contact.tangentImpulse - contactTangentImpulse;
|
||||||
}
|
}
|
||||||
|
|
||||||
// total impulse from contact
|
// total impulse from contact
|
||||||
impulse.x = (normal.x * normalImpulse) + (tangent.x * tangentImpulse);
|
var impulseX = normalX * normalImpulse + tangentX * tangentImpulse,
|
||||||
impulse.y = (normal.y * normalImpulse) + (tangent.y * tangentImpulse);
|
impulseY = normalY * normalImpulse + tangentY * tangentImpulse;
|
||||||
|
|
||||||
// apply impulse from contact
|
// apply impulse from contact
|
||||||
if (!(bodyA.isStatic || bodyA.isSleeping)) {
|
if (!(bodyA.isStatic || bodyA.isSleeping)) {
|
||||||
bodyA.positionPrev.x += impulse.x * bodyA.inverseMass;
|
bodyA.positionPrev.x += impulseX * bodyA.inverseMass;
|
||||||
bodyA.positionPrev.y += impulse.y * bodyA.inverseMass;
|
bodyA.positionPrev.y += impulseY * bodyA.inverseMass;
|
||||||
bodyA.anglePrev += Vector.cross(offsetA, impulse) * bodyA.inverseInertia;
|
bodyA.anglePrev += (offsetAX * impulseY - offsetAY * impulseX) * bodyA.inverseInertia;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(bodyB.isStatic || bodyB.isSleeping)) {
|
if (!(bodyB.isStatic || bodyB.isSleeping)) {
|
||||||
bodyB.positionPrev.x -= impulse.x * bodyB.inverseMass;
|
bodyB.positionPrev.x -= impulseX * bodyB.inverseMass;
|
||||||
bodyB.positionPrev.y -= impulse.y * bodyB.inverseMass;
|
bodyB.positionPrev.y -= impulseY * bodyB.inverseMass;
|
||||||
bodyB.anglePrev -= Vector.cross(offsetB, impulse) * bodyB.inverseInertia;
|
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.
|
* The `Matter.SAT` module contains methods for detecting collisions using the Separating Axis Theorem.
|
||||||
*
|
*
|
||||||
* @class SAT
|
* @class SAT
|
||||||
|
* @deprecated
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// TODO: true circles and curves
|
|
||||||
|
|
||||||
var SAT = {};
|
var SAT = {};
|
||||||
|
|
||||||
module.exports = SAT;
|
module.exports = SAT;
|
||||||
|
|
||||||
var Vertices = require('../geometry/Vertices');
|
var Collision = require('./Collision');
|
||||||
var Vector = require('../geometry/Vector');
|
|
||||||
var Common = require('../core/Common');
|
var Common = require('../core/Common');
|
||||||
|
var deprecated = Common.deprecated;
|
||||||
|
|
||||||
(function() {
|
(function() {
|
||||||
|
|
||||||
|
@ -20,258 +24,16 @@ var Common = require('../core/Common');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Detect collision between two bodies using the Separating Axis Theorem.
|
* Detect collision between two bodies using the Separating Axis Theorem.
|
||||||
|
* @deprecated replaced by Collision.collides
|
||||||
* @method collides
|
* @method collides
|
||||||
* @param {body} bodyA
|
* @param {body} bodyA
|
||||||
* @param {body} bodyB
|
* @param {body} bodyB
|
||||||
* @param {collision} previousCollision
|
|
||||||
* @param {number} [delta=0]
|
|
||||||
* @return {collision} collision
|
* @return {collision} collision
|
||||||
*/
|
*/
|
||||||
SAT.collides = function(bodyA, bodyB, previousCollision, delta) {
|
SAT.collides = function(bodyA, bodyB) {
|
||||||
var overlapAB,
|
return Collision.collides(bodyA, bodyB);
|
||||||
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;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
deprecated(SAT, 'collides', 'SAT.collides ➤ replaced by Collision.collides');
|
||||||
* Find the overlap between two sets of vertices.
|
|
||||||
* @method _overlapAxes
|
|
||||||
* @private
|
|
||||||
* @param {} verticesA
|
|
||||||
* @param {} verticesB
|
|
||||||
* @param {} axes
|
|
||||||
* @return result
|
|
||||||
*/
|
|
||||||
SAT._overlapAxes = function(verticesA, verticesB, axes) {
|
|
||||||
var projectionA = Vector._temp[0],
|
|
||||||
projectionB = Vector._temp[1],
|
|
||||||
result = { overlap: Number.MAX_VALUE },
|
|
||||||
overlap,
|
|
||||||
axis;
|
|
||||||
|
|
||||||
for (var i = 0; i < axes.length; i++) {
|
|
||||||
axis = axes[i];
|
|
||||||
|
|
||||||
SAT._projectToAxis(projectionA, verticesA, axis);
|
|
||||||
SAT._projectToAxis(projectionB, verticesB, axis);
|
|
||||||
|
|
||||||
overlap = Math.min(projectionA.max - projectionB.min, projectionB.max - projectionA.min);
|
|
||||||
|
|
||||||
if (overlap <= 0) {
|
|
||||||
result.overlap = overlap;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (overlap < result.overlap) {
|
|
||||||
result.overlap = overlap;
|
|
||||||
result.axis = axis;
|
|
||||||
result.axisNumber = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Projects vertices on an axis and returns an interval.
|
|
||||||
* @method _projectToAxis
|
|
||||||
* @private
|
|
||||||
* @param {} projection
|
|
||||||
* @param {} vertices
|
|
||||||
* @param {} axis
|
|
||||||
*/
|
|
||||||
SAT._projectToAxis = function(projection, vertices, axis) {
|
|
||||||
var min = Vector.dot(vertices[0], axis),
|
|
||||||
max = min;
|
|
||||||
|
|
||||||
for (var i = 1; i < vertices.length; i += 1) {
|
|
||||||
var dot = Vector.dot(vertices[i], axis);
|
|
||||||
|
|
||||||
if (dot > max) {
|
|
||||||
max = dot;
|
|
||||||
} else if (dot < min) {
|
|
||||||
min = dot;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
projection.min = min;
|
|
||||||
projection.max = max;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Finds supporting vertices given two bodies along a given direction using hill-climbing.
|
|
||||||
* @method _findSupports
|
|
||||||
* @private
|
|
||||||
* @param {} bodyA
|
|
||||||
* @param {} bodyB
|
|
||||||
* @param {} normal
|
|
||||||
* @return [vector]
|
|
||||||
*/
|
|
||||||
SAT._findSupports = function(bodyA, bodyB, normal) {
|
|
||||||
var nearestDistance = Number.MAX_VALUE,
|
|
||||||
vertexToBody = Vector._temp[0],
|
|
||||||
vertices = bodyB.vertices,
|
|
||||||
bodyAPosition = bodyA.position,
|
|
||||||
distance,
|
|
||||||
vertex,
|
|
||||||
vertexA,
|
|
||||||
vertexB;
|
|
||||||
|
|
||||||
// find closest vertex on bodyB
|
|
||||||
for (var i = 0; i < vertices.length; i++) {
|
|
||||||
vertex = vertices[i];
|
|
||||||
vertexToBody.x = vertex.x - bodyAPosition.x;
|
|
||||||
vertexToBody.y = vertex.y - bodyAPosition.y;
|
|
||||||
distance = -Vector.dot(normal, vertexToBody);
|
|
||||||
|
|
||||||
if (distance < nearestDistance) {
|
|
||||||
nearestDistance = distance;
|
|
||||||
vertexA = vertex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// find next closest vertex using the two connected to it
|
|
||||||
var prevIndex = vertexA.index - 1 >= 0 ? vertexA.index - 1 : vertices.length - 1;
|
|
||||||
vertex = vertices[prevIndex];
|
|
||||||
vertexToBody.x = vertex.x - bodyAPosition.x;
|
|
||||||
vertexToBody.y = vertex.y - bodyAPosition.y;
|
|
||||||
nearestDistance = -Vector.dot(normal, vertexToBody);
|
|
||||||
vertexB = vertex;
|
|
||||||
|
|
||||||
var nextIndex = (vertexA.index + 1) % vertices.length;
|
|
||||||
vertex = vertices[nextIndex];
|
|
||||||
vertexToBody.x = vertex.x - bodyAPosition.x;
|
|
||||||
vertexToBody.y = vertex.y - bodyAPosition.y;
|
|
||||||
distance = -Vector.dot(normal, vertexToBody);
|
|
||||||
if (distance < nearestDistance) {
|
|
||||||
vertexB = vertex;
|
|
||||||
}
|
|
||||||
|
|
||||||
return [vertexA, vertexB];
|
|
||||||
};
|
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
|
|
@ -14,6 +14,8 @@ module.exports = Common;
|
||||||
Common._nextId = 0;
|
Common._nextId = 0;
|
||||||
Common._seed = 0;
|
Common._seed = 0;
|
||||||
Common._nowStartTime = +(new Date());
|
Common._nowStartTime = +(new Date());
|
||||||
|
Common._warnedOnce = {};
|
||||||
|
Common._decomp = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extends the object in the first argument using the object in the second argument.
|
* 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).
|
* 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
|
* @method now
|
||||||
* @return {number} the current timestamp
|
* @return {number} the current timestamp in milliseconds
|
||||||
*/
|
*/
|
||||||
Common.now = function() {
|
Common.now = function() {
|
||||||
if (typeof window !== 'undefined' && window.performance) {
|
if (typeof window !== 'undefined' && window.performance) {
|
||||||
|
@ -266,6 +268,10 @@ module.exports = Common;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Date.now) {
|
||||||
|
return Date.now();
|
||||||
|
}
|
||||||
|
|
||||||
return (new Date()) - Common._nowStartTime;
|
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.
|
* Returns the next unique sequential ID.
|
||||||
* @method nextId
|
* @method nextId
|
||||||
|
@ -536,4 +571,42 @@ module.exports = Common;
|
||||||
func
|
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;
|
module.exports = Engine;
|
||||||
|
|
||||||
var World = require('../body/World');
|
|
||||||
var Sleeping = require('./Sleeping');
|
var Sleeping = require('./Sleeping');
|
||||||
var Resolver = require('../collision/Resolver');
|
var Resolver = require('../collision/Resolver');
|
||||||
var Render = require('../render/Render');
|
var Detector = require('../collision/Detector');
|
||||||
var Pairs = require('../collision/Pairs');
|
var Pairs = require('../collision/Pairs');
|
||||||
var Metrics = require('./Metrics');
|
|
||||||
var Grid = require('../collision/Grid');
|
|
||||||
var Events = require('./Events');
|
var Events = require('./Events');
|
||||||
var Composite = require('../body/Composite');
|
var Composite = require('../body/Composite');
|
||||||
var Constraint = require('../constraint/Constraint');
|
var Constraint = require('../constraint/Constraint');
|
||||||
|
@ -35,16 +32,9 @@ var Body = require('../body/Body');
|
||||||
* @param {object} [options]
|
* @param {object} [options]
|
||||||
* @return {engine} engine
|
* @return {engine} engine
|
||||||
*/
|
*/
|
||||||
Engine.create = function(element, options) {
|
Engine.create = function(options) {
|
||||||
// options may be passed as the first (and only) argument
|
|
||||||
options = Common.isElement(element) ? options : element;
|
|
||||||
element = Common.isElement(element) ? element : null;
|
|
||||||
options = options || {};
|
options = options || {};
|
||||||
|
|
||||||
if (element || options.render) {
|
|
||||||
Common.warn('Engine.create: engine.render is deprecated (see docs)');
|
|
||||||
}
|
|
||||||
|
|
||||||
var defaults = {
|
var defaults = {
|
||||||
positionIterations: 6,
|
positionIterations: 6,
|
||||||
velocityIterations: 4,
|
velocityIterations: 4,
|
||||||
|
@ -52,45 +42,30 @@ var Body = require('../body/Body');
|
||||||
enableSleeping: false,
|
enableSleeping: false,
|
||||||
events: [],
|
events: [],
|
||||||
plugin: {},
|
plugin: {},
|
||||||
|
gravity: {
|
||||||
|
x: 0,
|
||||||
|
y: 1,
|
||||||
|
scale: 0.001
|
||||||
|
},
|
||||||
timing: {
|
timing: {
|
||||||
timestamp: 0,
|
timestamp: 0,
|
||||||
timeScale: 1
|
timeScale: 1,
|
||||||
},
|
lastDelta: 0,
|
||||||
broadphase: {
|
lastElapsed: 0
|
||||||
controller: Grid
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var engine = Common.extend(defaults, options);
|
var engine = Common.extend(defaults, options);
|
||||||
|
|
||||||
// @deprecated
|
engine.world = options.world || Composite.create({ label: 'World' });
|
||||||
if (element || engine.render) {
|
engine.pairs = options.pairs || Pairs.create();
|
||||||
var renderDefaults = {
|
engine.detector = options.detector || Detector.create();
|
||||||
element: element,
|
|
||||||
controller: Render
|
|
||||||
};
|
|
||||||
|
|
||||||
engine.render = Common.extend(renderDefaults, engine.render);
|
// for temporary back compatibility only
|
||||||
}
|
engine.grid = { buckets: [] };
|
||||||
|
engine.world.gravity = engine.gravity;
|
||||||
// @deprecated
|
engine.broadphase = engine.grid;
|
||||||
if (engine.render && engine.render.controller) {
|
engine.metrics = {};
|
||||||
engine.render = engine.render.controller.create(engine.render);
|
|
||||||
}
|
|
||||||
|
|
||||||
// @deprecated
|
|
||||||
if (engine.render) {
|
|
||||||
engine.render.engine = engine;
|
|
||||||
}
|
|
||||||
|
|
||||||
engine.world = options.world || World.create(engine.world);
|
|
||||||
engine.pairs = Pairs.create();
|
|
||||||
engine.broadphase = engine.broadphase.controller.create(engine.broadphase);
|
|
||||||
engine.metrics = engine.metrics || { extended: false };
|
|
||||||
|
|
||||||
// @if DEBUG
|
|
||||||
engine.metrics = Metrics.create(engine.metrics);
|
|
||||||
// @endif
|
|
||||||
|
|
||||||
return engine;
|
return engine;
|
||||||
};
|
};
|
||||||
|
@ -104,17 +79,21 @@ var Body = require('../body/Body');
|
||||||
* @param {number} [delta=16.666]
|
* @param {number} [delta=16.666]
|
||||||
*/
|
*/
|
||||||
Engine.update = function(engine, delta) {
|
Engine.update = function(engine, delta) {
|
||||||
|
var startTime = Common.now();
|
||||||
|
|
||||||
var world = engine.world,
|
var world = engine.world,
|
||||||
|
detector = engine.detector,
|
||||||
|
pairs = engine.pairs,
|
||||||
timing = engine.timing,
|
timing = engine.timing,
|
||||||
broadphase = engine.broadphase,
|
timestamp = timing.timestamp,
|
||||||
broadphasePairs,
|
|
||||||
i;
|
i;
|
||||||
|
|
||||||
delta = typeof delta !== 'undefined' ? delta : Common._timeUnit;
|
delta = typeof delta !== 'undefined' ? delta : Common._timeUnit;
|
||||||
delta *= timing.timeScale;
|
delta *= timing.timeScale;
|
||||||
|
|
||||||
// increment timestamp
|
// increment timestamp
|
||||||
timing.timestamp += delta;
|
timing.timestamp += delta * timing.timeScale;
|
||||||
|
timing.lastDelta = delta * timing.timeScale;
|
||||||
|
|
||||||
// create an event object
|
// create an event object
|
||||||
var event = {
|
var event = {
|
||||||
|
@ -124,21 +103,26 @@ var Body = require('../body/Body');
|
||||||
|
|
||||||
Events.trigger(engine, 'beforeUpdate', event);
|
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),
|
var allBodies = Composite.allBodies(world),
|
||||||
allConstraints = Composite.allConstraints(world);
|
allConstraints = Composite.allConstraints(world);
|
||||||
|
|
||||||
// @if DEBUG
|
// update the detector bodies if they have changed
|
||||||
// reset metrics logging
|
if (world.isModified) {
|
||||||
Metrics.reset(engine.metrics);
|
Detector.setBodies(detector, allBodies);
|
||||||
// @endif
|
}
|
||||||
|
|
||||||
// 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)
|
if (engine.enableSleeping)
|
||||||
Sleeping.update(allBodies, delta);
|
Sleeping.update(allBodies, delta);
|
||||||
|
|
||||||
// applies gravity to all bodies
|
// apply gravity to all bodies
|
||||||
Engine._bodiesApplyGravity(allBodies, world.gravity);
|
Engine._bodiesApplyGravity(allBodies, engine.gravity);
|
||||||
|
|
||||||
// update all body position and rotation by integration
|
// update all body position and rotation by integration
|
||||||
if (delta > 0) {
|
if (delta > 0) {
|
||||||
|
@ -152,33 +136,12 @@ var Body = require('../body/Body');
|
||||||
}
|
}
|
||||||
Constraint.postSolveAll(allBodies);
|
Constraint.postSolveAll(allBodies);
|
||||||
|
|
||||||
// broadphase pass: find potential collision pairs
|
// find all collisions
|
||||||
if (broadphase.controller) {
|
detector.pairs = engine.pairs;
|
||||||
// if world is dirty, we must flush the whole grid
|
var collisions = Detector.collisions(detector);
|
||||||
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);
|
|
||||||
|
|
||||||
// update collision pairs
|
// update collision pairs
|
||||||
var pairs = engine.pairs,
|
|
||||||
timestamp = timing.timestamp;
|
|
||||||
Pairs.update(pairs, collisions, timestamp);
|
Pairs.update(pairs, collisions, timestamp);
|
||||||
Pairs.removeOld(pairs, timestamp);
|
|
||||||
|
|
||||||
// wake up bodies involved in collisions
|
// wake up bodies involved in collisions
|
||||||
if (engine.enableSleeping)
|
if (engine.enableSleeping)
|
||||||
|
@ -215,16 +178,14 @@ var Body = require('../body/Body');
|
||||||
if (pairs.collisionEnd.length > 0)
|
if (pairs.collisionEnd.length > 0)
|
||||||
Events.trigger(engine, 'collisionEnd', { pairs: pairs.collisionEnd });
|
Events.trigger(engine, 'collisionEnd', { pairs: pairs.collisionEnd });
|
||||||
|
|
||||||
// @if DEBUG
|
|
||||||
// update metrics log
|
|
||||||
Metrics.update(engine.metrics, engine);
|
|
||||||
// @endif
|
|
||||||
|
|
||||||
// clear force buffers
|
// clear force buffers
|
||||||
Engine._bodiesClearForces(allBodies);
|
Engine._bodiesClearForces(allBodies);
|
||||||
|
|
||||||
Events.trigger(engine, 'afterUpdate', event);
|
Events.trigger(engine, 'afterUpdate', event);
|
||||||
|
|
||||||
|
// log the time elapsed computing this update
|
||||||
|
engine.timing.lastElapsed = Common.now() - startTime;
|
||||||
|
|
||||||
return engine;
|
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
|
* @method clear
|
||||||
* @param {engine} engine
|
* @param {engine} engine
|
||||||
*/
|
*/
|
||||||
Engine.clear = function(engine) {
|
Engine.clear = function(engine) {
|
||||||
var world = engine.world;
|
|
||||||
|
|
||||||
Pairs.clear(engine.pairs);
|
Pairs.clear(engine.pairs);
|
||||||
|
Detector.clear(engine.detector);
|
||||||
var broadphase = engine.broadphase;
|
|
||||||
if (broadphase.controller) {
|
|
||||||
var bodies = Composite.allBodies(world);
|
|
||||||
broadphase.controller.clear(broadphase);
|
|
||||||
broadphase.controller.update(broadphase, bodies, engine, true);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -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
|
* @method run
|
||||||
* @param {engine} engine
|
* @param {engine} engine
|
||||||
*/
|
*/
|
||||||
|
@ -341,58 +295,58 @@ var Body = require('../body/Body');
|
||||||
* Fired just before an update
|
* Fired just before an update
|
||||||
*
|
*
|
||||||
* @event beforeUpdate
|
* @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.timestamp The engine.timing.timestamp of the event
|
||||||
* @param {number} event.delta The delta time in milliseconds value used in the update
|
* @param {number} event.delta The delta time in milliseconds value used in the update
|
||||||
* @param {} event.source The source object of the event
|
* @param {engine} event.source The source object of the event
|
||||||
* @param {} event.name The name of the event
|
* @param {string} event.name The name of the event
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fired after engine update and all collision events
|
* Fired after engine update and all collision events
|
||||||
*
|
*
|
||||||
* @event afterUpdate
|
* @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.timestamp The engine.timing.timestamp of the event
|
||||||
* @param {number} event.delta The delta time in milliseconds value used in the update
|
* @param {number} event.delta The delta time in milliseconds value used in the update
|
||||||
* @param {} event.source The source object of the event
|
* @param {engine} event.source The source object of the event
|
||||||
* @param {} event.name The name 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)
|
* Fired after engine update, provides a list of all pairs that have started to collide in the current tick (if any)
|
||||||
*
|
*
|
||||||
* @event collisionStart
|
* @event collisionStart
|
||||||
* @param {} event An event object
|
* @param {object} event An event object
|
||||||
* @param {} event.pairs List of affected pairs
|
* @param {pair[]} event.pairs List of affected pairs
|
||||||
* @param {number} event.timestamp The engine.timing.timestamp of the event
|
* @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 {number} event.delta The delta time in milliseconds value used in the update
|
||||||
* @param {} event.source The source object of the event
|
* @param {engine} event.source The source object of the event
|
||||||
* @param {} event.name The name 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)
|
* Fired after engine update, provides a list of all pairs that are colliding in the current tick (if any)
|
||||||
*
|
*
|
||||||
* @event collisionActive
|
* @event collisionActive
|
||||||
* @param {} event An event object
|
* @param {object} event An event object
|
||||||
* @param {} event.pairs List of affected pairs
|
* @param {pair[]} event.pairs List of affected pairs
|
||||||
* @param {number} event.timestamp The engine.timing.timestamp of the event
|
* @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 {number} event.delta The delta time in milliseconds value used in the update
|
||||||
* @param {} event.source The source object of the event
|
* @param {engine} event.source The source object of the event
|
||||||
* @param {} event.name The name 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)
|
* Fired after engine update, provides a list of all pairs that have ended collision in the current tick (if any)
|
||||||
*
|
*
|
||||||
* @event collisionEnd
|
* @event collisionEnd
|
||||||
* @param {} event An event object
|
* @param {object} event An event object
|
||||||
* @param {} event.pairs List of affected pairs
|
* @param {pair[]} event.pairs List of affected pairs
|
||||||
* @param {number} event.timestamp The engine.timing.timestamp of the event
|
* @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 {number} event.delta The delta time in milliseconds value used in the update
|
||||||
* @param {} event.source The source object of the event
|
* @param {engine} event.source The source object of the event
|
||||||
* @param {} event.name The name 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`.
|
* A `Number` that represents the total execution time elapsed during the last `Engine.update` in milliseconds.
|
||||||
* One may also develop a custom renderer module based on `Matter.Render` and pass an instance of it to `Engine.create` via `options.render`.
|
* 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`).
|
* This value will also include the total execution time of all event handlers directly or indirectly triggered by the engine update.
|
||||||
* It is also possible to instead pass the _module_ reference via `options.render.controller` and `Engine.create` will instantiate one for you.
|
|
||||||
*
|
*
|
||||||
* @property render
|
* @property timing.lastElapsed
|
||||||
* @type render
|
* @type number
|
||||||
* @deprecated see Demo.js for an example of creating a renderer
|
* @default 0
|
||||||
* @default a Matter.Render instance
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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
|
* @property broadphase
|
||||||
* @type grid
|
* @type grid
|
||||||
* @default a Matter.Grid instance
|
* @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
|
* @property world
|
||||||
* @type world
|
* @type composite
|
||||||
* @default a Matter.World instance
|
* @default a Matter.Composite instance
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -501,4 +479,35 @@ var Body = require('../body/Body');
|
||||||
* @type {}
|
* @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) {
|
Plugin.dependencyParse = function(dependency) {
|
||||||
if (Common.isString(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)) {
|
if (!pattern.test(dependency)) {
|
||||||
Common.warn('Plugin.dependencyParse:', dependency, 'is not a valid dependency string.');
|
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.
|
* @return {object} The version range parsed into its components.
|
||||||
*/
|
*/
|
||||||
Plugin.versionParse = function(range) {
|
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)) {
|
if (!pattern.test(range)) {
|
||||||
Common.warn('Plugin.versionParse:', range, 'is not a valid version or 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').
|
* A game loop utility that updates the engine and renderer by one step (a 'tick').
|
||||||
* Features delta smoothing and fixed or dynamic timing.
|
* Features delta smoothing, time correction and fixed or dynamic timing.
|
||||||
* Triggers `beforeTick`, `tick` and `afterTick` events on the engine.
|
|
||||||
* Consider just `Engine.update(engine, delta)` if you're using your own loop.
|
* Consider just `Engine.update(engine, delta)` if you're using your own loop.
|
||||||
* @method tick
|
* @method tick
|
||||||
* @param {runner} runner
|
* @param {runner} runner
|
||||||
|
@ -111,6 +110,13 @@ var Common = require('./Common');
|
||||||
var timing = engine.timing,
|
var timing = engine.timing,
|
||||||
delta;
|
delta;
|
||||||
|
|
||||||
|
// create an event object
|
||||||
|
var event = {
|
||||||
|
timestamp: timing.timestamp
|
||||||
|
};
|
||||||
|
|
||||||
|
Events.trigger(runner, 'beforeTick', event);
|
||||||
|
|
||||||
if (runner.isFixed) {
|
if (runner.isFixed) {
|
||||||
// fixed timestep
|
// fixed timestep
|
||||||
delta = runner.delta;
|
delta = runner.delta;
|
||||||
|
@ -149,15 +155,6 @@ var Common = require('./Common');
|
||||||
}
|
}
|
||||||
|
|
||||||
Events.trigger(runner, 'tick', event);
|
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
|
// update
|
||||||
Events.trigger(runner, 'beforeUpdate', event);
|
Events.trigger(runner, 'beforeUpdate', event);
|
||||||
|
@ -171,20 +168,7 @@ var Common = require('./Common');
|
||||||
|
|
||||||
Events.trigger(runner, 'afterUpdate', event);
|
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(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
|
* @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
|
* 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).
|
* Utility to create a compound body based on set(s) 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:_ To optionally enable automatic concave vertices decomposition the [poly-decomp](https://github.com/schteppe/poly-decomp.js)
|
||||||
* Note that this process is not guaranteed to support complex sets of vertices (e.g. those with holes may fail).
|
* package must be first installed and provided see `Common.setDecomp`, otherwise the convex hull of each vertex set will be used.
|
||||||
* 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`.
|
* The resulting vertices are reorientated about their centre of mass,
|
||||||
* If the vertices can not be decomposed, the result will fall back to using the convex hull.
|
* and offset such that `body.position` corresponds to this point.
|
||||||
* The options parameter is an object that specifies any `Matter.Body` properties you wish to override the defaults.
|
*
|
||||||
|
* 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.
|
* See the properties section of the `Matter.Body` module for detailed information on what you can pass via the `options` object.
|
||||||
* @method fromVertices
|
* @method fromVertices
|
||||||
* @param {number} x
|
* @param {number} x
|
||||||
* @param {number} y
|
* @param {number} y
|
||||||
* @param [[vector]] vertexSets
|
* @param {array} vertexSets One or more arrays of vertex points e.g. `[[{ x: 0, y: 0 }...], ...]`.
|
||||||
* @param {object} [options]
|
* @param {object} [options] The body options.
|
||||||
* @param {bool} [flagInternal=false]
|
* @param {bool} [flagInternal=false] Optionally marks internal edges with `isInternal`.
|
||||||
* @param {number} [removeCollinear=0.01]
|
* @param {number} [removeCollinear=0.01] Threshold when simplifying vertices along the same edge.
|
||||||
* @param {number} [minimumArea=10]
|
* @param {number} [minimumArea=10] Threshold when removing small parts.
|
||||||
|
* @param {number} [removeDuplicatePoints=0.01] Threshold when simplifying nearby vertices.
|
||||||
* @return {body}
|
* @return {body}
|
||||||
*/
|
*/
|
||||||
Bodies.fromVertices = function(x, y, vertexSets, options, flagInternal, removeCollinear, minimumArea) {
|
Bodies.fromVertices = function(x, y, vertexSets, options, flagInternal, removeCollinear, minimumArea, removeDuplicatePoints) {
|
||||||
var globals = typeof global !== 'undefined' ? global : window,
|
var decomp = Common.getDecomp(),
|
||||||
decomp,
|
canDecomp,
|
||||||
body,
|
body,
|
||||||
parts,
|
parts,
|
||||||
isConvex,
|
isConvex,
|
||||||
|
isConcave,
|
||||||
vertices,
|
vertices,
|
||||||
i,
|
i,
|
||||||
j,
|
j,
|
||||||
|
@ -208,11 +223,8 @@ var Vector = require('../geometry/Vector');
|
||||||
v,
|
v,
|
||||||
z;
|
z;
|
||||||
|
|
||||||
try {
|
// check decomp is as expected
|
||||||
decomp = globals.decomp || require('poly-decomp');
|
canDecomp = Boolean(decomp && decomp.quickDecomp);
|
||||||
} catch (e) {
|
|
||||||
// decomp is undefined
|
|
||||||
}
|
|
||||||
|
|
||||||
options = options || {};
|
options = options || {};
|
||||||
parts = [];
|
parts = [];
|
||||||
|
@ -220,10 +232,7 @@ var Vector = require('../geometry/Vector');
|
||||||
flagInternal = typeof flagInternal !== 'undefined' ? flagInternal : false;
|
flagInternal = typeof flagInternal !== 'undefined' ? flagInternal : false;
|
||||||
removeCollinear = typeof removeCollinear !== 'undefined' ? removeCollinear : 0.01;
|
removeCollinear = typeof removeCollinear !== 'undefined' ? removeCollinear : 0.01;
|
||||||
minimumArea = typeof minimumArea !== 'undefined' ? minimumArea : 10;
|
minimumArea = typeof minimumArea !== 'undefined' ? minimumArea : 10;
|
||||||
|
removeDuplicatePoints = typeof removeDuplicatePoints !== 'undefined' ? removeDuplicatePoints : 0.01;
|
||||||
if (!decomp) {
|
|
||||||
Common.warn('Bodies.fromVertices: poly-decomp.js required. Could not decompose vertices. Fallback to convex hull.');
|
|
||||||
}
|
|
||||||
|
|
||||||
// ensure vertexSets is an array of arrays
|
// ensure vertexSets is an array of arrays
|
||||||
if (!Common.isArray(vertexSets[0])) {
|
if (!Common.isArray(vertexSets[0])) {
|
||||||
|
@ -233,8 +242,15 @@ var Vector = require('../geometry/Vector');
|
||||||
for (v = 0; v < vertexSets.length; v += 1) {
|
for (v = 0; v < vertexSets.length; v += 1) {
|
||||||
vertices = vertexSets[v];
|
vertices = vertexSets[v];
|
||||||
isConvex = Vertices.isConvex(vertices);
|
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) {
|
if (isConvex) {
|
||||||
vertices = Vertices.clockwiseSort(vertices);
|
vertices = Vertices.clockwiseSort(vertices);
|
||||||
} else {
|
} else {
|
||||||
|
@ -256,6 +272,8 @@ var Vector = require('../geometry/Vector');
|
||||||
decomp.makeCCW(concave);
|
decomp.makeCCW(concave);
|
||||||
if (removeCollinear !== false)
|
if (removeCollinear !== false)
|
||||||
decomp.removeCollinearPoints(concave, removeCollinear);
|
decomp.removeCollinearPoints(concave, removeCollinear);
|
||||||
|
if (removeDuplicatePoints !== false && decomp.removeDuplicatePoints)
|
||||||
|
decomp.removeDuplicatePoints(concave, removeDuplicatePoints);
|
||||||
|
|
||||||
// use the quick decomposition algorithm (Bayazit)
|
// use the quick decomposition algorithm (Bayazit)
|
||||||
var decomposed = decomp.quickDecomp(concave);
|
var decomposed = decomp.quickDecomp(concave);
|
||||||
|
@ -327,6 +345,8 @@ var Vector = require('../geometry/Vector');
|
||||||
if (parts.length > 1) {
|
if (parts.length > 1) {
|
||||||
// create the parent body to be returned, that contains generated compound parts
|
// create the parent body to be returned, that contains generated compound parts
|
||||||
body = Body.create(Common.extend({ parts: parts.slice(0) }, options));
|
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 });
|
Body.setPosition(body, { x: x, y: y });
|
||||||
|
|
||||||
return body;
|
return body;
|
||||||
|
|
|
@ -16,6 +16,7 @@ var Constraint = require('../constraint/Constraint');
|
||||||
var Common = require('../core/Common');
|
var Common = require('../core/Common');
|
||||||
var Body = require('../body/Body');
|
var Body = require('../body/Body');
|
||||||
var Bodies = require('./Bodies');
|
var Bodies = require('./Bodies');
|
||||||
|
var deprecated = Common.deprecated;
|
||||||
|
|
||||||
(function() {
|
(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
|
* @method newtonsCradle
|
||||||
* @param {number} xx
|
* @param {number} xx
|
||||||
* @param {number} yy
|
* @param {number} yy
|
||||||
|
@ -227,8 +229,11 @@ var Bodies = require('./Bodies');
|
||||||
return newtonsCradle;
|
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
|
* @method car
|
||||||
* @param {number} xx
|
* @param {number} xx
|
||||||
* @param {number} yy
|
* @param {number} yy
|
||||||
|
@ -294,8 +299,12 @@ var Bodies = require('./Bodies');
|
||||||
return car;
|
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
|
* @method softBody
|
||||||
* @param {number} xx
|
* @param {number} xx
|
||||||
* @param {number} yy
|
* @param {number} yy
|
||||||
|
@ -324,4 +333,5 @@ var Bodies = require('./Bodies');
|
||||||
return softBody;
|
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
|
* @param {number} scalar
|
||||||
*/
|
*/
|
||||||
Vertices.translate = function(vertices, vector, scalar) {
|
Vertices.translate = function(vertices, vector, scalar) {
|
||||||
var i;
|
scalar = typeof scalar !== 'undefined' ? scalar : 1;
|
||||||
if (scalar) {
|
|
||||||
for (i = 0; i < vertices.length; i++) {
|
var verticesLength = vertices.length,
|
||||||
vertices[i].x += vector.x * scalar;
|
translateX = vector.x * scalar,
|
||||||
vertices[i].y += vector.y * scalar;
|
translateY = vector.y * scalar,
|
||||||
}
|
i;
|
||||||
} else {
|
|
||||||
for (i = 0; i < vertices.length; i++) {
|
for (i = 0; i < verticesLength; i++) {
|
||||||
vertices[i].x += vector.x;
|
vertices[i].x += translateX;
|
||||||
vertices[i].y += vector.y;
|
vertices[i].y += translateY;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return vertices;
|
return vertices;
|
||||||
|
@ -197,15 +196,21 @@ var Common = require('../core/Common');
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var cos = Math.cos(angle),
|
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++) {
|
for (i = 0; i < verticesLength; i++) {
|
||||||
var vertice = vertices[i],
|
vertex = vertices[i];
|
||||||
dx = vertice.x - point.x,
|
dx = vertex.x - pointX;
|
||||||
dy = vertice.y - point.y;
|
dy = vertex.y - pointY;
|
||||||
|
vertex.x = pointX + (dx * cos - dy * sin);
|
||||||
vertice.x = point.x + (dx * cos - dy * sin);
|
vertex.y = pointY + (dx * sin + dy * cos);
|
||||||
vertice.y = point.y + (dx * sin + dy * cos);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return vertices;
|
return vertices;
|
||||||
|
@ -219,12 +224,21 @@ var Common = require('../core/Common');
|
||||||
* @return {boolean} True if the vertices contains point, otherwise false
|
* @return {boolean} True if the vertices contains point, otherwise false
|
||||||
*/
|
*/
|
||||||
Vertices.contains = function(vertices, point) {
|
Vertices.contains = function(vertices, point) {
|
||||||
for (var i = 0; i < vertices.length; i++) {
|
var pointX = point.x,
|
||||||
var vertice = vertices[i],
|
pointY = point.y,
|
||||||
nextVertice = vertices[(i + 1) % vertices.length];
|
verticesLength = vertices.length,
|
||||||
if ((point.x - vertice.x) * (nextVertice.y - vertice.y) + (point.y - vertice.y) * (vertice.x - nextVertice.x) > 0) {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vertex = nextVertex;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -1,51 +1,35 @@
|
||||||
var Matter = module.exports = require('../core/Matter');
|
var Matter = module.exports = require('../core/Matter');
|
||||||
|
|
||||||
|
Matter.Axes = require('../geometry/Axes');
|
||||||
|
Matter.Bodies = require('../factory/Bodies');
|
||||||
Matter.Body = require('../body/Body');
|
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.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.Contact = require('../collision/Contact');
|
||||||
Matter.Detector = require('../collision/Detector');
|
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.Engine = require('../core/Engine');
|
||||||
Matter.Events = require('../core/Events');
|
Matter.Events = require('../core/Events');
|
||||||
|
Matter.Grid = require('../collision/Grid');
|
||||||
Matter.Mouse = require('../core/Mouse');
|
Matter.Mouse = require('../core/Mouse');
|
||||||
Matter.Runner = require('../core/Runner');
|
Matter.MouseConstraint = require('../constraint/MouseConstraint');
|
||||||
Matter.Sleeping = require('../core/Sleeping');
|
Matter.Pair = require('../collision/Pair');
|
||||||
|
Matter.Pairs = require('../collision/Pairs');
|
||||||
Matter.Plugin = require('../core/Plugin');
|
Matter.Plugin = require('../core/Plugin');
|
||||||
|
Matter.Query = require('../collision/Query');
|
||||||
// @if DEBUG
|
Matter.Render = require('../render/Render');
|
||||||
Matter.Metrics = require('../core/Metrics');
|
Matter.Resolver = require('../collision/Resolver');
|
||||||
// @endif
|
Matter.Runner = require('../core/Runner');
|
||||||
|
Matter.SAT = require('../collision/SAT');
|
||||||
Matter.Bodies = require('../factory/Bodies');
|
Matter.Sleeping = require('../core/Sleeping');
|
||||||
Matter.Composites = require('../factory/Composites');
|
|
||||||
|
|
||||||
Matter.Axes = require('../geometry/Axes');
|
|
||||||
Matter.Bounds = require('../geometry/Bounds');
|
|
||||||
Matter.Svg = require('../geometry/Svg');
|
Matter.Svg = require('../geometry/Svg');
|
||||||
Matter.Vector = require('../geometry/Vector');
|
Matter.Vector = require('../geometry/Vector');
|
||||||
Matter.Vertices = require('../geometry/Vertices');
|
Matter.Vertices = require('../geometry/Vertices');
|
||||||
|
Matter.World = require('../body/World');
|
||||||
|
|
||||||
Matter.Render = require('../render/Render');
|
// temporary back compatibility
|
||||||
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;
|
|
||||||
Matter.Engine.run = Matter.Runner.run;
|
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 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.
|
* 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 Composite = require('../body/Composite');
|
||||||
var Bounds = require('../geometry/Bounds');
|
var Bounds = require('../geometry/Bounds');
|
||||||
var Events = require('../core/Events');
|
var Events = require('../core/Events');
|
||||||
var Grid = require('../collision/Grid');
|
|
||||||
var Vector = require('../geometry/Vector');
|
var Vector = require('../geometry/Vector');
|
||||||
var Mouse = require('../core/Mouse');
|
var Mouse = require('../core/Mouse');
|
||||||
|
|
||||||
|
@ -32,6 +31,9 @@ var Mouse = require('../core/Mouse');
|
||||||
|| window.webkitCancelAnimationFrame || window.msCancelAnimationFrame;
|
|| 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.
|
* 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.
|
* 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,
|
canvas: null,
|
||||||
mouse: null,
|
mouse: null,
|
||||||
frameRequestId: null,
|
frameRequestId: null,
|
||||||
|
timing: {
|
||||||
|
historySize: 60,
|
||||||
|
delta: 0,
|
||||||
|
deltaHistory: [],
|
||||||
|
lastTime: 0,
|
||||||
|
lastTimestamp: 0,
|
||||||
|
lastElapsed: 0,
|
||||||
|
timestampElapsed: 0,
|
||||||
|
timestampElapsedHistory: [],
|
||||||
|
engineDeltaHistory: [],
|
||||||
|
engineElapsedHistory: [],
|
||||||
|
elapsedHistory: []
|
||||||
|
},
|
||||||
options: {
|
options: {
|
||||||
width: 800,
|
width: 800,
|
||||||
height: 600,
|
height: 600,
|
||||||
|
@ -59,7 +74,8 @@ var Mouse = require('../core/Mouse');
|
||||||
wireframes: true,
|
wireframes: true,
|
||||||
showSleeping: true,
|
showSleeping: true,
|
||||||
showDebug: false,
|
showDebug: false,
|
||||||
showBroadphase: false,
|
showStats: false,
|
||||||
|
showPerformance: false,
|
||||||
showBounds: false,
|
showBounds: false,
|
||||||
showVelocity: false,
|
showVelocity: false,
|
||||||
showCollisions: false,
|
showCollisions: false,
|
||||||
|
@ -68,7 +84,6 @@ var Mouse = require('../core/Mouse');
|
||||||
showPositions: false,
|
showPositions: false,
|
||||||
showAngleIndicator: false,
|
showAngleIndicator: false,
|
||||||
showIds: false,
|
showIds: false,
|
||||||
showShadows: false,
|
|
||||||
showVertexNumbers: false,
|
showVertexNumbers: false,
|
||||||
showConvexHulls: false,
|
showConvexHulls: false,
|
||||||
showInternalEdges: 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) {
|
if (render.options.pixelRatio !== 1) {
|
||||||
Render.setPixelRatio(render, render.options.pixelRatio);
|
Render.setPixelRatio(render, render.options.pixelRatio);
|
||||||
}
|
}
|
||||||
|
@ -121,7 +139,18 @@ var Mouse = require('../core/Mouse');
|
||||||
Render.run = function(render) {
|
Render.run = function(render) {
|
||||||
(function loop(time){
|
(function loop(time){
|
||||||
render.frameRequestId = _requestAnimationFrame(loop);
|
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
|
* @method world
|
||||||
* @param {render} render
|
* @param {render} render
|
||||||
*/
|
*/
|
||||||
Render.world = function(render) {
|
Render.world = function(render, time) {
|
||||||
var engine = render.engine,
|
var startTime = Common.now(),
|
||||||
|
engine = render.engine,
|
||||||
world = engine.world,
|
world = engine.world,
|
||||||
canvas = render.canvas,
|
canvas = render.canvas,
|
||||||
context = render.context,
|
context = render.context,
|
||||||
options = render.options,
|
options = render.options,
|
||||||
allBodies = Composite.allBodies(world),
|
timing = render.timing;
|
||||||
|
|
||||||
|
var allBodies = Composite.allBodies(world),
|
||||||
allConstraints = Composite.allConstraints(world),
|
allConstraints = Composite.allConstraints(world),
|
||||||
background = options.wireframes ? options.wireframeBackground : options.background,
|
background = options.wireframes ? options.wireframeBackground : options.background,
|
||||||
bodies = [],
|
bodies = [],
|
||||||
|
@ -406,84 +438,188 @@ var Mouse = require('../core/Mouse');
|
||||||
|
|
||||||
Render.constraints(constraints, context);
|
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) {
|
if (options.hasBounds) {
|
||||||
// revert view transforms
|
// revert view transforms
|
||||||
Render.endViewTransform(render);
|
Render.endViewTransform(render);
|
||||||
}
|
}
|
||||||
|
|
||||||
Events.trigger(render, 'afterRender', event);
|
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
|
* @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 {render} render
|
||||||
* @param {RenderingContext} context
|
* @param {RenderingContext} context
|
||||||
*/
|
*/
|
||||||
Render.debug = function(render, context) {
|
Render.performance = function(render, context) {
|
||||||
var c = context,
|
var engine = render.engine,
|
||||||
engine = render.engine,
|
timing = render.timing,
|
||||||
world = engine.world,
|
deltaHistory = timing.deltaHistory,
|
||||||
metrics = engine.metrics,
|
elapsedHistory = timing.elapsedHistory,
|
||||||
options = render.options,
|
timestampElapsedHistory = timing.timestampElapsedHistory,
|
||||||
bodies = Composite.allBodies(world),
|
engineDeltaHistory = timing.engineDeltaHistory,
|
||||||
space = " ";
|
engineElapsedHistory = timing.engineElapsedHistory,
|
||||||
|
lastEngineDelta = engine.timing.lastDelta;
|
||||||
|
|
||||||
if (engine.timing.timestamp - (render.debugTimestamp || 0) >= 500) {
|
var deltaMean = _mean(deltaHistory),
|
||||||
var text = "";
|
elapsedMean = _mean(elapsedHistory),
|
||||||
|
engineDeltaMean = _mean(engineDeltaHistory),
|
||||||
|
engineElapsedMean = _mean(engineElapsedHistory),
|
||||||
|
timestampElapsedMean = _mean(timestampElapsedHistory),
|
||||||
|
rateMean = (timestampElapsedMean / deltaMean) || 0,
|
||||||
|
fps = (1000 / deltaMean) || 0;
|
||||||
|
|
||||||
if (metrics.timing) {
|
var graphHeight = 4,
|
||||||
text += "fps: " + Math.round(metrics.timing.fps) + space;
|
gap = 12,
|
||||||
|
width = 60,
|
||||||
|
height = 34,
|
||||||
|
x = 10,
|
||||||
|
y = 69;
|
||||||
|
|
||||||
|
// background
|
||||||
|
context.fillStyle = '#0e0f19';
|
||||||
|
context.fillRect(0, 50, gap * 4 + width * 5 + 22, height);
|
||||||
|
|
||||||
|
// show FPS
|
||||||
|
Render.status(
|
||||||
|
context, x, y, width, graphHeight, deltaHistory.length,
|
||||||
|
Math.round(fps) + ' fps',
|
||||||
|
fps / Render._goodFps,
|
||||||
|
function(i) { return (deltaHistory[i] / deltaMean) - 1; }
|
||||||
|
);
|
||||||
|
|
||||||
|
// show engine delta
|
||||||
|
Render.status(
|
||||||
|
context, x + gap + width, y, width, graphHeight, engineDeltaHistory.length,
|
||||||
|
lastEngineDelta.toFixed(2) + ' dt',
|
||||||
|
Render._goodDelta / lastEngineDelta,
|
||||||
|
function(i) { return (engineDeltaHistory[i] / engineDeltaMean) - 1; }
|
||||||
|
);
|
||||||
|
|
||||||
|
// show engine 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; }
|
||||||
|
);
|
||||||
|
|
||||||
|
// 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; }
|
||||||
|
);
|
||||||
|
|
||||||
|
// 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 DEBUG
|
// indicator
|
||||||
if (metrics.extended) {
|
context.fillStyle = 'hsl(' + Common.clamp(25 + 95 * indicator, 0, 120) + ',100%,60%)';
|
||||||
if (metrics.timing) {
|
context.fillRect(x, y - 7, 4, 4);
|
||||||
text += "delta: " + metrics.timing.delta.toFixed(3) + space;
|
|
||||||
text += "correction: " + metrics.timing.correction.toFixed(3) + space;
|
|
||||||
}
|
|
||||||
|
|
||||||
text += "bodies: " + bodies.length + space;
|
// label
|
||||||
|
context.font = '12px Arial';
|
||||||
if (engine.broadphase.controller === Grid)
|
context.textBaseline = 'middle';
|
||||||
text += "buckets: " + metrics.buckets + space;
|
context.textAlign = 'right';
|
||||||
|
context.fillStyle = '#eee';
|
||||||
text += "\n";
|
context.fillText(label, x + width, y - 5);
|
||||||
|
|
||||||
text += "collisions: " + metrics.collisions + space;
|
|
||||||
text += "pairs: " + engine.pairs.list.length + space;
|
|
||||||
text += "broad: " + metrics.broadEff + space;
|
|
||||||
text += "mid: " + metrics.midEff + space;
|
|
||||||
text += "narrow: " + metrics.narrowEff + space;
|
|
||||||
}
|
|
||||||
// @endif
|
|
||||||
|
|
||||||
render.debugString = text;
|
|
||||||
render.debugTimestamp = engine.timing.timestamp;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (render.debugString) {
|
|
||||||
c.font = "12px Arial";
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -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
|
* Description
|
||||||
* @private
|
* @private
|
||||||
|
@ -1197,45 +1284,6 @@ var Mouse = require('../core/Mouse');
|
||||||
c.stroke();
|
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
|
* Description
|
||||||
* @private
|
* @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
|
* @method _createCanvas
|
||||||
* @private
|
* @private
|
||||||
* @param {} width
|
* @param {} width
|
||||||
|
@ -1455,37 +1552,6 @@ var Mouse = require('../core/Mouse');
|
||||||
* @default null
|
* @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.
|
* 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`).
|
* 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 {}
|
* @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