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 +++++++++++++++++++++++++++-----------------
 Spear.cabal                  |  2 +-
 Spear/Math/Vector.hs         | 12 ++++-----
 Spear/Math/Vector/Class.hs   | 43 --------------------------------
 Spear/Math/Vector/Vector.hs  | 43 ++++++++++++++++++++++++++++++++
 Spear/Math/Vector/Vector2.hs | 16 +++---------
 Spear/Math/Vector/Vector3.hs |  8 +++---
 Spear/Math/Vector/Vector4.hs |  8 +++---
 Spear/Window.hs              |  1 +
 9 files changed, 100 insertions(+), 92 deletions(-)
 delete mode 100644 Spear/Math/Vector/Class.hs
 create mode 100644 Spear/Math/Vector/Vector.hs

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)
diff --git a/Spear.cabal b/Spear.cabal
index 824f352..7025fcd 100644
--- a/Spear.cabal
+++ b/Spear.cabal
@@ -52,7 +52,7 @@ library
                      Spear.Math.Triangle
                      Spear.Math.Utils
                      Spear.Math.Vector
-                     Spear.Math.Vector.Class
+                     Spear.Math.Vector.Vector
                      Spear.Math.Vector.Vector2
                      Spear.Math.Vector.Vector3
                      Spear.Math.Vector.Vector4
diff --git a/Spear/Math/Vector.hs b/Spear/Math/Vector.hs
index dd5e496..b43f7ec 100644
--- a/Spear/Math/Vector.hs
+++ b/Spear/Math/Vector.hs
@@ -1,13 +1,13 @@
 module Spear.Math.Vector
 (
-    module Spear.Math.Vector.Vector2
+    module Spear.Math.Vector.Vector
+,   module Spear.Math.Vector.Vector2
 ,   module Spear.Math.Vector.Vector3
 ,   module Spear.Math.Vector.Vector4
-,   module Spear.Math.Vector.Class
 )
 where
 
-import Spear.Math.Vector.Vector2
-import Spear.Math.Vector.Vector3
-import Spear.Math.Vector.Vector4
-import Spear.Math.Vector.Class
+import           Spear.Math.Vector.Vector
+import           Spear.Math.Vector.Vector2
+import           Spear.Math.Vector.Vector3
+import           Spear.Math.Vector.Vector4
diff --git a/Spear/Math/Vector/Class.hs b/Spear/Math/Vector/Class.hs
deleted file mode 100644
index 19ddfac..0000000
--- a/Spear/Math/Vector/Class.hs
+++ /dev/null
@@ -1,43 +0,0 @@
-module Spear.Math.Vector.Class
-where
-
-class (Fractional a, Ord a) => VectorClass a where
-      -- | Create a vector from the given list.
-      fromList :: [Float] -> a
-      
-      -- | Return the vector's x coordinate.
-      x :: a -> Float
-      x _ = 0
-
-      -- | Return the vector's y coordinate.
-      y :: a -> Float
-      y _ = 0
-
-      -- | Return the vector's z coordinate.
-      z :: a -> Float
-      z _ = 0
-
-      -- | Return the vector's w coordinate.
-      w :: a -> Float
-      w _ = 0
-
-      -- | Return the vector's ith coordinate.
-      (!) :: a -> Int -> Float
-      
-      -- | Compute the given vectors' dot product.
-      dot :: a -> a -> Float
-      
-      -- | Compute the given vector's squared norm.
-      normSq :: a -> Float
-      
-      -- | Compute the given vector's norm.
-      norm :: a -> Float
-      
-      -- | Multiply the given vector with the given scalar.
-      scale :: Float -> a -> a
-      
-      -- | Negate the given vector.
-      neg :: a -> a
-      
-      -- | Normalise the given vector.
-      normalise :: a -> a
\ No newline at end of file
diff --git a/Spear/Math/Vector/Vector.hs b/Spear/Math/Vector/Vector.hs
new file mode 100644
index 0000000..35b04e2
--- /dev/null
+++ b/Spear/Math/Vector/Vector.hs
@@ -0,0 +1,43 @@
+module Spear.Math.Vector.Vector
+where
+
+class (Fractional a, Ord a) => Vector a where
+      -- | Create a vector from the given list.
+      fromList :: [Float] -> a
+
+      -- | Return the vector's x coordinate.
+      x :: a -> Float
+      x _ = 0
+
+      -- | Return the vector's y coordinate.
+      y :: a -> Float
+      y _ = 0
+
+      -- | Return the vector's z coordinate.
+      z :: a -> Float
+      z _ = 0
+
+      -- | Return the vector's w coordinate.
+      w :: a -> Float
+      w _ = 0
+
+      -- | Return the vector's ith coordinate.
+      (!) :: a -> Int -> Float
+
+      -- | Compute the given vectors' dot product.
+      dot :: a -> a -> Float
+
+      -- | Compute the given vector's squared norm.
+      normSq :: a -> Float
+
+      -- | Compute the given vector's norm.
+      norm :: a -> Float
+
+      -- | Multiply the given vector with the given scalar.
+      scale :: Float -> a -> a
+
+      -- | Negate the given vector.
+      neg :: a -> a
+
+      -- | Normalise the given vector.
+      normalise :: a -> a
diff --git a/Spear/Math/Vector/Vector2.hs b/Spear/Math/Vector/Vector2.hs
index dfb4fb9..5bbb632 100644
--- a/Spear/Math/Vector/Vector2.hs
+++ b/Spear/Math/Vector/Vector2.hs
@@ -14,10 +14,10 @@ module Spear.Math.Vector.Vector2
 )
 where
 
