From 45a103da2133b645fac9617cc97c11901d3e258f Mon Sep 17 00:00:00 2001 From: "Juan J. Martinez" Date: Fri, 10 Mar 2023 23:53:40 +0000 Subject: Change stage --- src/Game.hs | 39 +++++++++++++++++++++++++++++++++++---- src/Game/Entities.hs | 1 + src/Game/Entities/Exit.hs | 20 ++++++++++++++------ src/Game/Entities/Types.hs | 2 +- src/Game/Hud.hs | 13 ++++++++----- src/Game/State.hs | 4 +++- 6 files changed, 62 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/Game.hs b/src/Game.hs index 31aa40b..7951d09 100644 --- a/src/Game.hs +++ b/src/Game.hs @@ -36,12 +36,17 @@ windowWidth, windowHeight :: CInt version :: String version = "0.1.0" +-- XXX: placeholder for the map list, perhaps should be loaded from a JSON +maps :: [String] +maps = ["data/map1.json", "data/map2.json"] + data Env = Env { window :: SDL.Window, renderer :: SDL.Renderer, canvas :: SDL.Texture, fullscreen :: Bool, renderRect :: SDL.Rectangle CInt, + tsTexture :: SDL.Texture, map :: M.Map, sprites :: S.SpriteSheet, font :: BF.BitmapFont, @@ -65,7 +70,22 @@ initialState m = gameOverDelay = 0, exit = False, -- doesn't matter where - lastBattery = (0, 0) + lastBattery = (0, 0), + levelCompleted = False, + currentLevel = 0 + } + +levelState :: GS.State -> M.Map -> GS.State +levelState s m = + s + { GS.batteries = 0, + GS.totalBatteries = M.totalBatteries m, + GS.hitDelay = hitDelay, + GS.gameOverDelay = 0, + GS.exit = False, + -- doesn't matter where + GS.lastBattery = (0, 0), + GS.levelCompleted = False } main :: IO () @@ -88,12 +108,12 @@ main = do tsTexture <- SDL.Image.loadTexture renderer "data/tiles.png" ssTexture <- SDL.Image.loadTexture renderer "data/sprites.png" bfTexture <- SDL.Image.loadTexture renderer "data/font.png" - map' <- M.load "data/map.json" tsTexture + map' <- M.load (head maps) tsTexture sprites <- S.load "data/sprites.json" ssTexture font <- BF.load "data/font.json" bfTexture controls <- newIORef C.init entities <- E.mkEntities sprites map' controls - hud <- H.mkHud sprites + hud <- H.mkHud sprites font gameLoop Env { window = window, @@ -101,6 +121,7 @@ main = do canvas = canvas, fullscreen = False, renderRect = defaultRenderRect, + tsTexture = tsTexture, map = map', sprites = sprites, font = font, @@ -178,6 +199,15 @@ gameLoop e = do | state.batteries == state.totalBatteries && not state.exit = do es <- E.addExit env.entities x (y - 8) -- adjusted to player's height pure env {entities = es, state = state {GS.exit = True}} + | state.levelCompleted = do + map' <- M.load (maps !! (env.state.currentLevel + 1)) env.tsTexture + entities <- E.mkEntities env.sprites map' env.controls + pure $ + env + { map = map', + state = (levelState env.state map') {GS.currentLevel = env.state.currentLevel + 1}, + entities = entities + } | otherwise = pure env where state = env.state @@ -223,7 +253,8 @@ gameOverLoop e = do then do -- retry last level entities <- E.mkEntities sprites map' controls - pure e {state = initialState map', entities = entities} + pure + e {state = (levelState e.state map') {GS.lives = maxLives}, entities = entities} else do H.render renderer hud state title <- S.get sprites "game-over" diff --git a/src/Game/Entities.hs b/src/Game/Entities.hs index 21b6ba5..bd9729b 100644 --- a/src/Game/Entities.hs +++ b/src/Game/Entities.hs @@ -98,6 +98,7 @@ updateAll es state = do ents ) processActions s' ents' t + ActionExitLevel -> processActions s {GS.levelCompleted = True} ents t processActions s ents [] = pure (s, ents) -- Update entities skipping enemies if the player was hit diff --git a/src/Game/Entities/Exit.hs b/src/Game/Entities/Exit.hs index 075e1f4..12f160d 100644 --- a/src/Game/Entities/Exit.hs +++ b/src/Game/Entities/Exit.hs @@ -19,13 +19,21 @@ mkExit sprites x y playerCollision = do gravity = gravityOff, dir = DirRight, sprite = s, - update = pure . updateExit playerCollision, + update = updateExit playerCollision, destroy = False, actions = [] } -updateExit :: Collision -> Entity -> Entity -updateExit _ e - | e.delay > 0 = e {delay = e.delay - 1} - | e.frame + 1 < frameLimit e = e {delay = frameDelay, frame = e.frame + 1} - | otherwise = e {delay = frameDelay, frame = 7} +updateExit :: Collision -> Entity -> IO Entity +updateExit touchedPlayer e = do + touched <- if e.frame < fullyOpen then pure False else touchedPlayer e + pure $ if touched then e {destroy = True, actions = [ActionExitLevel]} else update + where + fullyOpen :: Int + fullyOpen = 7 + + update :: Entity + update + | e.delay > 0 = e {delay = e.delay - 1} + | e.frame + 1 < frameLimit e = e {delay = frameDelay, frame = e.frame + 1} + | otherwise = e {delay = frameDelay, frame = fullyOpen} diff --git a/src/Game/Entities/Types.hs b/src/Game/Entities/Types.hs index 64b4637..392a86f 100644 --- a/src/Game/Entities/Types.hs +++ b/src/Game/Entities/Types.hs @@ -29,7 +29,7 @@ data Entities = Entities -- | The effect name must match the sprite name in the spritesheet. type EffectName = String -data Action = ActionAddEffect Int Int EffectName | ActionAddBattery Int Int | ActionHitPlayer +data Action = ActionAddEffect Int Int EffectName | ActionAddBattery Int Int | ActionHitPlayer | ActionExitLevel data Entity = Entity { typ :: Type, diff --git a/src/Game/Hud.hs b/src/Game/Hud.hs index a5d3e22..c4d5234 100644 --- a/src/Game/Hud.hs +++ b/src/Game/Hud.hs @@ -1,5 +1,6 @@ module Game.Hud (Hud, mkHud, render, height) where +import qualified Game.BitmapFont as BM import qualified Game.Sprites as S import qualified Game.State as GS import qualified SDL @@ -7,16 +8,18 @@ import qualified SDL height :: Int height = 16 -newtype Hud = Hud S.Sprite +data Hud = Hud S.Sprite BM.BitmapFont -mkHud :: S.SpriteSheet -> IO Hud -mkHud sprites = do - Hud <$> S.get sprites "hud" +mkHud :: S.SpriteSheet -> BM.BitmapFont -> IO Hud +mkHud sprites font = do + sprite <- S.get sprites "hud" + pure $ Hud sprite font render :: SDL.Renderer -> Hud -> GS.State -> IO () -render renderer (Hud sprite) state = do +render renderer (Hud sprite font) state = do let xs = [0 .. state.totalBatteries - 1] in mapM_ (\x -> S.render renderer sprite (4 + x * 8) 4 0 (if state.batteries <= x then 0 else 1)) xs let xs = [0 .. state.totalLives - 1] in -- magic numbers mapM_ (\x -> S.render renderer sprite (320 - 4 - state.totalLives * 8 + x * 8) 4 0 (if state.lives <= x then 2 else 3)) xs + BM.renderText renderer font 140 4 $ "Stage " ++ show (state.currentLevel + 1) diff --git a/src/Game/State.hs b/src/Game/State.hs index 840c0ae..e05fb61 100644 --- a/src/Game/State.hs +++ b/src/Game/State.hs @@ -8,5 +8,7 @@ data State = State hitDelay :: Int, gameOverDelay :: Int, exit :: Bool, - lastBattery :: (Int, Int) + lastBattery :: (Int, Int), + levelCompleted :: Bool, + currentLevel :: Int } -- cgit v1.2.3