module Moving where import Data.WrapAround import qualified Data.WrapAround as W import Trigonometry import Data.List (find) import Control.Monad (join) import Common maxExpectedVelocity = 1000 -- should equal max velocity of fastest object in arena calcNewVelocity :: Velocity -> Double -> Angle -> Double -> Time -> (Double, Double) calcNewVelocity oVelocity accelerationRate thrustAngle maxVelocity t = let (vXo, vYo) = oVelocity in let acceleration = t * accelerationRate in let dX = cos thrustAngle * acceleration in let dY = sin thrustAngle * acceleration in let vXn = vXo + dX in let vYn = vYo + dY in let magVN' = sqrt (vXn ** 2 + vYn ** 2) in let magVN = if magVN' == 0 then 0.1 -- erm... necessary? else magVN' in let aVN = if vXn >= 0 then asin (vYn / magVN) else pi - asin (vYn / magVN) in let finalMag = min magVN maxVelocity in let finalX = cos aVN * finalMag in let finalY = sin aVN * finalMag in (finalX, finalY) idealNewLocation :: WrapMap -> WrapPoint -> Velocity -> Time -> WrapPoint idealNewLocation wmap oLocation (velX, velY) t = addPoints' wmap oLocation velocity' where velocity' = (velX * t, velY * t) class Locatable a where center :: a -> WrapPoint class (Locatable a) => Moving a where velocity :: a -> Velocity class (Moving a) => Colliding a where collisionRadius :: a -> Double data Collision = Collision { time :: Time -- since start of collision detection -- window frame , center1 :: WrapPoint -- at point of collision , center2 :: WrapPoint -- likewise } -- Double refers to time window for checking for collision collision :: (Colliding a, Colliding b) => WrapMap -> Time -> a -> b -> Maybe Collision collision wmap tw obj1 obj2 = let r1 = collisionRadius obj1 in let r2 = collisionRadius obj2 in let v1 = velocity obj1 in let v2 = velocity obj2 in let dD = Trigonometry.distance v1 v2 in let ts = fromIntegral $ ceiling (dD / (r1 + r2)) in let ti = tw / ts in let tpoints = [ x * ti | x <- [0..ts] ] in let o1 = center obj1 in let o2 = center obj2 in let points = [ ( addPoints' wmap o1 (mulSV t v1) , addPoints' wmap o2 (mulSV t v2) ) | t <- tpoints ] in let distances = [ W.distance wmap p1 p2 | (p1, p2) <- points ] in let zipped = zip3 tpoints points distances in do (t, (p1, p2), _) <- find (\(_, _, d) -> d <= r1 + r2) zipped Just Collision { time = t , center1 = p1 , center2 = p2 } collisionWindow :: (Colliding a, Colliding b) => WrapMap -> Double -> a -> b -> Bool collisionWindow wmap range obj1 obj2 = W.distance wmap (center obj1) (center obj2) <= range collisionScan :: (Colliding a, Colliding b) => WrapMap -> a -> [b] -> Time -> Maybe Collision collisionScan wmap c cs t = let relAsteroids = [ a | a <- cs , let range = max (maxExpectedVelocity * 2 * t) (collisionRadius c + collisionRadius a) in collisionWindow wmap range c a ] in let collisions = map (collision wmap t c) relAsteroids in join (find (\a -> case a of Nothing -> False otherwise -> True) collisions)