animate 0.3.0 → 0.4.0
raw patch · 3 files changed
+56/−60 lines, 3 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
- Animate: data Animations key loc
- Animate: instance Data.Aeson.Types.FromJSON.FromJSON Animate.SpriteSheetInfo
- Animate: instance Data.Aeson.Types.ToJSON.ToJSON Animate.SpriteSheetInfo
- Animate: instance GHC.Classes.Eq Animate.FrameStep
- Animate: instance GHC.Classes.Eq Animate.SpriteSheetInfo
- Animate: instance GHC.Classes.Eq key => GHC.Classes.Eq (Animate.Position key)
- Animate: instance GHC.Classes.Eq loc => GHC.Classes.Eq (Animate.Animations key loc)
- Animate: instance GHC.Classes.Eq loc => GHC.Classes.Eq (Animate.Frame loc)
- Animate: instance GHC.Show.Show Animate.FrameStep
- Animate: instance GHC.Show.Show Animate.SpriteSheetInfo
- Animate: instance GHC.Show.Show key => GHC.Show.Show (Animate.Position key)
- Animate: instance GHC.Show.Show loc => GHC.Show.Show (Animate.Animations key loc)
- Animate: instance GHC.Show.Show loc => GHC.Show.Show (Animate.Frame loc)
- Animate: type DeltaSeconds = Seconds
- Animate: type Seconds = Float
+ Animate: Animations :: Vector (Vector (Frame loc delay)) -> Animations key loc delay
+ Animate: [$sel:fDelay:Frame] :: Frame loc delay -> delay
+ Animate: [$sel:fLocation:Frame] :: Frame loc delay -> loc
+ Animate: [$sel:pCounter:Position] :: Position key delay -> delay
+ Animate: [$sel:pFrameIndex:Position] :: Position key delay -> FrameIndex
+ Animate: [$sel:pKey:Position] :: Position key delay -> key
+ Animate: [$sel:pLoop:Position] :: Position key delay -> Loop
+ Animate: [$sel:scH:SpriteClip] :: SpriteClip -> Int
+ Animate: [$sel:scOffset:SpriteClip] :: SpriteClip -> Maybe (Int, Int)
+ Animate: [$sel:scW:SpriteClip] :: SpriteClip -> Int
+ Animate: [$sel:scX:SpriteClip] :: SpriteClip -> Int
+ Animate: [$sel:scY:SpriteClip] :: SpriteClip -> Int
+ Animate: [$sel:ssAnimations:SpriteSheet] :: SpriteSheet key img delay -> Animations key SpriteClip delay
+ Animate: [$sel:ssImage:SpriteSheet] :: SpriteSheet key img delay -> img
+ Animate: [$sel:ssiAlpha:SpriteSheetInfo] :: SpriteSheetInfo delay -> Maybe Color
+ Animate: [$sel:ssiAnimations:SpriteSheetInfo] :: SpriteSheetInfo delay -> Map Text [(FrameIndex, delay)]
+ Animate: [$sel:ssiClips:SpriteSheetInfo] :: SpriteSheetInfo delay -> [SpriteClip]
+ Animate: [$sel:ssiImage:SpriteSheetInfo] :: SpriteSheetInfo delay -> FilePath
+ Animate: [$sel:unAnimations:Animations] :: Animations key loc delay -> Vector (Vector (Frame loc delay))
+ Animate: instance (GHC.Classes.Eq delay, GHC.Classes.Eq key) => GHC.Classes.Eq (Animate.Position key delay)
+ Animate: instance (GHC.Classes.Eq delay, GHC.Classes.Eq loc) => GHC.Classes.Eq (Animate.Frame loc delay)
+ Animate: instance (GHC.Classes.Eq loc, GHC.Classes.Eq delay) => GHC.Classes.Eq (Animate.Animations key loc delay)
+ Animate: instance (GHC.Show.Show delay, GHC.Show.Show key) => GHC.Show.Show (Animate.Position key delay)
+ Animate: instance (GHC.Show.Show delay, GHC.Show.Show loc) => GHC.Show.Show (Animate.Frame loc delay)
+ Animate: instance (GHC.Show.Show loc, GHC.Show.Show delay) => GHC.Show.Show (Animate.Animations key loc delay)
+ Animate: instance Data.Aeson.Types.FromJSON.FromJSON delay => Data.Aeson.Types.FromJSON.FromJSON (Animate.SpriteSheetInfo delay)
+ Animate: instance Data.Aeson.Types.ToJSON.ToJSON delay => Data.Aeson.Types.ToJSON.ToJSON (Animate.SpriteSheetInfo delay)
+ Animate: instance GHC.Classes.Eq delay => GHC.Classes.Eq (Animate.FrameStep delay)
+ Animate: instance GHC.Classes.Eq delay => GHC.Classes.Eq (Animate.SpriteSheetInfo delay)
+ Animate: instance GHC.Generics.Generic (Animate.Frame loc delay)
+ Animate: instance GHC.Generics.Generic (Animate.FrameStep delay)
+ Animate: instance GHC.Generics.Generic (Animate.Position key delay)
+ Animate: instance GHC.Generics.Generic (Animate.SpriteSheet key img delay)
+ Animate: instance GHC.Generics.Generic (Animate.SpriteSheetInfo delay)
+ Animate: instance GHC.Generics.Generic Animate.Loop
+ Animate: instance GHC.Generics.Generic Animate.SpriteClip
+ Animate: instance GHC.Show.Show delay => GHC.Show.Show (Animate.FrameStep delay)
+ Animate: instance GHC.Show.Show delay => GHC.Show.Show (Animate.SpriteSheetInfo delay)
+ Animate: newtype Animations key loc delay
- Animate: Frame :: loc -> Seconds -> Frame loc
+ Animate: Frame :: loc -> delay -> Frame loc delay
- Animate: FrameStep'Counter :: Seconds -> FrameStep
+ Animate: FrameStep'Counter :: delay -> FrameStep delay
- Animate: FrameStep'Delta :: DeltaSeconds -> FrameStep
+ Animate: FrameStep'Delta :: delay -> FrameStep delay
- Animate: Position :: key -> FrameIndex -> Seconds -> Loop -> Position key
+ Animate: Position :: key -> FrameIndex -> delay -> Loop -> Position key delay
- Animate: SpriteSheet :: Animations key SpriteClip -> img -> SpriteSheet key img
+ Animate: SpriteSheet :: Animations key SpriteClip delay -> img -> SpriteSheet key img delay
- Animate: SpriteSheetInfo :: FilePath -> Maybe Color -> [SpriteClip] -> Map Text [(FrameIndex, Seconds)] -> SpriteSheetInfo
+ Animate: SpriteSheetInfo :: FilePath -> Maybe Color -> [SpriteClip] -> Map Text [(FrameIndex, delay)] -> SpriteSheetInfo delay
- Animate: animations :: Key key => (key -> [Frame loc]) -> Animations key loc
+ Animate: animations :: Key key => (key -> [Frame loc delay]) -> Animations key loc delay
- Animate: currentFrame :: Key key => Animations key loc -> Position key -> Frame loc
+ Animate: currentFrame :: (Num delay, Key key) => Animations key loc delay -> Position key delay -> Frame loc delay
- Animate: currentLocation :: Key key => Animations key loc -> Position key -> loc
+ Animate: currentLocation :: (Num delay, Key key) => Animations key loc delay -> Position key delay -> loc
- Animate: data Frame loc
+ Animate: data Frame loc delay
- Animate: data FrameStep
+ Animate: data FrameStep delay
- Animate: data Position key
+ Animate: data Position key delay
- Animate: data SpriteSheet key img
+ Animate: data SpriteSheet key img delay
- Animate: data SpriteSheetInfo
+ Animate: data SpriteSheetInfo delay
- Animate: framesByAnimation :: Key key => Animations key loc -> key -> Vector (Frame loc)
+ Animate: framesByAnimation :: Key key => Animations key loc delay -> key -> Vector (Frame loc delay)
- Animate: initPosition :: Key key => key -> Position key
+ Animate: initPosition :: (Num delay, Key key) => key -> Position key delay
- Animate: initPositionLoops :: Key key => key -> Int -> Position key
+ Animate: initPositionLoops :: (Num delay, Key key) => key -> Int -> Position key delay
- Animate: initPositionWithLoop :: Key key => key -> Loop -> Position key
+ Animate: initPositionWithLoop :: (Num delay, Key key) => key -> Loop -> Position key delay
- Animate: isAnimationComplete :: Key key => Animations key loc -> Position key -> Bool
+ Animate: isAnimationComplete :: (Key key, Num delay, Ord delay) => Animations key loc delay -> Position key delay -> Bool
- Animate: positionHasLooped :: Position key -> Position key -> Bool
+ Animate: positionHasLooped :: Position key delay -> Position key delay -> Bool
- Animate: readSpriteSheetInfoJSON :: FilePath -> IO SpriteSheetInfo
+ Animate: readSpriteSheetInfoJSON :: FromJSON delay => FilePath -> IO (SpriteSheetInfo delay)
- Animate: readSpriteSheetJSON :: KeyName key => (FilePath -> Maybe Color -> IO img) -> FilePath -> IO (SpriteSheet key img)
+ Animate: readSpriteSheetJSON :: (KeyName key, FromJSON delay) => (FilePath -> Maybe Color -> IO img) -> FilePath -> IO (SpriteSheet key img delay)
- Animate: stepFrame :: Frame loc -> Position key -> DeltaSeconds -> FrameStep
+ Animate: stepFrame :: (Num delay, Ord delay) => Frame loc delay -> Position key delay -> delay -> FrameStep delay
- Animate: stepPosition :: Key key => Animations key loc -> Position key -> DeltaSeconds -> Position key
+ Animate: stepPosition :: (Num delay, Ord delay, Key key) => Animations key loc delay -> Position key delay -> delay -> Position key delay
Files
- animate.cabal +1/−1
- library/Animate.hs +54/−58
- package.yaml +1/−1
animate.cabal view
@@ -3,7 +3,7 @@ -- see: https://github.com/sol/hpack name: animate-version: 0.3.0+version: 0.4.0 synopsis: Animation for sprites description: Prototypical sprite animation with type-safety. category: Game
library/Animate.hs view
@@ -1,10 +1,9 @@+{-# LANGUAGE DeriveGeneric #-} module Animate- ( Seconds- , DeltaSeconds- , Color+ ( Color , FrameIndex , Frame(..)- , Animations+ , Animations(..) , Loop(..) , Position(..) , FrameStep(..)@@ -39,28 +38,23 @@ import Data.Map (Map) import Data.Word (Word8) import Data.Text (Text)---- | Avoided newtype wrapper for convenience-type Seconds = Float---- | Type aliased seconds-type DeltaSeconds = Seconds+import GHC.Generics (Generic) -- | Alias for RGB (8bit, 8bit, 8bit) type Color = (Word8, Word8, Word8) type FrameIndex = Int -data Frame loc = Frame+data Frame loc delay = Frame { fLocation :: loc -- ^ User defined reference to the location of a sprite. For example, a sprite sheet clip.- , fDelay :: Seconds -- ^ Minimium amount of time for the frame to last.- } deriving (Show, Eq)+ , fDelay :: delay -- ^ Minimium amount of units for the frame to last.+ } deriving (Show, Eq, Generic) --- | Type safe animation set. Use an sum type with an `Enum` and `Bounded` instance for the animation, 'a'.-newtype Animations key loc = Animations { unAnimations :: V.Vector (V.Vector (Frame loc)) }+-- | Type safe animation set. Use a sum type with an `Enum` and `Bounded` instance for the animation, @a@.+newtype Animations key loc delay = Animations { unAnimations :: V.Vector (V.Vector (Frame loc delay)) } deriving (Show, Eq) --- | Sematically for an animation key constraint+-- | Semantically for an animation key constraint class (Ord key, Bounded key, Enum key) => Key key -- | Animation Keyframe. `keyName` is used for JSON parsing.@@ -74,7 +68,7 @@ , scW :: Int , scH :: Int , scOffset :: Maybe (Int, Int)- } deriving (Show, Eq)+ } deriving (Show, Eq, Generic) instance ToJSON SpriteClip where toJSON SpriteClip{scX,scY,scW,scH,scOffset} = case scOffset of@@ -92,21 +86,21 @@ return SpriteClip { scX = x, scY = y, scW = w, scH = h, scOffset = Just (ofsX, ofsY) }) -- | Generalized sprite sheet data structure-data SpriteSheet key img = SpriteSheet- { ssAnimations :: Animations key SpriteClip+data SpriteSheet key img delay = SpriteSheet+ { ssAnimations :: Animations key SpriteClip delay , ssImage :: img- }+ } deriving (Generic) -- | One way to represent sprite sheet information.--- | JSON loading is included.-data SpriteSheetInfo = SpriteSheetInfo+-- JSON loading is included.+data SpriteSheetInfo delay = SpriteSheetInfo { ssiImage :: FilePath , ssiAlpha :: Maybe Color , ssiClips :: [SpriteClip]- , ssiAnimations :: Map Text [(FrameIndex, Seconds)]- } deriving (Show, Eq)+ , ssiAnimations :: Map Text [(FrameIndex, delay)]+ } deriving (Show, Eq, Generic) -instance ToJSON SpriteSheetInfo where+instance ToJSON delay => ToJSON (SpriteSheetInfo delay) where toJSON SpriteSheetInfo{ssiImage,ssiAlpha,ssiClips,ssiAnimations} = object [ "image" .= ssiImage , "alpha" .= ssiAlpha@@ -114,7 +108,7 @@ , "animations" .= ssiAnimations ] -instance FromJSON SpriteSheetInfo where+instance FromJSON delay => FromJSON (SpriteSheetInfo delay) where parseJSON (Object o) = do image <- o .: "image" alpha <- o .: "alpha"@@ -124,37 +118,38 @@ parseJSON _ = mzero -- | Generate animations given each constructor-animations :: Key key => (key -> [Frame loc]) -> Animations key loc+animations :: Key key => (key -> [Frame loc delay]) -> Animations key loc delay animations getFrames = Animations $ V.fromList $ map (V.fromList . getFrames) [minBound..maxBound] -- | Lookup the frames of an animation-framesByAnimation :: Key key => Animations key loc -> key -> V.Vector (Frame loc)+framesByAnimation :: Key key => Animations key loc delay -> key -> V.Vector (Frame loc delay) framesByAnimation (Animations as) k = as V.! fromEnum k data Loop = Loop'Always -- ^ Never stop looping. Animation can never be completed. | Loop'Count Int -- ^ Count down loops to below zero. 0 = no loop. 1 = one loop. 2 = two loops. etc.- deriving (Show, Eq)+ deriving (Show, Eq, Generic) -- | State for progression through an animation--- | `example = Position minBound 0 0 Loop'Always`-data Position key = Position+--+-- > example = Position minBound 0 0 Loop'Always+data Position key delay = Position { pKey :: key -- ^ Index for the animation. , pFrameIndex :: FrameIndex -- ^ Index wihin the animation. WARNING: Modifying to below zero or equal-to-or-greater-than-the-frame-count will throw out of bounds errors.- , pCounter :: Seconds -- ^ Accumulated seconds to end of the frame. Will continue to compound if animation is completed.+ , pCounter :: delay -- ^ Accumulated units to end of the frame. Will continue to compound if animation is completed. , pLoop :: Loop -- ^ How to loop through an animation. Loop'Count is a count down.- } deriving (Show, Eq)+ } deriving (Show, Eq, Generic) -- | New `Position` with its animation key to loop forever-initPosition :: Key key => key -> Position key+initPosition :: (Num delay, Key key) => key -> Position key delay initPosition key = initPositionWithLoop key Loop'Always -- | New `Position` with its animation key with a limited loop-initPositionLoops :: Key key => key -> Int -> Position key+initPositionLoops :: (Num delay, Key key) => key -> Int -> Position key delay initPositionLoops key count = initPositionWithLoop key (Loop'Count count) -- | New `Position`-initPositionWithLoop :: Key key => key -> Loop -> Position key+initPositionWithLoop :: (Num delay, Key key) => key -> Loop -> Position key delay initPositionWithLoop key loop = Position { pKey = key , pFrameIndex = 0@@ -163,20 +158,20 @@ } -- | You can ignore. An intermediate type for `stepPosition` to judge how to increment the current frame.-data FrameStep- = FrameStep'Counter Seconds -- ^ New counter to compare against the frame's delay.- | FrameStep'Delta DeltaSeconds -- ^ How much delta to carry over into the next frame.- deriving (Show, Eq)+data FrameStep delay+ = FrameStep'Counter delay -- ^ New counter to compare against the frame's delay.+ | FrameStep'Delta delay -- ^ How much delta to carry over into the next frame.+ deriving (Show, Eq, Generic) -- | Intermediate function for how a frame should be step through.-stepFrame :: Frame loc -> Position key -> DeltaSeconds -> FrameStep+stepFrame :: (Num delay, Ord delay) => Frame loc delay -> Position key delay -> delay -> FrameStep delay stepFrame Frame{fDelay} Position{pCounter} delta = if pCounter + delta >= fDelay then FrameStep'Delta $ pCounter + delta - fDelay else FrameStep'Counter $ pCounter + delta -- | Step through the animation resulting a new position.-stepPosition :: Key key => Animations key loc -> Position key -> DeltaSeconds -> Position key+stepPosition :: (Num delay, Ord delay, Key key) => Animations key loc delay -> Position key delay -> delay -> Position key delay stepPosition as p d = case frameStep of FrameStep'Counter counter -> p{pCounter = counter }@@ -196,16 +191,16 @@ , pLoop = Loop'Count n' } -- | Use the position to find the current frame of the animation.-currentFrame :: Key key => Animations key loc -> Position key -> Frame loc+currentFrame :: (Num delay, Key key) => Animations key loc delay -> Position key delay -> Frame loc delay currentFrame anis Position{pKey,pFrameIndex} = (framesByAnimation anis pKey) V.! pFrameIndex -- | Use the position to find the current location, lik a sprite sheet clip, of the animation.-currentLocation :: Key key => Animations key loc -> Position key -> loc+currentLocation :: (Num delay, Key key) => Animations key loc delay -> Position key delay -> loc currentLocation anis p = fLocation (currentFrame anis p) -- | The animation has finished all its frames. Useful for signalling into switching to another animation. -- With a Loop'Always, the animation will never be completed.-isAnimationComplete :: Key key => Animations key loc -> Position key -> Bool+isAnimationComplete :: (Key key, Num delay, Ord delay) => Animations key loc delay -> Position key delay -> Bool isAnimationComplete as p = case pLoop p of Loop'Always -> False Loop'Count n -> n < 0 && pFrameIndex p == lastIndex && pCounter p >= fDelay lastFrame@@ -214,41 +209,42 @@ lastIndex = V.length frames - 1 lastFrame = frames V.! lastIndex --- | Cycle through the next animation key+-- | Cycle through the next animation key. nextKey :: Key key => key -> key nextKey key = if key == maxBound then minBound else succ key --- | Cycle through the previous animation key+-- | Cycle through the previous animation key. prevKey :: Key key => key -> key prevKey key = if key == minBound then maxBound else pred key --- | Simple function diff'ing the position for loop change+-- | Simple function diff'ing the position for loop change. positionHasLooped- :: Position key -- ^ Previous- -> Position key -- ^ Next+ :: Position key delay -- ^ Previous+ -> Position key delay -- ^ Next -> Bool positionHasLooped Position{ pLoop = Loop'Count c } Position{ pLoop = Loop'Count c' } = c > c' positionHasLooped Position{ pLoop = Loop'Always } _ = False positionHasLooped _ Position{ pLoop = Loop'Always } = False -- | Quick function for loading `SpriteSheetInfo`.--- | Check the example.+-- Check the example. readSpriteSheetInfoJSON- :: FilePath -- ^ Path of the sprite sheet info JSON file- -> IO SpriteSheetInfo+ :: FromJSON delay+ => FilePath -- ^ Path of the sprite sheet info JSON file+ -> IO (SpriteSheetInfo delay) readSpriteSheetInfoJSON path = do metaBytes <- BL.readFile path case eitherDecode metaBytes of Left _err -> error $ "Cannot parse Sprite Sheet Info \"" ++ path ++ "\"" Right ssi -> return ssi --- | Quick function for loading `SpriteSheetInfo`, then using it to load its image for a `SpriteSheet`--- | Check the example.+-- | Quick function for loading `SpriteSheetInfo`, then using it to load its image for a `SpriteSheet`.+-- Check the example. readSpriteSheetJSON- :: KeyName key- => (FilePath -> Maybe Color -> IO img) -- ^ Inject animage loading function+ :: (KeyName key, FromJSON delay)+ => (FilePath -> Maybe Color -> IO img) -- ^ Inject an image loading function -> FilePath -- ^ Path of the sprite sheet info JSON file- -> IO (SpriteSheet key img)+ -> IO (SpriteSheet key img delay) readSpriteSheetJSON loadImage infoPath = do SpriteSheetInfo{ssiImage, ssiClips, ssiAnimations, ssiAlpha} <- readSpriteSheetInfoJSON infoPath i <- loadImage ssiImage ssiAlpha
package.yaml view
@@ -1,5 +1,5 @@ name: animate-version: '0.3.0'+version: '0.4.0' category: Game synopsis: Animation for sprites description: Prototypical sprite animation with type-safety.