-
Notifications
You must be signed in to change notification settings - Fork 1
/
redbox_physics.elm
95 lines (77 loc) · 3.28 KB
/
redbox_physics.elm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
module RedBoxPhysics where
import Anima exposing (..)
import Graphics.Element as El
import Graphics.Collage as Co
import Graphics.Input as In
import Touch
import Color
import Window
import Signal
import Debug exposing (..)
import Time
import Automaton as Auto exposing ((>>>))
import Focus exposing ((=>))
import Physics
import Space exposing (..)
{- A simple application that shows a red box that can be in one of two
positions within the window. Clicking within the window causes the
box to jump to the other position using a springy animation.
Note: This is nearly exactly the same as the redbox.elm example.
The only difference is that the animator is defined using physics
instead of filters to get a similar effect. The code for all the
other aspects is exactly the same as the redbox.elm example. -}
{- Our only input is a click within the box to switch its position. -}
type Input = Quiet | Click
{- Our only model state is a boolean - indicating whether the box
is on the left hand side or the right hand side. -}
type alias Model = {boxIsToTheLeft : Bool}
{- Given the position indication, the director decides a color for the box
and its actual stable position within the window. -}
type alias Direction = {color : Color.Color, x : Float}
{- The view state is structurally the same as the direction, except that the
meaning of the "x" field is "the position of the box right now" as opposed to
"the stable position of the box" as indicated by the direction. -}
type alias ViewState = Direction
clicks = Signal.mailbox Quiet
input = clicks.signal
initial =
{ model = { boxIsToTheLeft = False }
, direction = { color = Color.blue, x = 256.0 }
, viewstate = { color = Color.blue, x = 256.0 }
, view = El.show "initializing..."
}
app : OpinionatedApp Input Model Direction ViewState El.Element
app = {
{- The modeller responds to the input by flipping the position
of the box from left to right or vice versa. -}
modeller = \input model ->
case input of
Click -> { model | boxIsToTheLeft = not model.boxIsToTheLeft }
_ -> model
{- Based on the model, the director decides the stable position
of the box within the window, taking into account the window
environment. -}
, director = \(input, model) dir ->
let dx = 0.25 * toFloat dir.env.width
data = dir.data
in
{dir | data = { data | x = if model.boxIsToTheLeft then -dx else dx } }
{- The animator specifies how to achieve the position indicated
by the director. In this case, the indicated stable position is
to be reached using a springy animation. -}
, animator =
let box = Physics.particle f1d 1.0 initial.direction.x f1d.zero
in Physics.bind f1d box (data_ => x_) (\dir -> [Physics.Spring dir.data.x 200.0 10.0])
{- The viewer takes the position indicated by the animator and renders
the box at that position. -}
, viewer = \(model, vs) ->
Co.collage vs.env.width vs.env.height [
Co.rect 100.0 100.0
|> Co.filled vs.data.color
|> Co.moveX vs.data.x
]
|> In.clickable (Signal.message clicks.address Click)
, initial =
initial
}
main = let (app', _) = Anima.runOpinionatedApp app input in app'