on master help sign in
Get Pong back to working with 0.5.0.2.
abe4d52evancz
Examples/elm-js/Pong/Pong.elm+69−33
@@ -57,9 +57,29 @@ module Pong where
57
57
58import JavaScript
58import JavaScript
59import Keyboard.Raw
59import Keyboard.Raw
60+import Window as Win
60
61
61
62
62−time = lift (\t -> t / 1000) (Time.fps 60)
63+------------------------------------------------------------------------
64+------ Extracting timesteps from JavaScript ------
65+------------------------------------------------------------------------
66+
67+-- Export our desired FPS to JavaScript. We just want a steady 30 frames
68+-- per second for this game.
69+
70+desiredFPS = constant (castIntToJSNumber 30)
71+
72+foreign export jsevent "desiredFPS"
73+ desiredFPS :: Signal JSNumber
74+
75+
76+-- Import the current time from JavaScript. Events will come in roughly
77+-- 30 times per second.
78+
79+foreign import jsevent "trigger" (castIntToJSNumber 0)
80+ jsTime :: Signal JSNumber
81+
82+time = lift castJSNumberToFloat jsTime
63
83
64
84
65-- Determine the time that has elapsed since the last event. This is
85-- Determine the time that has elapsed since the last event. This is
@@ -97,11 +117,11 @@ defaultKeyInput = KeyInput False Neutral Neutral
97
117
98updateDirection upKey downKey key direction =
118updateDirection upKey downKey key direction =
99 case direction of
119 case direction of
100− Up -> if key == downKey then Neutral else Up
120+ { Up -> if key == downKey then Neutral else Up
101− Down -> if key == upKey then Neutral else Down
121+ ; Down -> if key == upKey then Neutral else Down
102− Neutral -> if key == upKey then Up else
122+ ; Neutral -> if key == upKey then Up else
103 if key == downKey then Down else Neutral
123 if key == downKey then Down else Neutral
104−
124+ }
105
125
106updateDirection1 = updateDirection 87 83 -- 'w' for up and 's' for down
126updateDirection1 = updateDirection 87 83 -- 'w' for up and 's' for down
107updateDirection2 = updateDirection 38 40 -- 'UP' for up and 'DOWN' for down
127updateDirection2 = updateDirection 38 40 -- 'UP' for up and 'DOWN' for down
@@ -196,9 +216,10 @@ defaultGame = GameState BetweenRounds
196
216
197stepPaddle delta dir (Paddle y) =
217stepPaddle delta dir (Paddle y) =
198 case dir of
218 case dir of
199− Up -> Paddle $ clamp 20 (gameHeight-20) (y - 200 * delta)
219+ { Up -> Paddle $ clamp 20 (gameHeight-20) (y - 200 * delta)
200− Down -> Paddle $ clamp 20 (gameHeight-20) (y + 200 * delta)
220+ ; Down -> Paddle $ clamp 20 (gameHeight-20) (y + 200 * delta)
201− Neutral -> Paddle y
221+ ; Neutral -> Paddle y
222+ }
202
223
203
224
204-- We must also step the ball forward. This is more complicated due to
225-- We must also step the ball forward. This is more complicated due to
@@ -220,13 +241,14 @@ stepVelocity velocity lowerCollision upperCollision =
220 if upperCollision then makeNegative velocity else velocity
241 if upperCollision then makeNegative velocity else velocity
221
242
222stepBall delta (Ball (x,y) (vx,vy)) (Paddle y1) (Paddle y2) =
243stepBall delta (Ball (x,y) (vx,vy)) (Paddle y1) (Paddle y2) =
223− let hitPaddle1 = within 20 y1 y && within 8 25 x
244+ let { hitPaddle1 = within 20 y1 y && within 8 25 x
224− hitPaddle2 = within 20 y2 y && within 8 (gameWidth - 25) x
245+ ; hitPaddle2 = within 20 y2 y && within 8 (gameWidth - 25) x
225− vx' = stepVelocity vx hitPaddle1 hitPaddle2
246+ ; vx' = stepVelocity vx hitPaddle1 hitPaddle2
226− vy' = stepVelocity vy (y < 7) (y > gameHeight - 7)
247+ ; vy' = stepVelocity vy (y < 7) (y > gameHeight - 7)
227− scored = x > gameWidth || x < 0
248+ ; scored = x > gameWidth || x < 0
228− x' = if scored then halfWidth else x + vx' * delta
249+ ; x' = if scored then halfWidth else x + vx' * delta
229− y' = if scored then halfHeight else y + vy' * delta
250+ ; y' = if scored then halfHeight else y + vy' * delta
251+ }
230 in ( Ball (x',y') (vx',vy')
252 in ( Ball (x',y') (vx',vy')
231 , if x > gameWidth then 1 else 0
253 , if x > gameWidth then 1 else 0
232 , if x < 0 then 1 else 0 )
254 , if x < 0 then 1 else 0 )
@@ -237,16 +259,15 @@ stepBall delta (Ball (x,y) (vx,vy)) (Paddle y1) (Paddle y2) =
237
259
238stepGame (Input delta (KeyInput space dir1 dir2))
260stepGame (Input delta (KeyInput space dir1 dir2))
239 (GameState state (Score s1 s2) ball paddle1 paddle2) =
261 (GameState state (Score s1 s2) ball paddle1 paddle2) =
240− let (ball',s1',s2') = if state == Play then stepBall delta ball paddle1 paddle2
262+ let { (ball',s1',s2') = if state == Play then stepBall delta ball paddle1 paddle2
241− else (ball, 0, 0)
263+ else (ball, 0, 0)
242− state' = case state of
243− Play -> if s1' /= s2' then BetweenRounds else state
264+ ; state' = case state of { Play -> if s1' /= s2' then BetweenRounds else state
244− BetweenRounds -> if space then Play else state
265+ ; BetweenRounds -> if space then Play else state }
245− in GameState state'
266+ } in GameState state'
246− (Score (s1+s1') (s2+s2'))
267+ (Score (s1+s1') (s2+s2'))
247− ball'
268+ ball'
248− (stepPaddle delta dir1 paddle1)
269+ (stepPaddle delta dir1 paddle1)
249− (stepPaddle delta dir2 paddle2)
270+ (stepPaddle delta dir2 paddle2)
250
271
251
272
252-- Now we put it all together. We have a signal of inputs that changes whenever there
273-- Now we put it all together. We have a signal of inputs that changes whenever there
@@ -275,13 +296,14 @@ gameState = foldp stepGame defaultGame input
275-- This function displays the current score and directions.
296-- This function displays the current score and directions.
276
297
277scoreBoard w inPlay p1 p2 =
298scoreBoard w inPlay p1 p2 =
278− let code = text . monospace . toText
299+ let { code = text . monospace . toText
279− stack top bottom = flow down [ code " ", code top, code bottom ]
300+ ; stack top bottom = flow down [ code " ", code top, code bottom ]
280− msg = width w . centeredText . monospace $ toText "Press SPACE to begin"
301+ ; msg = width w . centeredText . monospace $ toText "Press SPACE to begin"
281− board = flow right [ stack "W" "S", spacer 20 1
302+ ; board = flow right [ stack "W" "S", spacer 20 1
282− , text . Text.height 4 . toText $ show p1 ++ " " ++ show p2
303+ , text . Text.height 4 . toText $ show p1 ++ " " ++ show p2
283− , spacer 20 1, stack "&uarr;" "&darr;" ]
304+ , spacer 20 1, stack "&uarr;" "&darr;" ]
284− score = container w (heightOf board) midTop board
305+ ; score = container w (heightOf board) midTop board
306+ }
285 in if inPlay then score else score `above` msg
307 in if inPlay then score else score `above` msg
286
308
287
309
@@ -302,4 +324,18 @@ display (w,h) (GameState state (Score p1 p2) (Ball pos _) (Paddle y1) (Paddle y2
302-- We can now define a view of the game (a signal of Elements) that changes
324-- We can now define a view of the game (a signal of Elements) that changes
303-- as the GameState changes. This is what the users will see.
325-- as the GameState changes. This is what the users will see.
304
326
305−main = lift2 display Window.dimensions gameState
327+view = lift2 display Win.dimensions gameState
328+
329+
330+-- Here we tell the JavaScript FPS manager that all of the computations for
331+-- this frame are complete. This allows the manager to calculate when the next
332+-- step should happen.
333+
334+done = lift (\_ -> castBoolToJSBool True) view
335+foreign export jsevent "finished"
336+ done :: Signal JSBool
337+
338+
339+-- And finally, we display the view of the game to the user: Pong in Elm!
340+
341+main = view