├── .gitignore
├── .npmignore
├── demo
├── dev.html
├── line.html
├── triangulate.html
├── draw-triangles.js
├── bounce.js
├── triangulate.js
└── line.js
├── 2d.js
├── 3d.js
├── LICENSE.md
├── lib
├── box-collision.js
└── build.js
├── package.json
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | bower_components
2 | node_modules
3 | *.log
4 | .DS_Store
5 | bundle.js
6 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | bower_components
2 | node_modules
3 | *.log
4 | .DS_Store
5 | bundle.js
6 | test
7 | test.js
8 | demo/
--------------------------------------------------------------------------------
/demo/dev.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/demo/line.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/demo/triangulate.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/2d.js:
--------------------------------------------------------------------------------
1 | var vec2 = {
2 | create: require('gl-vec2/create'),
3 | add: require('gl-vec2/add'),
4 | multiply: require('gl-vec2/multiply'),
5 | sub: require('gl-vec2/subtract'),
6 | scale: require('gl-vec2/scale'),
7 | copy: require('gl-vec2/copy'),
8 | sqrLen: require('gl-vec2/squaredLength'),
9 | fromValues: require('gl-vec2/fromValues'),
10 | }
11 | module.exports = require('./lib/build')(vec2)
--------------------------------------------------------------------------------
/3d.js:
--------------------------------------------------------------------------------
1 | var vec3 = {
2 | create: require('gl-vec3/create'),
3 | add: require('gl-vec3/add'),
4 | multiply: require('gl-vec3/multiply'),
5 | sub: require('gl-vec3/subtract'),
6 | scale: require('gl-vec3/scale'),
7 | copy: require('gl-vec3/copy'),
8 | sqrLen: require('gl-vec3/squaredLength'),
9 | fromValues: require('gl-vec3/fromValues'),
10 | }
11 | module.exports = require('./lib/build')(vec3)
--------------------------------------------------------------------------------
/demo/draw-triangles.js:
--------------------------------------------------------------------------------
1 | var vec2 = require('gl-matrix').vec2
2 |
3 | module.exports = function drawTriangles(ctx, positions, cells, start, end) {
4 | var v = positions
5 | start = (start|0)
6 | end = typeof end === 'number' ? (end|0) : cells.length
7 |
8 | for (; start < end && start < cells.length; start++) {
9 | var f = cells[start]
10 |
11 | var v0 = v[f[0]],
12 | v1 = v[f[1]],
13 | v2 = v[f[2]]
14 |
15 | ctx.moveTo(v0[0], v0[1])
16 | ctx.lineTo(v1[0], v1[1])
17 | ctx.lineTo(v2[0], v2[1])
18 | ctx.lineTo(v0[0], v0[1])
19 | }
20 | }
--------------------------------------------------------------------------------
/demo/bounce.js:
--------------------------------------------------------------------------------
1 | require('canvas-testbed')(render, start)
2 |
3 | var Point = require('verlet-point')
4 | var World = require('../')
5 |
6 | var world,
7 | point,
8 | radius = 25
9 |
10 | function render(ctx, width, height, dt) {
11 | ctx.clearRect(0, 0, width, height)
12 |
13 | world.max = [width, height]
14 | world.integratePoint(point, dt/1000)
15 |
16 | ctx.beginPath()
17 | ctx.arc(point.position[0], point.position[1], radius, 0, Math.PI*2, false)
18 | ctx.fill()
19 | }
20 |
21 | function start(ctx, width, height) {
22 | world = World({
23 | gravity: [500, 500],
24 | bounce: 0.5 //collision friction
25 | })
26 |
27 | point = Point({
28 | position: [width/2, height/2],
29 | radius: radius
30 | })
31 | }
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 | Copyright (c) 2014 Matt DesLauriers
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in all
12 | copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
20 | OR OTHER DEALINGS IN THE SOFTWARE.
21 |
22 |
--------------------------------------------------------------------------------
/lib/box-collision.js:
--------------------------------------------------------------------------------
1 | module.exports = function(vec) {
2 | var negInfinity = vec.fromValues(-Infinity, -Infinity, -Infinity)
3 | var posInfinity = vec.fromValues(Infinity, Infinity, Infinity)
4 | var ones = vec.fromValues(1, 1, 1)
5 | var reflect = vec.create()
6 | var EPSILON = 0.000001
7 |
8 | return function collider(p, velocity, min, max, friction) {
9 | if (!min && !max)
10 | return
11 |
12 | //reset reflection
13 | vec.copy(reflect, ones)
14 |
15 | min = min || negInfinity
16 | max = max || posInfinity
17 |
18 | var i = 0,
19 | n = p.position.length,
20 | hit = false,
21 | radius = p.radius || 0
22 |
23 | //bounce and clamp
24 | for (i=0; i max[i]) {
32 | reflect[i] = -1
33 | p.position[i] = max[i]-radius
34 | hit = true
35 | }
36 |
37 | //no bounce
38 | var len2 = vec.sqrLen(velocity)
39 | if (!hit || len2 <= EPSILON)
40 | return
41 |
42 | var m = Math.sqrt(len2)
43 | if (m !== 0)
44 | vec.scale(velocity, velocity, 1/m)
45 |
46 | //scale bounce by friction
47 | vec.scale(reflect, reflect, m * friction)
48 |
49 | //bounce back
50 | vec.multiply(velocity, velocity, reflect)
51 | }
52 | }
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "verlet-system",
3 | "version": "1.0.15",
4 | "description": "2D and 3D verlet integration",
5 | "main": "2d.js",
6 | "license": "MIT",
7 | "author": {
8 | "name": "Matt DesLauriers",
9 | "email": "dave.des@gmail.com",
10 | "url": "https://github.com/mattdesl"
11 | },
12 | "dependencies": {
13 | "as-number": "^1.0.0",
14 | "clamp": "^1.0.1",
15 | "gl-vec2": "^1.0.0",
16 | "gl-vec3": "^1.0.2"
17 | },
18 | "devDependencies": {
19 | "add-event-listener": "0.0.1",
20 | "array-range": "^1.0.1",
21 | "canvas-testbed": "^1.0.2",
22 | "color-style": "^1.0.0",
23 | "delaunay-triangulate": "^1.1.6",
24 | "lerp": "^1.0.0",
25 | "lerp-array": "^1.0.2",
26 | "randf": "^1.0.0",
27 | "smoothstep": "^1.0.1",
28 | "tape": "^3.0.3",
29 | "touch-position": "^1.0.2",
30 | "verlet-constraint": "^1.0.3",
31 | "verlet-point": "^1.2.1",
32 | "xtend": "^4.0.0"
33 | },
34 | "scripts": {
35 | "test": "node test.js",
36 | "line": "beefy --open --index=./demo/dev.html ./demo/line.js",
37 | "triangulate": "beefy --open --index=./demo/dev.html ./demo/triangulate.js",
38 | "build-triangulate": "mkdir -p demo/static && browserify demo/triangulate.js | uglifyjs -cm > demo/static/triangulate.js",
39 | "build-line": "mkdir -p demo/static && browserify demo/line.js | uglifyjs -cm > demo/static/line.js"
40 | },
41 | "keywords": [
42 | "verlet",
43 | "physics",
44 | "integrate",
45 | "integration"
46 | ],
47 | "repository": {
48 | "type": "git",
49 | "url": "git://github.com/mattdesl/verlet-system.git"
50 | },
51 | "homepage": "https://github.com/mattdesl/verlet-system",
52 | "bugs": {
53 | "url": "https://github.com/mattdesl/verlet-system/issues"
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/lib/build.js:
--------------------------------------------------------------------------------
1 | var number = require('as-number')
2 | var clamp = require('clamp')
3 | var createCollider = require('./box-collision')
4 |
5 | module.exports = function create(vec) {
6 |
7 | var collide = createCollider(vec)
8 |
9 | var velocity = vec.create()
10 | var tmp = vec.create()
11 | var zero = vec.create()
12 |
13 | function VerletSystem(opt) {
14 | if (!(this instanceof VerletSystem))
15 | return new VerletSystem(opt)
16 |
17 | opt = opt||{}
18 |
19 | this.gravity = opt.gravity || vec.create()
20 | this.friction = number(opt.friction, 0.98)
21 | this.min = opt.min
22 | this.max = opt.max
23 | this.bounce = number(opt.bounce, 1)
24 | }
25 |
26 | VerletSystem.prototype.collision = function(p, velocity) {
27 | collide(p, velocity, this.min, this.max, this.bounce)
28 | }
29 |
30 | VerletSystem.prototype.integratePoint = function(point, delta) {
31 | var mass = typeof point.mass === 'number' ? point.mass : 1
32 |
33 | //if mass is zero, assume body is static / unmovable
34 | if (mass === 0) {
35 | this.collision(point, zero)
36 | vec.copy(point.acceleration, zero)
37 | return
38 | }
39 |
40 | vec.add(point.acceleration, point.acceleration, this.gravity)
41 | vec.scale(point.acceleration, point.acceleration, mass)
42 |
43 | //difference in positions
44 | vec.sub(velocity, point.position, point.previous)
45 |
46 | //dampen velocity
47 | vec.scale(velocity, velocity, this.friction)
48 |
49 | //handle custom collisions in 2D or 3D space
50 | this.collision(point, velocity)
51 |
52 | //set last position
53 | vec.copy(point.previous, point.position)
54 | var tSqr = delta * delta
55 |
56 | //integrate
57 | vec.scale(tmp, point.acceleration, 0.5 * tSqr)
58 | vec.add(point.position, point.position, velocity)
59 | vec.add(point.position, point.position, tmp)
60 |
61 | //reset acceleration
62 | vec.copy(point.acceleration, zero)
63 | }
64 |
65 | VerletSystem.prototype.integrate = function(points, delta) {
66 | for (var i=0; i