diff options
Diffstat (limited to 'lib/Grav2ty/Core.hs')
-rw-r--r-- | lib/Grav2ty/Core.hs | 52 |
1 files changed, 44 insertions, 8 deletions
diff --git a/lib/Grav2ty/Core.hs b/lib/Grav2ty/Core.hs index f4b872c..e4bd9b6 100644 --- a/lib/Grav2ty/Core.hs +++ b/lib/Grav2ty/Core.hs @@ -2,6 +2,7 @@ module Grav2ty.Core ( -- * Basic Types Id (..) + , Tick (..) , World (..) -- ** Object , Object (..) @@ -19,14 +20,14 @@ module Grav2ty.Core , zeroModification -- * The Grav2ty Monad , Grav2ty (..) + -- ** State + , Grav2tyState (..) + , tick, timePerTick, inputs, graphics, world, highestId + -- ** Operations , setObject , getObject , addObject , delObject - -- ** State - , Grav2tyState (..) - , tick, timePerTick, inputs, graphics, world, highestId - , Tick (..) ) where import Control.Lens @@ -35,9 +36,15 @@ import Data.Map.Strict (Map (..)) import qualified Data.Map.Strict as M import Linear.V2 +-- | Identifier used for 'Object's in 'World'. type Id = Integer + +-- | A tick is a simulation step. This type represents the ascending number of simulation steps. type Tick = Integer +-- | The 'Object's are stored in a strict 'Map'. We need to access all Objects relatively frequently +-- and also add 'Object's from time to time as well as access 'Object's by their 'Id'. 'Map' +-- seems to provide a good compromise in terms of performance for these operations. type World a = Map Id (Object a) data Modifier @@ -52,10 +59,16 @@ data Modifier -- are disabled for the particular 'Object'. type Cannon a = Maybe (V2 a, V2 a) +-- | Objects come in two flavors: 'Static' Objects don't change in the course +-- of the simulation, but will influence other Objects either by collision +-- or gravity. They also can never be destroyed. +-- +-- 'Dynamic' objects are affected by physics and are destroyed on collision. +-- They also may be controlled by a player depending on their 'Modifier'. data Object a = Dynamic { objectHitbox :: Hitbox a -- ^ hitbox of the object. Hitbox points at - -- (V2 0 0) will always be at the center of + -- @(V2 0 0)@ will always be at the center of -- the object , objectRot :: a -- ^ Radial angle , objectMass :: a -- ^ mass of the object in kg @@ -83,6 +96,15 @@ isDynamic :: Object a -> Bool isDynamic Dynamic {} = True isDynamic _ = False +-- | Hitboxes are the basis for collision detection and also may be +-- used as a basis for the graphical representation of 'Object's, +-- although they probably should be replaced by a more appealing +-- alternative. +-- +-- They can be combined from lines and circles and are always +-- centered around position of the corresponding 'Object', +-- i. e. @V2 0 0@ of the Hitbox is always at the center of +-- the object. Also they naturally rotate with the object. data Hitbox a = HCombined [Hitbox a] | HLine @@ -106,18 +128,24 @@ shipHitbox = HCombined centeredCircle :: Num a => a -> Hitbox a centeredCircle = HCircle (V2 0 0) +-- | A Modification contains the attributes of an Object that can +-- be controlled by a player: Rotation, acceleration and firing +-- of projectiles. data Modification a = Modification { _modRot :: a -- ^ Rotation (angle in radiant) set by the modification , _modAcc :: a -- ^ Acceleration set by the modification - , _modFire :: Integer -- ^ Set to tick a projectile should be fired at + , _modFire :: Integer -- ^ Tick a projectile should be fired at } deriving (Show, Eq, Ord) makeLenses ''Modification +-- | 'Modification' that represents the default state of an 'Object'. zeroModification :: Num a => Modification a zeroModification = Modification 0 0 (-1) +-- | Used to store the 'Modification's for every controllable 'Object' +-- that is being simulated. type ModMap a = Map Modifier (Modification a) data Grav2tyState a g = Grav2tyState @@ -125,8 +153,9 @@ data Grav2tyState a g = Grav2tyState , _timePerTick :: a -- ^ The time between two 'Tick's. , _inputs :: ModMap a -- ^ 'Modification's that have to be processed in the next tick. , _graphics :: g -- ^ Graphics state. Use @()@ if non-graphical. - , _world :: World a - , _highestId :: Id + , _world :: World a -- ^ All objects. + , _highestId :: Id -- ^ Highest 'Id' used in 'World'. This is updated by 'addObject' + -- in Order to prevent accidental overwrites. } deriving (Show, Eq) makeLenses ''Grav2tyState @@ -134,9 +163,13 @@ makeLenses ''Grav2tyState -- | The 'Grav2ty' Monad is a renamed 'StateT' holding a 'Grav2tyState'. type Grav2ty p g m a = StateT (Grav2tyState p g) m a +-- | Shortcut for @'setObject' Nothing@. addObject :: Monad m => Object a -> Grav2ty a g m () addObject = setObject Nothing +-- | setObject overwrites or sets the 'Object' at the given 'Id'. +-- If no 'Id' is given it picks a new 'Id' using '_highestId' +-- that is guaranteed to be unused (if nothing messed with the 'World'). setObject :: Monad m => Maybe Id -> Object a -> Grav2ty a g m () setObject id obj = do id <- case id of @@ -146,8 +179,11 @@ setObject id obj = do use highestId world %= M.insert id obj +-- | Returns the 'Object' at 'Id'. getObject :: Monad m => Id -> Grav2ty a g m (Maybe (Object a)) getObject id = use (world.at id) +-- | Deletes the 'Object' at 'Id'. Note: This doesn't influence '_highestId' +-- which only ever increases. delObject :: Monad m => Id -> Grav2ty a g m () delObject id = world %= M.delete id |