aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJuan J. Martinez <jjm@usebox.net>2023-03-11 23:17:21 +0000
committerJuan J. Martinez <jjm@usebox.net>2023-03-11 23:17:21 +0000
commit897bfe0f72ddc80a020a421cbe987b54716e571e (patch)
tree4fefcc434abf0e0699f40276efefa71a802457b5
parentedc6b611de752a224082583cd00d19ee6da04c5e (diff)
downloadspace-plat-hs-897bfe0f72ddc80a020a421cbe987b54716e571e.tar.gz
space-plat-hs-897bfe0f72ddc80a020a421cbe987b54716e571e.zip
Exit transition
-rw-r--r--data/sprites.json6
-rw-r--r--data/sprites.pngbin17881 -> 18016 bytes
-rw-r--r--src/Game.hs2
-rw-r--r--src/Game/Entities.hs18
-rw-r--r--src/Game/Entities/Common.hs2
-rw-r--r--src/Game/Entities/Exit.hs19
-rw-r--r--src/Game/Entities/Types.hs4
-rw-r--r--src/Game/State.hs10
8 files changed, 41 insertions, 20 deletions
diff --git a/data/sprites.json b/data/sprites.json
index 2ee7663..182ef35 100644
--- a/data/sprites.json
+++ b/data/sprites.json
@@ -100,11 +100,13 @@
{ "x": 16, "y": 184, "width": 16, "height": 24 },
{ "x": 32, "y": 184, "width": 16, "height": 24 },
{ "x": 48, "y": 184, "width": 16, "height": 24 },
- { "x": 64, "y": 184, "width": 16, "height": 24 }
+ { "x": 64, "y": 184, "width": 16, "height": 24 },
+ { "x": 80, "y": 184, "width": 16, "height": 24 }
],
"sets": [
[0, 1, 2, 3, 4, 5, 5,
- 6, 7, 8, 9, 10, 10, 10, 10, 10, 10, 10]
+ 6, 7, 8, 9, 10, 10, 10, 10, 10, 10, 10],
+ [11, 11, 5, 4, 3, 2, 1, 0]
]
}
}
diff --git a/data/sprites.png b/data/sprites.png
index efe1560..c3c2826 100644
--- a/data/sprites.png
+++ b/data/sprites.png
Binary files differ
diff --git a/src/Game.hs b/src/Game.hs
index 8c416e3..be34a08 100644
--- a/src/Game.hs
+++ b/src/Game.hs
@@ -166,7 +166,7 @@ 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
+ | state.levelCompleted == GS.ExitDone = do
map' <- M.load (maps !! (env.state.currentLevel + 1)) env.tsTexture
entities <- E.mkEntities env.sprites map' env.controls
pure $
diff --git a/src/Game/Entities.hs b/src/Game/Entities.hs
index b53e4e3..8a939f4 100644
--- a/src/Game/Entities.hs
+++ b/src/Game/Entities.hs
@@ -60,8 +60,8 @@ addExit es x y = do
updateAll :: Entities -> GS.State -> IO (Entities, GS.State)
updateAll es state = do
- -- update the player first (including the reference)
- updatedPlayer <- player.update player
+ -- update the player first (including the reference), unless the level is completed
+ updatedPlayer <- if state.levelCompleted /= GS.ExitOff then pure player else player.update player
void $ writeIORef es.player updatedPlayer
-- then the other entities
updated <- (updatedPlayer :) <$> traverse (updateFilter $ state.hitDelay > 0) others
@@ -91,14 +91,21 @@ updateAll es state = do
if s.lives == 1
then
( s {GS.lives = 0, GS.gameOverDelay = gameOverDelay},
- (head ents) {dir = Dying, gravity = gravityUp, frame = 0} : tail ents
+ -- the player is not in the action, changing then type disables collision detection
+ (head ents) {typ = TypeEffect, dir = Dying, gravity = gravityUp, frame = 0} : tail ents
)
else
( s {GS.lives = s.lives - 1, GS.hitDelay = hitDelay},
ents
)
processActions s' ents' t
- ActionExitLevel -> processActions s {GS.levelCompleted = True} ents t
+ ActionExitStarted ->
+ processActions
+ s {GS.levelCompleted = GS.ExitStarted}
+ -- the player is not in the action, changing the type disables collision detection
+ ((head ents) {typ = TypeEffect} : tail ents)
+ t
+ ActionExitDone -> processActions s {GS.levelCompleted = GS.ExitDone} ents t
processActions s ents [] = pure (s, ents)
-- Update entities skipping enemies if the player was hit
@@ -134,7 +141,8 @@ render renderer es state = do
else traverse_ (renderWiggling ((.&.) 2 state.hitDelay)) others
-- always render player last
-- won't draw all the frames if the player was hit
- if testBit state.hitDelay 2 then pure () else renderOne player
+ -- or we are exiting the level
+ if testBit state.hitDelay 2 || state.levelCompleted /= GS.ExitOff then pure () else renderOne player
where
player = head es.entities
others = tail es.entities
diff --git a/src/Game/Entities/Common.hs b/src/Game/Entities/Common.hs
index 2e447f5..69786e5 100644
--- a/src/Game/Entities/Common.hs
+++ b/src/Game/Entities/Common.hs
@@ -30,7 +30,7 @@ collision :: IORef Entity -> Int -> Collision
collision playerRef otherHeight other = do
player <- readIORef playerRef
pure $
- player.dir /= Dying
+ player.typ == TypePlayer
&& player.x + 4 < other.x + 12
&& other.x + 4 < player.x + 12
&& player.y + otherHeight - 4 < other.y + otherHeight
diff --git a/src/Game/Entities/Exit.hs b/src/Game/Entities/Exit.hs
index 12f160d..b87c115 100644
--- a/src/Game/Entities/Exit.hs
+++ b/src/Game/Entities/Exit.hs
@@ -25,15 +25,24 @@ mkExit sprites x y playerCollision = do
}
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
+updateExit touchedPlayer e
+ -- right is the set 0, left set 1
+ | e.dir == DirRight = do
+ touched <- if e.frame < fullyOpen then pure False else touchedPlayer e
+ pure $ if touched then e {dir = DirLeft, frame = 0, actions = [ActionExitStarted]} else updateLoop
+ | otherwise = pure updateOnce
where
fullyOpen :: Int
fullyOpen = 7
- update :: Entity
- update
+ updateLoop :: Entity
+ updateLoop
| 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}
+
+ updateOnce :: Entity
+ updateOnce
+ | e.delay > 0 = e {delay = e.delay - 1}
+ | e.frame + 1 < frameLimit e = e {delay = frameDelay, frame = e.frame + 1}
+ | otherwise = e {destroy = True, actions = [ActionExitDone]}
diff --git a/src/Game/Entities/Types.hs b/src/Game/Entities/Types.hs
index 392a86f..4ece6c5 100644
--- a/src/Game/Entities/Types.hs
+++ b/src/Game/Entities/Types.hs
@@ -14,7 +14,7 @@ import qualified Game.Sprites as S
data Dir = DirRight | DirLeft | Dying deriving (Eq)
-data Type = TypePlayer | TypePickup | TypeEffect | TypeEnemy
+data Type = TypePlayer | TypePickup | TypeEffect | TypeEnemy deriving (Eq)
type Collision = Entity -> IO Bool
@@ -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 | ActionExitLevel
+data Action = ActionAddEffect Int Int EffectName | ActionAddBattery Int Int | ActionHitPlayer | ActionExitStarted | ActionExitDone
data Entity = Entity
{ typ :: Type,
diff --git a/src/Game/State.hs b/src/Game/State.hs
index 3773268..4f46c01 100644
--- a/src/Game/State.hs
+++ b/src/Game/State.hs
@@ -1,4 +1,4 @@
-module Game.State (State (..), initialState, levelState, maxLives) where
+module Game.State (State (..), initialState, levelState, maxLives, ExitState (..)) where
import Game.Entities.Const (hitDelay)
import qualified Game.Map as M
@@ -6,6 +6,8 @@ import qualified Game.Map as M
maxLives :: Int
maxLives = 4
+data ExitState = ExitOff | ExitStarted | ExitDone deriving (Eq)
+
data State = State
{ batteries :: Int,
totalBatteries :: Int,
@@ -15,7 +17,7 @@ data State = State
gameOverDelay :: Int,
exit :: Bool,
lastBattery :: (Int, Int),
- levelCompleted :: Bool,
+ levelCompleted :: ExitState,
currentLevel :: Int
}
@@ -31,7 +33,7 @@ initialState m =
exit = False,
-- doesn't matter where
lastBattery = (0, 0),
- levelCompleted = False,
+ levelCompleted = ExitOff,
currentLevel = 0
}
@@ -45,5 +47,5 @@ levelState s m =
exit = False,
-- doesn't matter where
lastBattery = (0, 0),
- levelCompleted = False
+ levelCompleted = ExitOff
}