From b9578c2a2c60d75c4a4d4519f10b99703ee5ea27 Mon Sep 17 00:00:00 2001 From: "Juan J. Martinez" Date: Sun, 5 Feb 2023 23:18:30 +0000 Subject: Swpan new entities - Each entity can generate a list of "spawns" (add a new entity) - Added a "dust" effect to the jump WIP TODO: probably wrap the entity list in a type so we don't need to pass the spritesheet to the update function. --- src/Game/Entities.hs | 41 +++++++++++++++++++++++++++++++++++------ 1 file changed, 35 insertions(+), 6 deletions(-) (limited to 'src/Game') diff --git a/src/Game/Entities.hs b/src/Game/Entities.hs index bd11235..0cfdb47 100644 --- a/src/Game/Entities.hs +++ b/src/Game/Entities.hs @@ -1,4 +1,4 @@ -module Game.Entities (Entity (..), toSpriteSet, mkPlayer, render) where +module Game.Entities (Entity (..), toSpriteSet, mkPlayer, mkEffect, update, render) where import Data.IORef import qualified Game.Controller as C @@ -7,7 +7,7 @@ import qualified SDL data Dir = DirRight | DirLeft deriving (Eq) -data Type = TypePlayer -- \| TypeEnemy | TypeItem +data Type = TypePlayer | TypeEffect toSpriteSet :: Dir -> Int toSpriteSet DirRight = 0 @@ -31,6 +31,8 @@ gravityDown = 16 gravityTable :: [Int] gravityTable = [0, 6, 4, 4, 2, 2, 2, 2, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 2, 4] +data Spawn = DustEffectSpawn Int Int + data Entity = Entity { eType :: Type, eX :: Int, @@ -43,23 +45,40 @@ data Entity = Entity eSprite :: S.Sprite, eUpdate :: Entity -> IO Entity, eBlocked :: Int -> Int -> Bool, - eDestroy :: Bool + eDestroy :: Bool, + eSpawns :: [Spawn] } +mkEffect :: S.SpriteSheet -> Int -> Int -> String -> IO Entity +mkEffect sprites x y name = do + s <- S.get sprites name + pure $ Entity TypeEffect x y frameDelay 0 3 gravityOff DirRight s (pure . updateEffect) (\_ _ -> False) False [] + +updateEffect :: Entity -> Entity +updateEffect e + | delay > 0 = e {eDelay = delay - 1} + | frame + 1 < frameLimit = e {eDelay = frameDelay, eFrame = frame + 1} + | otherwise = e {eDestroy = True} + where + frame = eFrame e + frameLimit = eFrameLimit e + delay = eDelay e + mkPlayer :: S.SpriteSheet -> Int -> Int -> IORef C.Controls -> (Int -> Int -> Bool) -> IO Entity mkPlayer sprites x y controls isBlocked = do s <- S.get sprites "player" - pure $ Entity TypePlayer x y 0 0 3 gravityOff DirRight s (updatePlayer controls) isBlocked False + pure $ Entity TypePlayer x y 0 0 3 gravityOff DirRight s (updatePlayer controls) isBlocked False [] updateFrame :: Bool -> Entity -> Entity updateFrame updated e | isGravityOn = e | delay > 0 = e {eDelay = delay - 1} - | frame < eFrameLimit e = e {eDelay = frameDelay, eFrame = if updated then frame + 1 else 0} + | frame < frameLimit = e {eDelay = frameDelay, eFrame = if updated then frame + 1 else 0} | otherwise = e {eDelay = frameDelay, eFrame = 0} where isGravityOn = eGravity e > gravityOff frame = eFrame e + frameLimit = eFrameLimit e delay = eDelay e updateHorizontal :: Bool -> Bool -> Entity -> Entity @@ -84,7 +103,7 @@ updateHorizontal left right e updateVertical :: Bool -> Bool -> Entity -> Entity updateVertical jump down e | not jump || gravity /= gravityOff = e - | not down = e {eGravity = gravityUp, eFrame = jumpFrame} + | not down = e {eGravity = gravityUp, eFrame = jumpFrame, eSpawns = events ++ [DustEffectSpawn x (y + 8)]} -- go down a 8 pixel tall platform; not ideal to have these values hardcoded here -- but to be fair, the player height/width is hardcoded as well | down @@ -97,6 +116,7 @@ updateVertical jump down e y = eY e gravity = eGravity e isBlocked = eBlocked e + events = eSpawns e applyGravity :: Int -> Entity -> Entity applyGravity v e @@ -138,6 +158,15 @@ updatePlayer controls e = do -- left or right, but not both (keyboard) updateFrame ((C.cLeft ctl || C.cRight ctl) && (C.cLeft ctl /= C.cRight ctl)) e +processSpawn :: S.SpriteSheet -> Spawn -> IO Entity +processSpawn sprites (DustEffectSpawn x y) = mkEffect sprites x y "dust" + +update :: S.SpriteSheet -> [Entity] -> IO [Entity] +update sprites entities = do + updated <- traverse (\e -> eUpdate e e) entities + new <- traverse (processSpawn sprites) (concatMap eSpawns updated) + pure $ map (\e -> e {eSpawns = []}) (filter (not . eDestroy) updated) ++ new + render :: SDL.Renderer -> Entity -> IO () render renderer ent = S.render renderer sp x y set frame -- cgit v1.2.3