From 5a395dbb9491cee0a921553b331923d492a16fc4 Mon Sep 17 00:00:00 2001 From: 3gg <3gg@shellblade.net> Date: Wed, 23 Aug 2023 08:47:16 -0700 Subject: Better physics and Vector class rename. --- Demos/Pong/Pong.hs | 59 ++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 37 insertions(+), 22 deletions(-) (limited to 'Demos') 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 -- Configuration -padSize = vec2 0.05 0.02 - -ballSize = 0.01 - -ballVelocity = vec2 0.3 0.3 - -playerSpeed = 0.7 - +padSize = vec2 0.07 0.02 +ballSize = 0.012 +ballSpeed = 0.6 +initialBallVelocity = vec2 1 1 +maxBounceAngle = 65 * pi/180 +playerSpeed = 1.0 +enemySpeed = 1.5 initialEnemyPos = vec2 0.5 0.9 - initialPlayerPos = vec2 0.5 0.1 - initialBallPos = vec2 0.5 0.5 -- Game events @@ -66,7 +63,7 @@ padBox = AABB2 (-padSize) padSize obj2 = obj2FromVectors unitx2 unity2 newWorld = - [ GameObject ballBox (obj2 initialBallPos) $ stepBall ballVelocity, + [ GameObject ballBox (obj2 initialBallPos) $ stepBall initialBallVelocity, GameObject padBox (obj2 initialEnemyPos) stepEnemy, GameObject padBox (obj2 initialPlayerPos) stepPlayer ] @@ -75,19 +72,37 @@ newWorld = stepBall vel = collideBall vel .> moveBall +-- TODO: in collideBall and paddleBounce, we should an apply an offset to the +-- ball when collision is detected. collideBall :: Vector2 -> Step [GameObject] e GameObject (Vector2, GameObject) collideBall vel = step $ \_ dt gos _ ball -> let (AABB2 pmin pmax) = aabb ball `aabbAdd` pos ball - collideCol = x pmin < 0 || x pmax > 1 - collideRow = y pmin < 0 || y pmax > 1 || any (collide ball) (tail gos) - negx v@(Vector2 x y) = if collideCol then vec2 (-x) y else v - negy v@(Vector2 x y) = if collideRow then vec2 x (-y) else v - vel' = negx . negy $ vel - delta = dt -- A small delta to apply when collision occurs. - adjustX = if collideCol then scale delta (vec2 (x vel) 0) else vec2 0 0 - adjustY = if collideRow then scale delta (vec2 0 (y vel)) else vec2 0 0 - in ((vel' + adjustX + adjustY, ball), collideBall vel') - + collideSide = x pmin < 0 || x pmax > 1 + collideBack = y pmin < 0 || y pmax > 1 + collidePaddle = any (collide ball) (tail gos) + flipX v@(Vector2 x y) = if collideSide then vec2 (-x) y else v + flipY v@(Vector2 x y) = if collideBack then vec2 x (-y) else v + vel' = normalise . (\v -> foldl (paddleBounce ball) v (tail gos)) . flipX . flipY $ vel + -- A small delta to apply when collision occurs. + delta = 1 + if collideSide || collideBack || collidePaddle then 2*dt else 0 + in ((scale ballSpeed (scale delta vel'), ball), collideBall vel') + +paddleBounce :: GameObject -> Vector2 -> GameObject -> Vector2 +paddleBounce ball v paddle = + if collide ball paddle + then + let (AABB2 pmin pmax) = aabb paddle `aabbAdd` pos paddle + center = (x pmin + x pmax) / 2 + -- Normalized offset of the ball from the paddle's center, [-1, +1]. + -- It's outside the [-1, +1] range if there is no collision. + offset = (x (pos ball) - center) / ((x pmax - x pmin) / 2) + angle = offset * maxBounceAngle + -- When it bounces off of a paddle, y vel is flipped. + ysign = -(signum (y v)) + in vec2 (sin angle) (ysign * cos angle) + else v + +collide :: GameObject -> GameObject -> Bool collide go1 go2 = let (AABB2 (Vector2 xmin1 ymin1) (Vector2 xmax1 ymax1)) = aabb go1 `aabbAdd` pos go1 @@ -112,7 +127,7 @@ movePad :: Step s e GameObject GameObject movePad = step $ \elapsed _ _ _ pad -> let p = vec2 px 0.9 px = - double2Float (sin elapsed * 0.5 + 0.5) + double2Float (sin (elapsed * enemySpeed) * 0.5 + 0.5) * (1 - 2 * x padSize) + x padSize in (setPos p pad, movePad) -- cgit v1.2.3