packages feed

edge-0.8.18: Projectile/BulletMkI.hs

module Projectile.BulletMkI ( BulletMkI(..)
                           , new
                           , prj
                           ) where

import Combat ( Damageable(..), Damaging(..), Projectile(..) )
import Animation ( Animation(..) )
import Updating
    ( SimpleTransient(..), Transient(..), InternallyUpdating(..) )
import Graphics.Gloss.Data.Picture ( Picture(Circle, Color) )
import Graphics.Gloss.Data.Color ( cyan, blue )
import Data.WrapAround ( WP, WM, distance )
import qualified Moving as M
    ( Colliding(..), Moving(..), Locatable(..), newLocation )
import Common ( Velocity, Angle, Time )
import Math ( appPair, remF, zeroOrLess, moreThanZero )

velocityC = 700.0

rangeC = 1000.0

damE = 1

data BulletMkI =
  BulletMkI { velocity :: Velocity
            , center :: WP
            , rangeLeft :: Double
            , wrapMap :: WM
            , idealNewCenter :: Maybe WP
            , impacted :: Bool
            , clock :: Time
            }

new a b c (d, e) =
  BulletMkI { velocity = (x + d, y + e)
           , center = c
           , rangeLeft = rangeC
           , wrapMap = a
           , idealNewCenter = Nothing
           , impacted = False
           , clock = 0.0
           }
  where (x, y) = appPair ((* velocityC) . ($ b)) (cos, sin)

instance Animation BulletMkI where

  image s t = (Color (c r) . Circle) 2.0
    where c x | x < 0.10 = blue
              | otherwise = cyan
          r = remF (clock s) 0.2

instance M.Colliding BulletMkI where

  collisionRadius _ = 2.0

instance M.Moving BulletMkI where

  velocity = velocity

instance M.Locatable BulletMkI where

  center = center

instance SimpleTransient BulletMkI where

  expired = zeroOrLess . rangeLeft

instance InternallyUpdating BulletMkI where

  preUpdate s t = s { clock = clock s + t }

  postUpdate s t = s { center = a, rangeLeft = r }
    where a = M.newLocation (wrapMap s) (center s) (velocity s) t
          r = max 0 (rangeLeft s - distance (wrapMap s) (center s) a)

instance Damaging BulletMkI where

  damageEnergy _ = damE

instance Transient BulletMkI where

  expired' s = if impacted s || zeroOrLess (rangeLeft s) then Just [] else Nothing

instance Damageable BulletMkI where

  inflictDamage s d = if moreThanZero d then s { impacted = True } else s

-- | Func abstracting construction of 'BulletMkI' projectile
prj :: (M.Moving a)
    => a -- ^ object receiving projectile
    -> (a -> WM) -- ^ func which retrieves WM from object
    -> Angle -- ^ firing angle
    -> Projectile
prj a f b = Projectile (new (f a) b (M.center a) (M.velocity a))