collide-motion
Version:
collide-motion --------------
179 lines (166 loc) • 3.97 kB
JavaScript
/**
* A HUGE thank you to dynamics.js which inspired these dynamics simulations.
* https://github.com/michaelvillar/dynamics.js
*
* Also licensed under MIT
*/
var extend = require('node.extend');
module.exports = {
Spring: DynamicsSpring,
Gravity: DynamicsGravity
};
function DynamicsSpring(opts) {
var defaults = {
frequency: 15,
friction: 200,
anticipationStrength: 0,
anticipationSize: 0
};
extend(this, defaults);
var maxs = {
frequency: 100,
friction: 1000,
anticipationStrength: 1000,
anticipationSize: 99
};
var mins = {
frequency: 0,
friction: 1,
anticipationStrength: 0,
anticipationSize: 0
};
extend(this, opts);
}
DynamicsSpring.prototype = {
at: function(t) {
var A, At, a, angle, b, decal, frequency, friction, frictionT, s, v, y0, yS,
_this = this;
frequency = Math.max(1, this.frequency);
friction = Math.pow(20, this.friction / 100);
s = this.anticipationSize / 100;
decal = Math.max(0, s);
frictionT = (t / (1 - s)) - (s / (1 - s));
if (t < s) {
A = function(t) {
var M, a, b, x0, x1;
M = 0.8;
x0 = s / (1 - s);
x1 = 0;
b = (x0 - (M * x1)) / (x0 - x1);
a = (M - b) / x0;
return (a * t * _this.anticipationStrength / 100) + b;
};
yS = (s / (1 - s)) - (s / (1 - s));
y0 = (0 / (1 - s)) - (s / (1 - s));
b = Math.acos(1 / A(yS));
a = (Math.acos(1 / A(y0)) - b) / (frequency * (-s));
} else {
A = function(t) {
return Math.pow(friction / 10, -t) * (1 - t);
};
b = 0;
a = 1;
}
At = A(frictionT);
angle = frequency * (t - s) * a + b;
v = 1 - (At * Math.cos(angle));
//return [t, v, At, frictionT, angle];
return v;
}
};
function DynamicsGravity(opts) {
this.options = {
bounce: 40,
gravity: 1000,
initialForce: false
};
extend(this.options, opts);
this.curves = [];
this.init();
}
DynamicsGravity.prototype = {
length: function() {
var L, b, bounce, curve, gravity;
bounce = Math.min(this.options.bounce / 100, 80);
gravity = this.options.gravity / 100;
b = Math.sqrt(2 / gravity);
curve = {
a: -b,
b: b,
H: 1
};
if (this.options.initialForce) {
curve.a = 0;
curve.b = curve.b * 2;
}
while (curve.H > 0.001) {
L = curve.b - curve.a;
curve = {
a: curve.b,
b: curve.b + L * bounce,
H: curve.H * bounce * bounce
};
}
return curve.b;
},
init: function() {
var L, b, bounce, curve, gravity, _results;
L = this.length();
gravity = (this.options.gravity / 100) * L * L;
bounce = Math.min(this.options.bounce / 100, 80);
b = Math.sqrt(2 / gravity);
this.curves = [];
curve = {
a: -b,
b: b,
H: 1
};
if (this.options.initialForce) {
curve.a = 0;
curve.b = curve.b * 2;
}
this.curves.push(curve);
_results = [];
while (curve.b < 1 && curve.H > 0.001) {
L = curve.b - curve.a;
curve = {
a: curve.b,
b: curve.b + L * bounce,
H: curve.H * bounce * bounce
};
_results.push(this.curves.push(curve));
}
return _results;
},
curve: function(a, b, H, t){
var L, c, t2;
L = b - a;
t2 = (2 / L) * t - 1 - (a * 2 / L);
c = t2 * t2 * H - H + 1;
if (this.initialForce) {
c = 1 - c;
}
return c;
},
at: function(t) {
var bounce, curve, gravity, i, v;
bounce = this.options.bounce / 100;
gravity = this.options.gravity;
i = 0;
curve = this.curves[i];
while (!(t >= curve.a && t <= curve.b)) {
i += 1;
curve = this.curves[i];
if (!curve) {
break;
}
}
if (!curve) {
v = this.options.initialForce ? 0 : 1;
} else {
v = this.curve(curve.a, curve.b, curve.H, t);
}
//return [t, v];
return v;
}
};