Skip to content

Instantly share code, notes, and snippets.

@dobesv
Last active August 29, 2015 14:19
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 dobesv/1166b90d697b57bfd861 to your computer and use it in GitHub Desktop.
Save dobesv/1166b90d697b57bfd861 to your computer and use it in GitHub Desktop.
Bouncing ball comparisons
import Color exposing (..)
import Graphics.Collage exposing (..)
import Graphics.Element exposing (..)
import Signal exposing (..)
import Time
import Mouse
gravity = 40.0
initialState = {
velocity = 0.0,
height = 150.0
}
inputSignal =
(\ dt clicked -> {dt = dt*0.001, clicked = clicked}) <~ (Time.fps 10.0) ~ Mouse.isDown
applyBounce dt state = if state.height <= 0.0 then {
height = 0,
velocity = dt*state.height - state.velocity
} else state
applyVelocity dt state = {
velocity = state.velocity - dt*gravity,
height = state.height + (dt*state.velocity)
}
stepState {dt,clicked} oldState =
if clicked then initialState else applyBounce dt (applyVelocity dt oldState)
stateSignal = Signal.foldp stepState initialState inputSignal
renderState {height} = collage 400 400 [ move (0,height-180) (filled ballColor (circle 10))]
renderStateWithText input state = flow down [
show input,
show state,
renderState state
]
main = renderStateWithText <~ inputSignal ~ stateSignal
ballColor : Color
ballColor =
rgba 256 111 111 1
<pre id="debug">
{ ... }
</pre>
<canvas id="canvas" width="400" height="400">
</canvas>
var gravity = 10.0;
var currentTimeFloatSecs = function() { return (new Date()).getTime() * 0.001; };
var startTime = currentTimeFloatSecs()
var initialState = {
"height" : 100,
"velocity": 0,
"time" : startTime
};
var state = {
"height" : 100,
"velocity": 0,
"time" : startTime
};
window.state = state;
var resetState = function() {
state.height = initialState.height;
state.velocity = initialState.velocity;
};
var updateState = function() {
var now = currentTimeFloatSecs();
var dt = state.time - now;
state.time = now;
state.height += (dt*state.velocity);
state.velocity -= (dt*gravity);
if(state.height <= 0) {
state.velocity = dt*state.height - state.velocity;
state.height = 0;
}
};
var draw = function() {
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
ctx.clearRect(0,0,300,300);
ctx.fillStyle = "#FF5555";
ctx.beginPath();
ctx.arc(75, 250-state.height, 10, 0, 2*Math.PI);
ctx.closePath();
ctx.fill();
};
var showStateAsText = function() {
document.getElementById("debug").innerText = JSON.stringify(state);
};
var runFrame = function() {
updateState();
showStateAsText();
draw();
window.requestAnimationFrame(runFrame);
};
runFrame();
document.getElementById("canvas").addEventListener("click", resetState);
(require frtime/animation)
(define-struct state (height velocity t))
(define-struct inputs (t clicked))
(define gravity 10.0)
(define frac-seconds (* 0.001 milliseconds)) ; Signal of seconds, but updated (much) more frequently
(define start-time (value-now frac-seconds))
(define initial-state (make-state 100 0 start-time))
(define fps 10) ; Simulation frames per second
(define s-per-frame (/ fps)) ; Seconds per simulation frame
(define frames-e (map-e (lambda (x) (value-now frac-seconds)) (changes (floor (* fps frac-seconds)))))
(define clicked (hold left-clicks))
; Apply bounce to a state input
(define (apply-bounce dt state)
(let* ([height (state-height state)]
[velocity (state-velocity state)]
[t (state-t state)])
(if (<= height 0.0)
(make-state 0.0 (- (* dt height) velocity) t)
state)))
; Apply velocity to the state
(define (apply-velocity dt state)
(let* ([height (state-height state)]
[velocity (state-velocity state)]
[t (state-t state)])
(make-state (+ height (* dt velocity)) (- velocity (* dt gravity)) t)))
; Apply a new timestamp to the state
(define (update-time new-time state)
(let* ([height (state-height state)]
[velocity (state-velocity state)]
[t (state-t state)])
(make-state height velocity new-time)))
; Step the state ahead one frame; or reset on click
(define (step-state input old-state)
(let* ([t (inputs-t input)]
[dt (- t (state-t old-state))])
(if (inputs-clicked input)
initial-state
(apply-bounce dt (apply-velocity dt (update-time t old-state))))))
; Define the input event stream - either we are looking for new frames or clicks
(define inputs-e
(map-e (lambda (clicked) (make-inputs (value-now frac-seconds) clicked))
(merge-e
(map-e (lambda (e) #f) frames-e)
(map-e (lambda (e) #t) left-clicks)
)))
(define frame-state
(collect-b inputs-e initial-state step-state)
)
(define height (state-height frame-state))
(define velocity (state-velocity frame-state))
(define ball-posn (make-posn 75 (- 300 height)))
(display-shapes
(list
(make-circle ball-posn 10 "blue")))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment