aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJuan J. Martinez <jjm@usebox.net>2023-05-23 22:52:01 +0100
committerJuan J. Martinez <jjm@usebox.net>2023-05-23 22:52:01 +0100
commitf886dc2f03a75b12749ad029134b70c346aea194 (patch)
treeb3d6f00d52672e35c477a003537e159e86161318
parenta8091dc3c82a4d646e84b356c46319ba54847ce0 (diff)
downloadspace-plat-hs-f886dc2f03a75b12749ad029134b70c346aea194.tar.gz
space-plat-hs-f886dc2f03a75b12749ad029134b70c346aea194.zip
Deadly blocks kill the player
Implemented "auto-checkpoints" based on where the player lands after a jump.
-rw-r--r--src/Game/Entities.hs35
-rw-r--r--src/Game/Entities/Player.hs22
-rw-r--r--src/Game/Entities/Types.hs3
3 files changed, 40 insertions, 20 deletions
diff --git a/src/Game/Entities.hs b/src/Game/Entities.hs
index bea6e33..5e1af65 100644
--- a/src/Game/Entities.hs
+++ b/src/Game/Entities.hs
@@ -38,7 +38,7 @@ import qualified SDL
mkEntities :: S.SpriteSheet -> M.Map -> IORef C.Controls -> IO Entities
mkEntities sprites m controls = do
player <- case find M.isPlayer (M.objects m) of
- Just (M.PlayerEntity x y) -> mkPlayer sprites x y controls (M.isBlocked m)
+ Just (M.PlayerEntity x y) -> mkPlayer sprites x y controls (M.isBlocked m) (M.isBlockedDeadly m)
_ -> error "No player entity in map"
playerRef <- newIORef player
entities <- traverse (toEntity playerRef) $ sort $ filter (not . M.isPlayer) (M.objects m)
@@ -97,18 +97,11 @@ updateAll es state = do
ActionAddBattery x y ->
processActions s {GS.batteries = s.batteries + 1, GS.lastBattery = (x, y)} ents t
ActionHitPlayer -> do
- let (s', ents') =
- if s.lives == 1
- then
- ( s {GS.lives = 0, GS.gameOverDelay = gameOverDelay},
- -- the player is not in the action, changing then type disables collision detection
- (head ents) {typ = TypeEffect, set = dyingSet, gravity = gravityUp, frame = 0} : tail ents
- )
- else
- ( s {GS.lives = s.lives - 1, GS.hitDelay = hitDelay},
- ents
- )
+ let (s', ents') = processPlayerHitAction s ents
processActions s' ents' t
+ ActionHitPlayerDeadly -> do
+ let (s', ents') = processPlayerHitAction s ents
+ processActions s' (playerToCheckpoint s'.lives (head ents') : tail ents') t
ActionExitStarted ->
processActions
s {GS.playState = GS.ExitStarted}
@@ -122,6 +115,24 @@ updateAll es state = do
processActions s (ents ++ [blast]) t
processActions s ents [] = pure (s, ents)
+ playerToCheckpoint :: Int -> Entity -> Entity
+ playerToCheckpoint lives p
+ | lives == 0 = p
+ | otherwise = p {x = p.dat.checkx, y = p.dat.checky}
+
+ processPlayerHitAction :: GS.State -> [Entity] -> (GS.State, [Entity])
+ processPlayerHitAction s ents =
+ if s.lives == 1
+ then
+ ( s {GS.lives = 0, GS.gameOverDelay = gameOverDelay, GS.hitDelay = 0},
+ -- the player is not in the action, changing then type disables collision detection
+ (head ents) {typ = TypeEffect, set = dyingSet, gravity = gravityUp, frame = 0} : tail ents
+ )
+ else
+ ( s {GS.lives = s.lives - 1, GS.hitDelay = hitDelay},
+ ents
+ )
+
-- Update entities skipping enemies if the player was hit
updateFilter :: Bool -> Entity -> IO Entity
updateFilter False e = e.update e
diff --git a/src/Game/Entities/Player.hs b/src/Game/Entities/Player.hs
index 620f236..82e528a 100644
--- a/src/Game/Entities/Player.hs
+++ b/src/Game/Entities/Player.hs
@@ -10,8 +10,8 @@ import qualified Game.Sprites as S
dyingSet :: Int
dyingSet = 2
-mkPlayer :: S.SpriteSheet -> Int -> Int -> IORef C.Controls -> IsBlocked -> IO Entity
-mkPlayer sprites x y controls isBlocked = do
+mkPlayer :: S.SpriteSheet -> Int -> Int -> IORef C.Controls -> IsBlocked -> IsBlocked -> IO Entity
+mkPlayer sprites x y controls isBlocked isBlockedDeadly = do
s <- S.get sprites "player"
pure
Entity
@@ -25,10 +25,10 @@ mkPlayer sprites x y controls isBlocked = do
gravity = gravityOff,
dir = DirRight,
sprite = s,
- update = updatePlayer controls isBlocked,
+ update = updatePlayer controls isBlocked isBlockedDeadly,
destroy = False,
actions = [],
- dat = NoData
+ dat = PlayerData x y
}
updateHorizontal :: IsBlocked -> Bool -> Bool -> Entity -> Entity
@@ -62,12 +62,20 @@ updateVertical isBlocked jump down e
e {gravity = gravityDown, frame = jumpFrame, y = e.y + 1}
| otherwise = e
-updatePlayer :: IORef C.Controls -> IsBlocked -> Entity -> IO Entity
-updatePlayer controls isBlocked e
+updateGravityCheckDeadly :: IsBlocked -> IsBlocked -> Entity -> Entity
+updateGravityCheckDeadly isBlocked isBlockedDeadly e
+ | isBlockedDeadly (updated.x + 8) (updated.y + 24) = updated {actions = updated.actions ++ [ActionHitPlayerDeadly]}
+ | updated.gravity == gravityOff && e.gravity /= gravityOff = updated {dat = PlayerData updated.x updated.y}
+ | otherwise = updated
+ where
+ updated = updateGravity isBlocked e
+
+updatePlayer :: IORef C.Controls -> IsBlocked -> IsBlocked -> Entity -> IO Entity
+updatePlayer controls isBlocked isBlockedDeadly e
| e.set /= dyingSet = do
ctl <- readIORef controls
pure $
- updateGravity isBlocked $
+ updateGravityCheckDeadly isBlocked isBlockedDeadly $
updateVertical isBlocked ctl.a ctl.down $
updateHorizontal isBlocked ctl.left ctl.right $
-- left or right, but not both (keyboard)
diff --git a/src/Game/Entities/Types.hs b/src/Game/Entities/Types.hs
index e9ca02f..765800f 100644
--- a/src/Game/Entities/Types.hs
+++ b/src/Game/Entities/Types.hs
@@ -17,7 +17,7 @@ data Dir = DirRight | DirLeft deriving (Eq, Show, Ord)
data Type = TypePlayer | TypePickup | TypeEffect | TypeEnemy deriving (Eq)
-data EntityData = NoData | ShooterData {coolDown :: Int} | RunnerData {wallCount :: Int}
+data EntityData = NoData | ShooterData {coolDown :: Int} | RunnerData {wallCount :: Int} | PlayerData {checkx :: Int, checky :: Int}
type Collision = Entity -> IO Bool
@@ -36,6 +36,7 @@ data Action
= ActionAddEffect Int Int EffectName
| ActionAddBattery Int Int
| ActionHitPlayer
+ | ActionHitPlayerDeadly
| ActionExitStarted
| ActionEntryDone
| ActionExitDone