-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpong.elm
More file actions
105 lines (80 loc) · 3.33 KB
/
pong.elm
File metadata and controls
105 lines (80 loc) · 3.33 KB
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
96
97
98
99
100
101
102
103
104
105
import Keyboard
import Text
import Window
-- Inputs
type Input = { space:Bool, dir1:Int, dir2:Int, delta:Time }
delta = inSeconds <~ fps 35
input = sampleOn delta (Input <~ Keyboard.space
~ lift .y Keyboard.wasd
~ lift .y Keyboard.arrows
~ delta)
-- Model
(gameWidth,gameHeight) = (600,400)
(halfWidth,halfHeight) = (300,200)
data State = Play | Pause
type Ball = { x:Float, y:Float, vx:Float, vy:Float }
type Player = { x:Float, y:Float, vx:Float, vy:Float, score:Int }
type Game = { state:State, ball:Ball, player1:Player, player2:Player }
player : Float -> Player
player x = { x=x, y=0, vx=0, vy=0, score=0 }
defaultGame : Game
defaultGame =
{ state = Pause,
ball = { x=0, y=0, vx=200, vy=200 },
player1 = player (20-halfWidth) ,
player2 = player (halfWidth-20) }
-- Updates
stepObj t ({x,y,vx,vy} as obj) =
{ obj | x <- x + vx*t, y <- y + vy*t }
near k c n = n >= k-c && n <= k+c
within ball paddle = (ball.x |> near paddle.x 8)
&& (ball.y |> near paddle.y 20)
stepV v lowerCollision upperCollision =
if | lowerCollision -> abs v
| upperCollision -> 0 - abs v
| otherwise -> v
stepBall : Time -> Ball -> Player -> Player -> Ball
stepBall t ({x,y,vx,vy} as ball) p1 p2 =
if not (ball.x |> near 0 halfWidth)
then { ball | x <- 0, y <- 0 }
else stepObj t { ball | vx <- stepV vx (ball `within` p1) (ball `within` p2) ,
vy <- stepV vy (y < 7-halfHeight) (y > halfHeight-7) }
stepPlyr : Time -> Int -> Int -> Player -> Player
stepPlyr t dir points player =
let player1 = stepObj t { player | vy <- toFloat dir * 200 }
in { player1 | y <- clamp (22-halfHeight) (halfHeight-22) player1.y
, score <- player.score + points }
stepGame : Input -> Game -> Game
stepGame {space,dir1,dir2,delta} ({state,ball,player1,player2} as game) =
let score1 = if ball.x > halfWidth then 1 else 0
score2 = if ball.x < -halfWidth then 1 else 0
in {game| state <- if | space -> Play
| score1 /= score2 -> Pause
| otherwise -> state
, ball <- if state == Pause then ball else
stepBall delta ball player1 player2
, player1 <- stepPlyr delta dir1 score1 player1
, player2 <- stepPlyr delta dir2 score2 player2 }
gameState = foldp stepGame defaultGame input
-- Display
pongGreen = rgb 60 100 60
textGreen = rgb 160 200 160
txt f = toText >> Text.color textGreen >> monospace >> f >> leftAligned
msg = "SPACE to start, WS and ↑↓ to move"
make obj shape =
shape |> filled white
|> move (obj.x,obj.y)
display : (Int,Int) -> Game -> Element
display (w,h) {state,ball,player1,player2} =
let scores : Element
scores = txt (Text.height 50) (show player1.score ++ " " ++ show player2.score)
in container w h middle <| collage gameWidth gameHeight
[ rect gameWidth gameHeight |> filled pongGreen
, oval 15 15 |> make ball
, rect 10 40 |> make player1
, rect 10 40 |> make player2
, toForm scores |> move (0, gameHeight/2 - 40)
, toForm (if state == Play then spacer 1 1 else txt identity msg)
|> move (0, 40 - gameHeight/2)
]
main = lift2 display Window.dimensions gameState