diff options
Diffstat (limited to 'Demos/Pong/Pong.hs')
-rw-r--r-- | Demos/Pong/Pong.hs | 59 |
1 files changed, 37 insertions, 22 deletions
diff --git a/Demos/Pong/Pong.hs b/Demos/Pong/Pong.hs index fd7fbeb..0e24a42 100644 --- a/Demos/Pong/Pong.hs +++ b/Demos/Pong/Pong.hs | |||
@@ -16,18 +16,15 @@ import Spear.Step | |||
16 | 16 | ||
17 | -- Configuration | 17 | -- Configuration |
18 | 18 | ||
19 | padSize = vec2 0.05 0.02 | 19 | padSize = vec2 0.07 0.02 |
20 | 20 | ballSize = 0.012 | |
21 | ballSize = 0.01 | 21 | ballSpeed = 0.6 |
22 | 22 | initialBallVelocity = vec2 1 1 | |
23 | ballVelocity = vec2 0.3 0.3 | 23 | maxBounceAngle = 65 * pi/180 |
24 | 24 | playerSpeed = 1.0 | |
25 | playerSpeed = 0.7 | 25 | enemySpeed = 1.5 |
26 | |||
27 | initialEnemyPos = vec2 0.5 0.9 | 26 | initialEnemyPos = vec2 0.5 0.9 |
28 | |||
29 | initialPlayerPos = vec2 0.5 0.1 | 27 | initialPlayerPos = vec2 0.5 0.1 |
30 | |||
31 | initialBallPos = vec2 0.5 0.5 | 28 | initialBallPos = vec2 0.5 0.5 |
32 | 29 | ||
33 | -- Game events | 30 | -- Game events |
@@ -66,7 +63,7 @@ padBox = AABB2 (-padSize) padSize | |||
66 | obj2 = obj2FromVectors unitx2 unity2 | 63 | obj2 = obj2FromVectors unitx2 unity2 |
67 | 64 | ||
68 | newWorld = | 65 | newWorld = |
69 | [ GameObject ballBox (obj2 initialBallPos) $ stepBall ballVelocity, | 66 | [ GameObject ballBox (obj2 initialBallPos) $ stepBall initialBallVelocity, |
70 | GameObject padBox (obj2 initialEnemyPos) stepEnemy, | 67 | GameObject padBox (obj2 initialEnemyPos) stepEnemy, |
71 | GameObject padBox (obj2 initialPlayerPos) stepPlayer | 68 | GameObject padBox (obj2 initialPlayerPos) stepPlayer |
72 | ] | 69 | ] |
@@ -75,19 +72,37 @@ newWorld = | |||
75 | 72 | ||
76 | stepBall vel = collideBall vel .> moveBall | 73 | stepBall vel = collideBall vel .> moveBall |
77 | 74 | ||
75 | -- TODO: in collideBall and paddleBounce, we should an apply an offset to the | ||
76 | -- ball when collision is detected. | ||
78 | collideBall :: Vector2 -> Step [GameObject] e GameObject (Vector2, GameObject) | 77 | collideBall :: Vector2 -> Step [GameObject] e GameObject (Vector2, GameObject) |
79 | collideBall vel = step $ \_ dt gos _ ball -> | 78 | collideBall vel = step $ \_ dt gos _ ball -> |
80 | let (AABB2 pmin pmax) = aabb ball `aabbAdd` pos ball | 79 | let (AABB2 pmin pmax) = aabb ball `aabbAdd` pos ball |
81 | collideCol = x pmin < 0 || x pmax > 1 | 80 | collideSide = x pmin < 0 || x pmax > 1 |
82 | collideRow = y pmin < 0 || y pmax > 1 || any (collide ball) (tail gos) | 81 | collideBack = y pmin < 0 || y pmax > 1 |
83 | negx v@(Vector2 x y) = if collideCol then vec2 (-x) y else v | 82 | collidePaddle = any (collide ball) (tail gos) |
84 | negy v@(Vector2 x y) = if collideRow then vec2 x (-y) else v | 83 | flipX v@(Vector2 x y) = if collideSide then vec2 (-x) y else v |
85 | vel' = negx . negy $ vel | 84 | flipY v@(Vector2 x y) = if collideBack then vec2 x (-y) else v |
86 | delta = dt -- A small delta to apply when collision occurs. | 85 | vel' = normalise . (\v -> foldl (paddleBounce ball) v (tail gos)) . flipX . flipY $ vel |
87 | adjustX = if collideCol then scale delta (vec2 (x vel) 0) else vec2 0 0 | 86 | -- A small delta to apply when collision occurs. |
88 | adjustY = if collideRow then scale delta (vec2 0 (y vel)) else vec2 0 0 | 87 | delta = 1 + if collideSide || collideBack || collidePaddle then 2*dt else 0 |
89 | in ((vel' + adjustX + adjustY, ball), collideBall vel') | 88 | in ((scale ballSpeed (scale delta vel'), ball), collideBall vel') |
90 | 89 | ||
90 | paddleBounce :: GameObject -> Vector2 -> GameObject -> Vector2 | ||
91 | paddleBounce ball v paddle = | ||
92 | if collide ball paddle | ||
93 | then | ||
94 | let (AABB2 pmin pmax) = aabb paddle `aabbAdd` pos paddle | ||
95 | center = (x pmin + x pmax) / 2 | ||
96 | -- Normalized offset of the ball from the paddle's center, [-1, +1]. | ||
97 | -- It's outside the [-1, +1] range if there is no collision. | ||
98 | offset = (x (pos ball) - center) / ((x pmax - x pmin) / 2) | ||
99 | angle = offset * maxBounceAngle | ||
100 | -- When it bounces off of a paddle, y vel is flipped. | ||
101 | ysign = -(signum (y v)) | ||
102 | in vec2 (sin angle) (ysign * cos angle) | ||
103 | else v | ||
104 | |||
105 | collide :: GameObject -> GameObject -> Bool | ||
91 | collide go1 go2 = | 106 | collide go1 go2 = |
92 | let (AABB2 (Vector2 xmin1 ymin1) (Vector2 xmax1 ymax1)) = | 107 | let (AABB2 (Vector2 xmin1 ymin1) (Vector2 xmax1 ymax1)) = |
93 | aabb go1 `aabbAdd` pos go1 | 108 | aabb go1 `aabbAdd` pos go1 |
@@ -112,7 +127,7 @@ movePad :: Step s e GameObject GameObject | |||
112 | movePad = step $ \elapsed _ _ _ pad -> | 127 | movePad = step $ \elapsed _ _ _ pad -> |
113 | let p = vec2 px 0.9 | 128 | let p = vec2 px 0.9 |
114 | px = | 129 | px = |
115 | double2Float (sin elapsed * 0.5 + 0.5) | 130 | double2Float (sin (elapsed * enemySpeed) * 0.5 + 0.5) |
116 | * (1 - 2 * x padSize) | 131 | * (1 - 2 * x padSize) |
117 | + x padSize | 132 | + x padSize |
118 | in (setPos p pad, movePad) | 133 | in (setPos p pad, movePad) |