-
Notifications
You must be signed in to change notification settings - Fork 1
/
Game.hs
96 lines (72 loc) · 2.42 KB
/
Game.hs
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
{-# LANGUAGE Arrows #-}
module Pong.Game (GameLogic, game) where
import Control.Arrow
import Control.Coroutine
import Control.Coroutine.FRP
import Data.Monoid
import Pong.Keyboard
import Pong.Controls
import Pong.Rect
import Control.Category (id)
import Prelude hiding (id)
type GameLogic = Coroutine Keyboard Rects
type PlayerPos = Pos
type BallPos = Pos
type Velocity = (X,Y)
batSpeed = 5
batSize = (10,40)
startPos = 200
ballInitPos = (400,200)
ballSize = (8,8)
ballInitVel = (-6, -6)
topWall = 10
bottomWall = 590
data BallBounce = HBounce | VBounce
type BallReset = ()
game :: Coroutine Keyboard Rects
game = proc kb -> do
plPos <- playerPos -< kb
blPos <- resettingBallPos -< plPos
returnA -< [mkRect plPos batSize, mkRect blPos ballSize]
playerSpeed :: Coroutine Keyboard Int
playerSpeed = arr keyboardDir where
keyboardDir kb
| isKeyDown kb up = -batSpeed
| isKeyDown kb down = batSpeed
| otherwise = 0
playerPos :: Coroutine Keyboard PlayerPos
playerPos = playerSpeed >>> integrate startPos >>> arr (\y -> (10, y))
ballPos :: Coroutine PlayerPos BallPos
ballPos = proc plPos -> do
rec bounces <- (batBounce -< (plPos, pos)) <++> (wallBounce -< pos)
vel <- scanE bounce ballInitVel -< bounces
pos <- delay ballInitPos <<< scan vecAdd ballInitPos -< vel
returnA -< pos
resettingBallPos :: Coroutine PlayerPos BallPos
resettingBallPos = proc plPos -> do
rec pos <- restartWhen ballPos -< (plPos, reset)
reset <- watch outOfBounds -< pos
returnA -< pos
where outOfBounds (x,_) = x < 0 || x > 800
collision :: (PlayerPos, BallPos) -> Bool
collision ((px,py),(bx,by)) = abs (px-bx) < w' && abs (py-by) < h' where
w' = (bw + pw) `div` 2
h' = (bh + ph) `div` 2
(bw,bh) = ballSize
(pw,ph) = batSize
bounce :: Velocity -> BallBounce -> Velocity
bounce (dx,dy) b = case b of
HBounce -> (-dx,dy)
VBounce -> (dx,-dy)
wallBounce :: Coroutine BallPos (Event BallBounce)
wallBounce = watch (\(_,y) -> y < topWall || y > bottomWall) >>> constE VBounce
batBounce :: Coroutine (PlayerPos, BallPos) (Event BallBounce)
batBounce = watch collision >>> constE HBounce
vecMul :: Int -> (Int, Int) -> (Int, Int)
vecMul c (x,y) = (x*c,y*c)
vecAdd :: (Int, Int) -> (Int, Int) -> (Int, Int)
vecAdd (a,b) (c,d) = (a+c,b+d)
mkRect :: Pos -> Size -> Rect
mkRect (x,y) (w,h) = ((x-w',y-h'),(w,h)) where
w' = w `div` 2
h' = h `div` 2