edge-0.8.2: Moving.hs
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)