Created
January 12, 2013 23:01
-
-
Save pawel-dubiel/4520928 to your computer and use it in GitHub Desktop.
Fixed time step + rk4 integration
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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