packages feed

pang-a-lambda-0.2.0.0: Experiments/collisions/Physics/TwoDimensions/GameCollisions.hs

{-# LANGUAGE FlexibleContexts #-}
-- | A very rudimentary collision system.
--
-- It compares every pair of objects, trying to determine if there is a
-- collision between the two of them.
--
-- NOTE: In order to minimize the number of comparisons, only moving objects
-- are tested (against every game object). That's only 2 objects right now
-- (making it almost linear in complexity), but it could easily grow and become
-- too slow.
--
module Physics.TwoDimensions.GameCollisions where

import           Data.List
import           Data.Maybe
import           Data.IdentityList
import           Physics.TwoDimensions.Collisions
import qualified Physics.TwoDimensions.Collisions      as C
import           Physics.TwoDimensions.PhysicalObjects
import           Physics.TwoDimensions.Shapes

-- | Given a list of objects, it detects all the collisions between them.
--
-- Note: this is a simple n*m-complex algorithm, with n the
-- number of objects and m the number of moving objects (right now,
-- only 2).
--
detectCollisions :: (Eq n , PhysicalObject o n Shape) => IL o -> Collisions n
detectCollisions = detectCollisionsH
 where detectCollisionsH objsT = flattened
         where -- Eliminate empty collision sets
               -- TODO: why is this really necessary?
               flattened = filter (\(C.Collision n) -> not (null n)) collisions

               -- Detect collisions between moving objects and any other objects
               collisions = detectCollisions' objsT moving

               -- Partition the object space between moving and static objects
               (moving, _static) = partition (physObjectCollides.snd) $ assocsIL objsT

-- | Detect collisions between each moving object and
-- every other object.
detectCollisions' :: (Eq n, PhysicalObject o n Shape) => IL o -> [(ILKey, o)] -> [Collision n]
detectCollisions' objsT ms = concatMap (detectCollisions'' objsT) ms

-- | Detect collisions between one specific moving object and every existing
-- object. Each collision is idependent of the rest (which is not necessarily
-- what should happen, but since the transformed velocities are eventually
-- added, there isn't much difference in the end).
detectCollisions'' :: (Eq n, PhysicalObject o n Shape) => IL o -> (ILKey, o ) -> [Collision n]
detectCollisions'' objsT m = concatMap (detectCollisions''' m) (assocsIL objsT)

-- | Detect a possible collision between two objects. Uses the object's keys to
-- distinguish them. Uses the basic 'Object'-based 'detectCollision' to
-- determine whether the two objects do collide.
detectCollisions''' :: (Eq n, PhysicalObject o n Shape) => (ILKey, o) -> (ILKey, o) -> [Collision n]
detectCollisions''' m o
 | fst m == fst o = []    -- Same object -> no collision
 | otherwise      = maybeToList (detectCollision (snd m) (snd o))