Skip to content

Instantly share code, notes, and snippets.

@pawel-dubiel
Created January 12, 2013 23:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pawel-dubiel/4520928 to your computer and use it in GitHub Desktop.
Save pawel-dubiel/4520928 to your computer and use it in GitHub Desktop.
Fixed time step + rk4 integration
// from http://mndlss.com/2011/05/rk4-in-javascript/
/** EXAMPLE SETUP
**************************************************/
var ball = document.getElementById("ball")
, container = document.getElementById("cont")
, halfWidth = container.clientWidth / 2
, halfHeight = container.clientHeight / 2
, mouseUp = true
;
container.style.background = "rgb(185,195,159)";
var render = function(state) {
ball.style.left = Math.floor(halfWidth + state.x) + "px";
};
/** STATE
**************************************************/
var State = function(state) {
this.setXV(state ? state.x : 0, state ? state.v : 0);
};
State.prototype.setXV = function(x, v) {
this.x = x || 0;
this.v = v || 0;
};
/** DERIVATIVE
**************************************************/
var Derivative = function() {
this.dx = 0;
this.dv = 0;
};
/** MAIN
**************************************************/
var Main = function() {
var getTimeInSeconds = function() {
return (new Date).getTime() / 1000;
};
var t = 0.0
, dt = 0.01
, currentTime = 0.0
, accumulator = 0.0
, previous = new State()
, current = new State()
, state = null
;
this.setXV = function(x, v) {
current.setXV(x, v);
};
function acceleration(state, t) {
var k = 10
, b = 1
;
return -k * state.x - b * state.v;
}
function derive(state, t) {
var output = new Derivative();
output.dx = state.v;
output.dv = acceleration(state, t);
return output;
}
function evaluate(initial, t, dt, derivative) {
var state = new State();
state.x = initial.x + derivative.dx * dt;
state.v = initial.v + derivative.dv * dt;
return derive(state, t + dt);
}
function integrate(state,t, dt) {
var a = derive(state, t)
, b = evaluate(state, t, dt * 0.5, a)
, c = evaluate(state, t, dt * 0.5, b)
, d = evaluate(state, t, dt, c)
, dxdt = 1.0 / 6.0 * (a.dx + 2.0 * (b.dx + c.dx) + d.dx)
, dvdt = 1.0 / 6.0 * (a.dv + 2.0 * (b.dv + c.dv) + d.dv)
;
state.x += dxdt * dt;
state.v += dvdt * dt;
}
function interpolate(previous, current, alpha)
{
var state = new State();
state.x = current.x * alpha + previous.x * (1 - alpha);
state.v = current.v * alpha + previous.v * (1 - alpha);
return state;
}
// shim layer with setTimeout fallback
window.requestAnimFrame = window.requestAnimationFrame
|| window.webkitRequestAnimationFrame
|| window.mozRequestAnimationFrame
|| window.oRequestAnimationFrame
|| window.msRequestAnimationFrame
|| function (callback) { window.setTimeout(callback, 1000 / 60); };
function loop() {
if (mouseUp) {
var newTime = getTimeInSeconds()
, deltaTime = newTime - currentTime
, maxDeltaTime = 0.25
;
currentTime = newTime;
if (deltaTime > maxDeltaTime) {
// note: max frame time to avoid spiral of death
deltaTime = maxDeltaTime;
}
accumulator += deltaTime;
while(accumulator >= dt) {
previous = new State(current);
integrate(current, t, dt);
t += dt;
accumulator -= dt;
}
var alpha = accumulator / dt;
current = interpolate(previous, current, alpha);
}
render(current);
}
(function animLoop() { requestAnimFrame(animLoop); loop(); })();
};
var main = new Main();
/** EXAMPLE SETUP
**************************************************/
var mouseDownEvent = window.Touch ? "touchstart" : "mousedown"
, mouseUpEvent = window.Touch ? "touchend" : "mouseup"
, mouseMoveEvent = window.Touch ? "touchmove" : "mousemove"
;
var transformMouseEvent = function(e) {
return e.changedTouches ? e.changedTouches[0] : e;
};
var setXV = function(e) {
main.setXV(e.offsetX - halfWidth, 0);
};
container.addEventListener(mouseDownEvent, function(e) {
e.preventDefault();
mouseUp = false;
e = transformMouseEvent(e);
setXV(e);
}, false);
container.addEventListener(mouseUpEvent, function(e) {
e.preventDefault();
mouseUp = true;
}, false);
container.addEventListener(mouseMoveEvent, function(e) {
e.preventDefault();
if (mouseUp) { return; }
e = transformMouseEvent(e);
setXV(e);
}, false);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment