From 12728ed582057403e273d593eba781dd8b655f1f Mon Sep 17 00:00:00 2001 From: "Juan J. Martinez" Date: Fri, 17 Feb 2023 23:20:31 +0000 Subject: Added fixed pattern enemy (slimes) --- data/map.json | 46 +++++++++++++++++++++++++++++++++++++++++++++- data/sprites.json | 10 ++++++++++ data/sprites.png | Bin 10424 -> 10844 bytes src/Game/Entities.hs | 48 +++++++++++++++++++++++++++++++++++++++++++++++- src/Game/Map.hs | 5 ++++- 5 files changed, 106 insertions(+), 3 deletions(-) diff --git a/data/map.json b/data/map.json index 9eb7906..097fbe4 100644 --- a/data/map.json +++ b/data/map.json @@ -65,6 +65,50 @@ "x":160, "y":120 }, + { + "height":16, + "id":15, + "name":"Slime", + "rotation":0, + "type":"", + "visible":true, + "width":16, + "x":112, + "y":96 + }, + { + "height":16, + "id":16, + "name":"Slime", + "rotation":0, + "type":"", + "visible":true, + "width":16, + "x":192, + "y":24 + }, + { + "height":16, + "id":17, + "name":"Slime", + "rotation":0, + "type":"", + "visible":true, + "width":16, + "x":112, + "y":48 + }, + { + "height":16, + "id":20, + "name":"Slime", + "rotation":0, + "type":"", + "visible":true, + "width":16, + "x":256, + "y":120 + }, { "height":16, "id":5, @@ -138,7 +182,7 @@ "y":0 }], "nextlayerid":6, - "nextobjectid":15, + "nextobjectid":21, "orientation":"orthogonal", "renderorder":"right-down", "tiledversion":"1.7.2", diff --git a/data/sprites.json b/data/sprites.json index a911207..3ce716b 100644 --- a/data/sprites.json +++ b/data/sprites.json @@ -44,5 +44,15 @@ "sets": [ [0, 1, 2, 3] ] + }, + "slime": { + "frames": [ + { "x": 0, "y": 56, "width": 16, "height": 16 }, + { "x": 16, "y": 56, "width": 16, "height": 16 } + ], + "sets": [ + [0, 1], + [0, 1] + ] } } diff --git a/data/sprites.png b/data/sprites.png index 6b84a40..2b3616d 100644 Binary files a/data/sprites.png and b/data/sprites.png differ diff --git a/src/Game/Entities.hs b/src/Game/Entities.hs index 9152175..f45ae1a 100644 --- a/src/Game/Entities.hs +++ b/src/Game/Entities.hs @@ -1,7 +1,9 @@ module Game.Entities (Entities, Entity, mkEntities, updateAll, render) where +import Data.Bits (Bits (..)) import Data.Foldable (find, traverse_) import Data.IORef +import Data.List (sort) import qualified Game.Controller as C import qualified Game.Map as M import qualified Game.Sprites as S @@ -87,11 +89,12 @@ mkEntities sprites m controls stateRef = do Just (M.PlayerEntity x y) -> mkPlayer sprites x y controls (M.isBlocked m) _ -> error "No player entity in map" playerRef <- newIORef player - entities <- traverse (toEntity playerRef) $ filter (not . M.isPlayer) (M.objects m) + entities <- traverse (toEntity playerRef) $ sort $ filter (not . M.isPlayer) (M.objects m) -- the entities list has always player first pure $ Entities sprites playerRef (player : entities) where toEntity :: IORef Entity -> M.Object -> IO Entity + toEntity playerRef (M.SlimeEntity x y) = mkSlime sprites x y playerRef (M.isBlocked m) toEntity playerRef (M.BatteryEntity x y) = mkBattery sprites x y playerRef stateRef toEntity _ (M.PlayerEntity _ _) = error "Player already processed" @@ -187,6 +190,49 @@ updateBattery touchedPlayer collectedBattery e = do | e.frame + 1 < frameLimit e = e {delay = frameDelay, frame = e.frame + 1} | otherwise = e {delay = frameDelay, frame = 0} +mkSlime :: S.SpriteSheet -> Int -> Int -> IORef Entity -> IsBlocked -> IO Entity +mkSlime sprites x y playerRef isBlocked = do + s <- S.get sprites "slime" + pure + Entity + { typ = TypePickup, + x = x, + y = y, + delay = frameDelay, + frame = 0, + jumping = False, + gravity = gravityOff, + dir = DirRight, + sprite = s, + update = updateSlime (collision playerRef) isBlocked, + destroy = False, + spawns = [] + } + +updateSlime :: Collision -> IsBlocked -> Entity -> IO Entity +updateSlime touchedPlayer isBlocked e = do + touched <- touchedPlayer e + let updated = updateSlimeFrame + pure $ if touched then e {destroy = True} else updateMovement updated + where + updateMovement :: Entity -> Entity + updateMovement e' + | testBit e'.delay 1 = e' + | e'.dir == DirLeft + && (isBlocked (e'.x - 1) (e'.y + 15) || isBlocked (e'.x - 1) (e'.y + 10) || not (isBlocked (e'.x - 1) (e'.y + 16))) = + e' {dir = DirRight} + | e'.dir == DirLeft = e' {x = e'.x - 1} + | e'.dir == DirRight + && (isBlocked (e'.x + 16) (e'.y + 15) || isBlocked (e'.x + 16) (e'.y + 10) || not (isBlocked (e'.x + 16) (e'.y + 16))) = + e' {dir = DirLeft} + | e'.dir == DirRight = e' {x = e'.x + 1} + | otherwise = e' + updateSlimeFrame :: Entity + updateSlimeFrame + | e.delay > 0 = e {delay = e.delay - 1} + | e.frame + 1 < frameLimit e = e {delay = frameDelay + 2, frame = e.frame + 1} + | otherwise = e {delay = frameDelay + 2, frame = 0} + mkPlayer :: S.SpriteSheet -> Int -> Int -> IORef C.Controls -> IsBlocked -> IO Entity mkPlayer sprites x y controls isBlocked = do s <- S.get sprites "player" diff --git a/src/Game/Map.hs b/src/Game/Map.hs index ee30437..95e5618 100644 --- a/src/Game/Map.hs +++ b/src/Game/Map.hs @@ -36,7 +36,8 @@ data Layer data Object = PlayerEntity Int Int | BatteryEntity Int Int - deriving (Show) + | SlimeEntity Int Int + deriving (Show, Eq, Ord) data JsonMapData = JsonMapData { width :: Int, @@ -75,6 +76,8 @@ instance JSON Object where PlayerEntity <$> valFromObj "x" obj <*> valFromObj "y" obj Just "Battery" -> BatteryEntity <$> valFromObj "x" obj <*> valFromObj "y" obj + Just "Slime" -> + SlimeEntity <$> valFromObj "x" obj <*> valFromObj "y" obj Just (JSString (JSONString s)) -> Error $ "unsupported entity " ++ show s e -> Error $ "unsupported entity in " ++ show e readJSON _ = mzero -- cgit v1.2.3