aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJuan J. Martinez <jjm@usebox.net>2023-02-25 13:50:04 +0000
committerJuan J. Martinez <jjm@usebox.net>2023-02-25 13:50:04 +0000
commit2f40109ab69892c7b7812fdbba3a83dc3ca96193 (patch)
treedb3a61adae19487c15f5977befd918a5fb213c9b
parente066422b950a06873efb6a884b47155c867b7acf (diff)
downloadspace-plat-hs-2f40109ab69892c7b7812fdbba3a83dc3ca96193.tar.gz
space-plat-hs-2f40109ab69892c7b7812fdbba3a83dc3ca96193.zip
Game over sequence WIP
-rw-r--r--data/sprites.json6
-rw-r--r--data/sprites.pngbin13384 -> 15083 bytes
-rw-r--r--src/Game.hs72
-rw-r--r--src/Game/Entities/Common.hs5
-rw-r--r--src/Game/Entities/Const.hs3
-rw-r--r--src/Game/State.hs3
6 files changed, 72 insertions, 17 deletions
diff --git a/data/sprites.json b/data/sprites.json
index 844a796..61c751e 100644
--- a/data/sprites.json
+++ b/data/sprites.json
@@ -1,4 +1,10 @@
{
+ "game-over": {
+ "frames": [
+ { "x": 0, "y": 224, "width": 96, "height": 16 }
+ ],
+ "sets": [[0]]
+ },
"player": {
"frames": [
{ "x": 0, "y": 0, "width": 16, "height": 24 },
diff --git a/data/sprites.png b/data/sprites.png
index ee25de5..d2beccd 100644
--- a/data/sprites.png
+++ b/data/sprites.png
Binary files differ
diff --git a/src/Game.hs b/src/Game.hs
index f04acc6..4f84ad1 100644
--- a/src/Game.hs
+++ b/src/Game.hs
@@ -8,15 +8,16 @@ import Foreign.C.Types (CInt)
import qualified Game.BitmapFont as BF
import qualified Game.Controller as C
import qualified Game.Entities as E
+import Game.Entities.Const (gameOverDelay)
import qualified Game.Hud as H
import qualified Game.Map as M
import qualified Game.Sprites as S
import qualified Game.State as GS
-import Game.Utils (isPressed)
+import qualified Game.Utils as U
import SDL (($=), ($~))
import qualified SDL
import qualified SDL.Image
-import SDL.Vect (V2 (..))
+import SDL.Vect (V2 (..), V4 (..))
name :: String
name = "Haskell gamedev [Space Platformer]"
@@ -87,7 +88,8 @@ main = do
totalBatteries = M.totalBatteries map',
lives = maxLives,
totalLives = maxLives,
- hitDelay = 0
+ hitDelay = 0,
+ gameOverDelay = 0
}
hud <- H.mkHud sprites state
entities <- newIORef =<< E.mkEntities sprites map' controls state
@@ -142,17 +144,15 @@ gameLoop = do
canvas = env.canvas
renderRect = env.renderRect
controls = env.controls
- map' = env.map
- entities = env.entities
- hud = env.hud
+ stateRef = env.state
events <- map SDL.eventPayload <$> SDL.pollEvents
-- F11 for fullscreen / windowed
- when (fromMaybe False $ isPressed SDL.KeycodeF11 events) toggleFullscreen
+ when (fromMaybe False $ U.isPressed SDL.KeycodeF11 events) toggleFullscreen
-- ESC or close the window to quit
- let quit = fromMaybe False (isPressed SDL.KeycodeEscape events) || SDL.QuitEvent `elem` events
+ let quit = fromMaybe False (U.isPressed SDL.KeycodeEscape events) || SDL.QuitEvent `elem` events
unless quit $ do
-- update controls
controls $~ flip C.update events
@@ -160,14 +160,14 @@ gameLoop = do
SDL.rendererRenderTarget renderer $= Just canvas
SDL.clear renderer
- updated <- liftIO $ E.updateAll =<< readIORef entities
- entities $= updated
-
- -- render map and entities
void $ liftIO $ do
- M.render renderer map'
- H.render renderer hud
- E.render renderer updated
+ state <- readIORef stateRef
+ if state.lives > 0
+ then playLoop env
+ else
+ if state.gameOverDelay > 0
+ then fadeOutLoop env state.gameOverDelay >> stateRef $= state {GS.gameOverDelay = state.gameOverDelay - 1}
+ else gameOverLoop env
SDL.rendererRenderTarget renderer $= Nothing
SDL.clear renderer
@@ -177,3 +177,45 @@ gameLoop = do
SDL.present renderer
gameLoop
+ where
+ playLoop :: Env -> IO ()
+ playLoop env = do
+ let renderer = env.renderer
+ map' = env.map
+ entities = env.entities
+ hud = env.hud
+
+ updated <- E.updateAll =<< readIORef entities
+ entities $= updated
+
+ -- render map and entities
+ void $ do
+ M.render renderer map'
+ H.render renderer hud
+ E.render renderer updated
+
+ fadeOutLoop :: Env -> Int -> IO ()
+ fadeOutLoop env i = do
+ let renderer = env.renderer
+ map' = env.map
+ entities = env.entities
+ hud = env.hud
+
+ -- render map and entities
+ -- doing a fade to black
+ void $ do
+ M.render renderer map'
+ H.render renderer hud
+ E.render renderer =<< readIORef entities
+
+ SDL.rendererDrawBlendMode renderer $= SDL.BlendAlphaBlend
+ SDL.rendererDrawColor renderer $= V4 0 0 0 (fromIntegral (255 - i * (255 `div` gameOverDelay)))
+ SDL.fillRect renderer Nothing
+
+ gameOverLoop :: Env -> IO ()
+ gameOverLoop env = do
+ let renderer = env.renderer
+ sprites = env.sprites
+
+ title <- S.get sprites "game-over"
+ S.render renderer title 112 80 0 0
diff --git a/src/Game/Entities/Common.hs b/src/Game/Entities/Common.hs
index 2a0c6f1..251dbb4 100644
--- a/src/Game/Entities/Common.hs
+++ b/src/Game/Entities/Common.hs
@@ -43,7 +43,10 @@ hitPlayer stateRef =
stateRef $~ updatePlayerHit
where
updatePlayerHit :: GS.State -> GS.State
- updatePlayerHit s = s {GS.lives = s.lives - 1, GS.hitDelay = hitDelay}
+ updatePlayerHit s
+ -- if we run out of lives, trigger the game over
+ | s.lives == 1 = s {GS.lives = 0, GS.gameOverDelay = gameOverDelay}
+ | otherwise = s {GS.lives = s.lives - 1, GS.hitDelay = hitDelay}
-- | Update game state to reflect that the player picked up a battery.
collectedBattery :: IORef GS.State -> IO ()
diff --git a/src/Game/Entities/Const.hs b/src/Game/Entities/Const.hs
index 4855e24..a24c304 100644
--- a/src/Game/Entities/Const.hs
+++ b/src/Game/Entities/Const.hs
@@ -3,6 +3,9 @@ module Game.Entities.Const where
hitDelay :: Int
hitDelay = 96
+gameOverDelay :: Int
+gameOverDelay = 96
+
frameDelay :: Int
frameDelay = 6
diff --git a/src/Game/State.hs b/src/Game/State.hs
index d943ac0..f8b5721 100644
--- a/src/Game/State.hs
+++ b/src/Game/State.hs
@@ -5,5 +5,6 @@ data State = State
totalBatteries :: Int,
lives :: Int,
totalLives :: Int,
- hitDelay :: Int
+ hitDelay :: Int,
+ gameOverDelay :: Int
}