helm-1.0.0: src/Helm/Time.hs
-- | Contains functions for composing units of time and
-- subscriptions to events from the game clock.
module Helm.Time
(
-- * Types
Time
-- * Units
, millisecond
, second
, minute
, hour
, inMilliseconds
, inSeconds
, inMinutes
, inHours
-- * Commands
, now
-- * Subscriptions
, every
, fps
) where
import Control.Monad.State (get)
import Control.Monad.IO.Class (liftIO)
import FRP.Elerea.Param (transfer, input, snapshot, effectful)
import Helm.Engine (Cmd(..), Sub(..), Engine(..))
-- | Represents an amount of time in an arbitary unit.
-- This type can then be composed with the relevant utility functions.
type Time = Double
-- | A time value representing one millisecond.
millisecond :: Time
millisecond = 1
-- | A time value representing one second.
second :: Time
second = 1000
-- | A time value representing one minute.
minute :: Time
minute = 60000
-- | A time value representing one hour.
hour :: Time
hour = 3600000
-- | Converts a time value to a fractional value, in milliseconds.
inMilliseconds :: Time -> Double
inMilliseconds n = n
-- | Converts a time value to a fractional value, in seconds.
inSeconds :: Time -> Double
inSeconds n = n / second
-- | Converts a time value to a fractional value, in minutes.
inMinutes :: Time -> Double
inMinutes n = n / minute
-- | Converts a time value to a fractional value, in hours.
inHours :: Time -> Double
inHours n = n / hour
-- | Map the running time of the engine to a game action.
-- Note that this is not the current clock time but rather the engine time,
-- i.e. when the engine first starts running, the applied value will be zero.
now
:: Engine e
=> (Time -> a) -- ^ The function to map the running time to an action.
-> Cmd e a -- ^ The mapped command.
now f = Cmd $ do
engine <- get
ticks <- liftIO $ f <$> runningTime engine
return [ticks]
-- | Generic subscription for time interval-based events.
every' :: Engine e => (e -> Time -> (Time, [Double]) -> (Time, [Double])) -> (Time -> a) -> Sub e a
every' step f = Sub $ do
engine <- input >>= snapshot
time <- effectful $ runningTime engine
sig <- transfer (0, []) step time
return $ map f . snd <$> sig
-- | Subscribe to the running time of the engine and map to a game action,
-- producing events at a provided interval.
every
:: Engine e
=> Time -- ^ The interval of time to produce events at.
-> (Time -> a) -- ^ The function to map the running time to an action.
-> Sub e a -- ^ The mapped subscription.
every interval = every' step
where
step _ t (lt, _) =
if t - lt >= interval
then (t, [t]) -- Use new t value with t event
else (lt, []) -- Use old t value with no event
-- | Subscribe to events that emit at a provided frames per second and map to a game action,
-- producing events at a provided interval. The time value applied is the delta between
-- the current and last event emission time.
fps
:: Engine e
=> Int -- ^ The frames per second.
-> (Time -> a) -- ^ The function to map the time delta to an action.
-> Sub e a -- ^ The mapped subscription.
fps frames = every' step
where
interval = 1000 / fromIntegral frames
step _ t (lt, _) =
if t - lt >= interval
then (t, [t - lt]) -- Use new t value with t event
else (lt, []) -- Use old t value with no event