aboutsummaryrefslogtreecommitdiff
path: root/Demos
diff options
context:
space:
mode:
author3gg <3gg@shellblade.net>2024-12-24 12:07:05 -0800
committer3gg <3gg@shellblade.net>2024-12-24 12:07:05 -0800
commit92e7a93d8c1475bdc802d10a1722bcf8a295449d (patch)
treefc4ada902fec59e461aceff1cafddf87eaeb938c /Demos
parent0e62e481f56e7085856a4650268c04ac9d05fb9c (diff)
New physics module.HEADmain
Diffstat (limited to 'Demos')
-rw-r--r--Demos/Pong/Pong.hs101
1 files changed, 61 insertions, 40 deletions
diff --git a/Demos/Pong/Pong.hs b/Demos/Pong/Pong.hs
index b9661ee..b12f792 100644
--- a/Demos/Pong/Pong.hs
+++ b/Demos/Pong/Pong.hs
@@ -16,10 +16,11 @@ import Spear.Math.Algebra
16import Spear.Math.Spatial 16import Spear.Math.Spatial
17import Spear.Math.Spatial2 17import Spear.Math.Spatial2
18import Spear.Math.Vector 18import Spear.Math.Vector
19import Spear.Physics.Collision
19import Spear.Prelude 20import Spear.Prelude
20import Spear.Step 21import Spear.Step
21 22
22import Data.Monoid (mconcat) 23import Data.Monoid (mconcat)
23 24
24 25
25-- Configuration 26-- Configuration
@@ -41,14 +42,22 @@ initialBallPos = vec2 0.5 0.5
41data GameEvent 42data GameEvent
42 = MoveLeft 43 = MoveLeft
43 | MoveRight 44 | MoveRight
44 deriving (Eq, Ord, Show) 45 | Collision GameObjectId GameObjectId
46 deriving (Eq, Show)
45 47
46-- Game objects 48-- Game objects
47 49
50data GameObjectId
51 = Ball
52 | Enemy
53 | Player
54 deriving (Eq, Show)
55
48data GameObject = GameObject 56data GameObject = GameObject
49 { aabb :: AABB2, 57 { gameObjectId :: !GameObjectId
50 basis :: Transform2, 58 , aabb :: {-# UNPACK #-} !AABB2
51 gostep :: Step [GameObject] [GameEvent] GameObject GameObject 59 , basis :: {-# UNPACK #-} !Transform2
60 , gostep :: Step [GameObject] [GameEvent] GameObject GameObject
52 } 61 }
53 62
54 63
@@ -78,46 +87,68 @@ instance Spatial GameObject Vector2 Angle Transform2 where
78 transform = basis 87 transform = basis
79 88
80 89
90instance Bounded2 GameObject where
91 boundingVolume obj = aabb2Volume $ translate (position obj) (aabb obj)
92
93
81ballBox, padBox :: AABB2 94ballBox, padBox :: AABB2
82ballBox = AABB2 (vec2 (-s) (-s)) (vec2 s s) where s = ballSize 95ballBox = AABB2 (vec2 (-s) (-s)) (vec2 s s) where s = ballSize
83padBox = AABB2 (-padSize) padSize 96padBox = AABB2 (-padSize) padSize
84 97
85newWorld = 98newWorld =
86 [ GameObject ballBox (makeAt initialBallPos) $ stepBall initialBallVelocity, 99 [ GameObject Ball ballBox (makeAt initialBallPos) $ stepBall initialBallVelocity,
87 GameObject padBox (makeAt initialEnemyPos) stepEnemy, 100 GameObject Enemy padBox (makeAt initialEnemyPos) stepEnemy,
88 GameObject padBox (makeAt initialPlayerPos) stepPlayer 101 GameObject Player padBox (makeAt initialPlayerPos) stepPlayer
89 ] 102 ]
90 where makeAt = newTransform2 unitx2 unity2 103 where makeAt = newTransform2 unitx2 unity2
91 104
92 105
106-- Step the game world:
107-- 1. Simulate physics.
108-- 2. Collide objects and clip -> produce collision events.
109-- 3. Update game objects <- input collision events.
93stepWorld :: Elapsed -> Dt -> [GameEvent] -> [GameObject] -> [GameObject] 110stepWorld :: Elapsed -> Dt -> [GameEvent] -> [GameObject] -> [GameObject]
94stepWorld elapsed dt evts gos = map (update elapsed dt evts gos) gos 111stepWorld elapsed dt events gos@[ball, enemy, player] =
112 let
113 collisions = collide [ball] [enemy, player]
114 collisionEvents = (\(x,y) -> Collision (gameObjectId x) (gameObjectId y)) <$> collisions
115 events' = events ++ collisionEvents
116 gos' = map (update elapsed dt events' gos) gos
117 in
118 gos'
95 119
96update :: Elapsed -> Dt -> [GameEvent] -> [GameObject] -> GameObject -> GameObject 120update :: Elapsed -> Dt -> [GameEvent] -> [GameObject] -> GameObject -> GameObject
97update elapsed dt evts gos go = 121update elapsed dt events gos go =
98 let (go', s') = runStep (gostep go) elapsed dt gos evts go 122 let (go', s') = runStep (gostep go) elapsed dt gos events go
99 in go' {gostep = s'} 123 in go' { gostep = s' }
124
100 125
101-- Ball steppers 126-- Ball steppers
102 127
103stepBall vel = collideBall vel .> moveBall 128stepBall vel = bounceBall vel .> moveBall
104 129
105collideBall :: Vector2 -> Step [GameObject] e GameObject (Vector2, GameObject) 130bounceBall :: Vector2 -> Step [GameObject] [GameEvent] GameObject (Vector2, GameObject)
106collideBall vel = step $ \_ dt gos _ ball -> 131bounceBall vel = step $ \_ dt gos events ball ->
107 let (AABB2 pmin pmax) = translate (position ball) (aabb ball) 132 let (AABB2 pmin pmax) = translate (position ball) (aabb ball)
108 sideCollision = x pmin < 0 || x pmax > 1 133 sideCollision = x pmin < 0 || x pmax > 1
109 backCollision = y pmin < 0 || y pmax > 1 134 backCollision = y pmin < 0 || y pmax > 1
110 flipX v@(Vector2 x y) = if sideCollision then vec2 (-x) y else v 135 flipX v@(Vector2 x y) = if sideCollision then vec2 (-x) y else v
111 flipY v@(Vector2 x y) = if backCollision then vec2 x (-y) else v 136 flipY v@(Vector2 x y) = if backCollision then vec2 x (-y) else v
112 vel' = normalise . (\v -> foldl (paddleBounce ball) v (tail gos)) . flipX . flipY $ vel 137 collideWithPaddles vel = foldl (paddleBounce ball events) vel (tail gos)
138 vel' = normalise
139 . collideWithPaddles
140 . flipX
141 . flipY
142 $ vel
113 collision = vel' /= vel 143 collision = vel' /= vel
114 -- Apply offset when collision occurs to avoid sticky collisions. 144 -- Apply offset when collision occurs to avoid sticky collisions.
115 delta = (1::Float) + if collision then (3::Float)*dt else (0::Float) 145 delta = (1::Float) + if collision then (3::Float)*dt else (0::Float)
116 in ((ballSpeed * delta * vel', ball), collideBall vel') 146 in ((ballSpeed * delta * vel', ball), bounceBall vel')
117 147
118paddleBounce :: GameObject -> Vector2 -> GameObject -> Vector2 148paddleBounce :: GameObject -> [GameEvent] -> Vector2 -> GameObject -> Vector2
119paddleBounce ball v paddle = 149paddleBounce ball events vel paddle =
120 if collide ball paddle 150 let collision = Collision Ball (gameObjectId paddle) `elem` events
151 in if collision
121 then 152 then
122 let (AABB2 pmin pmax) = translate (position paddle) (aabb paddle) 153 let (AABB2 pmin pmax) = translate (position paddle) (aabb paddle)
123 center = (x pmin + x pmax) / (2::Float) 154 center = (x pmin + x pmax) / (2::Float)
@@ -126,25 +157,14 @@ paddleBounce ball v paddle =
126 offset = (x (position ball) - center) / ((x pmax - x pmin) / (2::Float)) 157 offset = (x (position ball) - center) / ((x pmax - x pmin) / (2::Float))
127 angle = offset * maxBounceAngle 158 angle = offset * maxBounceAngle
128 -- When it bounces off of a paddle, y vel is flipped. 159 -- When it bounces off of a paddle, y vel is flipped.
129 ysign = -(signum (y v)) 160 ysign = -(signum (y vel))
130 in vec2 (sin angle) (ysign * cos angle) 161 in vec2 (sin angle) (ysign * cos angle)
131 else v 162 else vel
132
133collide :: GameObject -> GameObject -> Bool
134collide go1 go2 =
135 let (AABB2 (Vector2 xmin1 ymin1) (Vector2 xmax1 ymax1)) =
136 translate (position go1) (aabb go1)
137 (AABB2 (Vector2 xmin2 ymin2) (Vector2 xmax2 ymax2)) =
138 translate (position go2) (aabb go2)
139 in not $
140 xmax1 < xmin2 ||
141 xmin1 > xmax2 ||
142 ymax1 < ymin2 ||
143 ymin1 > ymax2
144 163
145moveBall :: Step s e (Vector2, GameObject) GameObject 164moveBall :: Step s e (Vector2, GameObject) GameObject
146moveBall = step $ \_ dt _ _ (vel, ball) -> (translate (vel * dt) ball, moveBall) 165moveBall = step $ \_ dt _ _ (vel, ball) -> (translate (vel * dt) ball, moveBall)
147 166
167
148-- Enemy stepper 168-- Enemy stepper
149 169
150stepEnemy = movePad 0 .> clamp 170stepEnemy = movePad 0 .> clamp
@@ -161,17 +181,18 @@ movePad previousMomentumVector = step $ \_ dt gos _ pad ->
161sign :: Float -> Float 181sign :: Float -> Float
162sign x = if x >= 0 then 1 else -1 182sign x = if x >= 0 then 1 else -1
163 183
184
164-- Player stepper 185-- Player stepper
165 186
166stepPlayer = sfold moveGO .> clamp 187stepPlayer = sfold movePlayer .> clamp
167 188
168moveGO = mconcat 189movePlayer = mconcat
169 [ swhen MoveLeft $ moveGO' (vec2 (-playerSpeed) 0) 190 [ swhen MoveLeft $ movePlayer' (vec2 (-playerSpeed) 0)
170 , swhen MoveRight $ moveGO' (vec2 playerSpeed 0) 191 , swhen MoveRight $ movePlayer' (vec2 playerSpeed 0)
171 ] 192 ]
172 193
173moveGO' :: Vector2 -> Step s e GameObject GameObject 194movePlayer' :: Vector2 -> Step s e GameObject GameObject
174moveGO' dir = step $ \_ dt _ _ go -> (translate (dir * dt) go, moveGO' dir) 195movePlayer' dir = step $ \_ dt _ _ go -> (translate (dir * dt) go, movePlayer' dir)
175 196
176clamp :: Step s e GameObject GameObject 197clamp :: Step s e GameObject GameObject
177clamp = spure $ \go -> 198clamp = spure $ \go ->