{-# 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))