-import Spear.Math.Vector.Class
+import           Spear.Math.Vector.Vector
 
-import Foreign.C.Types (CFloat)
-import Foreign.Storable
+import           Foreign.C.Types          (CFloat)
+import           Foreign.Storable
 
 type Right2 = Vector2
 type Up2 = Vector2
@@ -50,7 +50,7 @@ instance Ord Vector2 where
     min (Vector2 ax ay) (Vector2 bx by) = Vector2 (Prelude.min ax bx) (Prelude.min ay by)
 
 
-instance VectorClass Vector2 where
+instance Vector Vector2 where
          {-# INLINABLE fromList #-}
          fromList (ax:ay:_) = Vector2 ax ay
 
@@ -104,27 +104,19 @@ instance Storable Vector2 where
         pokeByteOff ptr sizeFloat ay
 
 
--- | Get the vector's x coordinate.
-
-
-
 -- | Unit vector along the X axis.
 unitx2 = Vector2 1 0
 
-
 -- | Unit vector along the Y axis.
 unity2 = Vector2 0 1
 
-
 -- | Zero vector.
 zero2 = Vector2 0 0
 
-
 -- | Create a vector from the given values.
 vec2 :: Float -> Float -> Vector2
 vec2 ax ay = Vector2 ax ay
 
-
 -- | Compute a vector perpendicular to the given one, satisfying:
 --
 -- perp (Vector2 0 1) = Vector2 1 0
diff --git a/Spear/Math/Vector/Vector3.hs b/Spear/Math/Vector/Vector3.hs
index 429df0f..82deba2 100644
--- a/Spear/Math/Vector/Vector3.hs
+++ b/Spear/Math/Vector/Vector3.hs
@@ -18,10 +18,10 @@ module Spear.Math.Vector.Vector3
 where
 
 
-import Spear.Math.Vector.Class
+import           Spear.Math.Vector.Vector
 
-import Foreign.C.Types (CFloat)
-import Foreign.Storable
+import           Foreign.C.Types          (CFloat)
+import           Foreign.Storable
 
 type Right3 = Vector3
 type Up3 = Vector3
@@ -76,7 +76,7 @@ instance Ord Vector3 where
     min (Vector3 ax ay az) (Vector3 bx by bz) = Vector3 (Prelude.min ax bx) (Prelude.min ay by) (Prelude.min az bz)
 
 
-instance VectorClass Vector3 where
+instance Vector Vector3 where
          {-# INLINABLE fromList #-}
          fromList (ax:ay:az:_) = Vector3 ax ay az
 
diff --git a/Spear/Math/Vector/Vector4.hs b/Spear/Math/Vector/Vector4.hs
index 4314b51..325eefc 100644
--- a/Spear/Math/Vector/Vector4.hs
+++ b/Spear/Math/Vector/Vector4.hs
@@ -12,10 +12,10 @@ module Spear.Math.Vector.Vector4
 where
 
 
-import Spear.Math.Vector.Class
+import           Spear.Math.Vector.Vector
 
-import Foreign.C.Types (CFloat)
-import Foreign.Storable
+import           Foreign.C.Types          (CFloat)
+import           Foreign.Storable
 
 
 -- | Represents a vector in 3D.
@@ -73,7 +73,7 @@ instance Ord Vector4 where
         Vector4 (Prelude.max ax bx) (Prelude.max ay by) (Prelude.max az bz) (Prelude.min aw bw)
 
 
-instance VectorClass Vector4 where
+instance Vector Vector4 where
          {-# INLINABLE fromList #-}
          fromList (ax:ay:az:aw:_) = Vector4 ax ay az aw
 
diff --git a/Spear/Window.hs b/Spear/Window.hs
index ec90a2f..336910b 100644
--- a/Spear/Window.hs
+++ b/Spear/Window.hs
@@ -31,6 +31,7 @@ where
 import           Control.Concurrent.MVar
 import           Control.Exception
 import           Control.Monad           (foldM, unless, void, when)
+import           Data.Functor            ((<&>))
 import           Data.Maybe              (fromJust, fromMaybe, isJust)
 import qualified Graphics.UI.GLFW        as GLFW
 import           Spear.Game
-- 
cgit v1.2.3