From 9ffa3f57067598acfbe5196a4452b225ab295b83 Mon Sep 17 00:00:00 2001 From: "Juan J. Martinez" Date: Wed, 19 Apr 2023 23:16:22 +0100 Subject: Added "runner" enemy --- data/map1.json | 83 +++++++++++++++++++++++++++++------------- data/sprites.json | 14 ++++++++ data/sprites.png | Bin 21424 -> 23767 bytes game.cabal | 2 ++ src/Game/Entities.hs | 2 ++ src/Game/Entities/Common.hs | 6 ++++ src/Game/Entities/Runner.hs | 86 ++++++++++++++++++++++++++++++++++++++++++++ src/Game/Entities/Types.hs | 3 +- src/Game/Map.hs | 5 +++ 9 files changed, 175 insertions(+), 26 deletions(-) create mode 100644 src/Game/Entities/Runner.hs diff --git a/data/map1.json b/data/map1.json index 0d532df..ee95e6c 100644 --- a/data/map1.json +++ b/data/map1.json @@ -52,8 +52,8 @@ "type":"", "visible":true, "width":16, - "x":32, - "y":112 + "x":176, + "y":88 }, { "height":16, @@ -165,28 +165,6 @@ "x":336, "y":40 }, - { - "height":24, - "id":26, - "name":"Robot-l", - "rotation":0, - "type":"", - "visible":true, - "width":16, - "x":144, - "y":88 - }, - { - "height":24, - "id":25, - "name":"Shooter", - "rotation":0, - "type":"", - "visible":true, - "width":16, - "x":64, - "y":136 - }, { "height":16, "id":17, @@ -228,7 +206,62 @@ "type":"", "visible":true, "width":16, + "x":224, + "y":16 + }, + { + "height":24, + "id":34, + "name":"Runner", + "rotation":0, + "type":"", + "visible":true, + "width":16, + "x":144, + "y":64 + }, + { + "height":24, + "id":35, + "name":"Runner", + "rotation":0, + "type":"", + "visible":true, + "width":16, + "x":32, + "y":40 + }, + { + "height":24, + "id":36, + "name":"Runner", + "rotation":0, + "type":"", + "visible":true, + "width":16, "x":112, + "y":112 + }, + { + "height":24, + "id":37, + "name":"Runner", + "rotation":0, + "type":"", + "visible":true, + "width":16, + "x":64, + "y":136 + }, + { + "height":24, + "id":38, + "name":"Runner", + "rotation":0, + "type":"", + "visible":true, + "width":16, + "x":136, "y":136 }], "opacity":1, @@ -238,7 +271,7 @@ "y":0 }], "nextlayerid":6, - "nextobjectid":34, + "nextobjectid":39, "orientation":"orthogonal", "renderorder":"right-down", "tiledversion":"1.7.2", diff --git a/data/sprites.json b/data/sprites.json index c4fcfb3..fac70b5 100644 --- a/data/sprites.json +++ b/data/sprites.json @@ -120,6 +120,20 @@ [0, 1, 2] ] }, + "runner": { + "frames": [ + { "x": 0, "y": 120, "width": 16, "height": 24 }, + { "x": 16, "y": 120, "width": 16, "height": 24 }, + { "x": 32, "y": 120, "width": 16, "height": 24 }, + { "x": 48, "y": 120, "width": 16, "height": 24 }, + { "x": 64, "y": 120, "width": 16, "height": 24 }, + { "x": 80, "y": 120, "width": 16, "height": 24 } + ], + "sets": [ + [0, 1, 0, 2], + [5, 4, 5, 3] + ] + }, "exit": { "frames": [ { "x": 0, "y": 160, "width": 16, "height": 24 }, diff --git a/data/sprites.png b/data/sprites.png index 0247640..697ee1f 100644 Binary files a/data/sprites.png and b/data/sprites.png differ diff --git a/game.cabal b/game.cabal index f5f38b7..f5b92dd 100644 --- a/game.cabal +++ b/game.cabal @@ -34,6 +34,7 @@ library Game.Entities.Robot Game.Entities.Shooter Game.Entities.Blast + Game.Entities.Runner Game.Controller Game.Utils Game.Toaster @@ -45,6 +46,7 @@ library , sdl2 , sdl2-image , json + , random ghc-options: -Wall -Werror -O2 -j default-extensions: diff --git a/src/Game/Entities.hs b/src/Game/Entities.hs index 25a7184..a0c596d 100644 --- a/src/Game/Entities.hs +++ b/src/Game/Entities.hs @@ -25,6 +25,7 @@ import Game.Entities.Exit import Game.Entities.Pickup import Game.Entities.Player import Game.Entities.Robot +import Game.Entities.Runner import Game.Entities.Shooter import Game.Entities.Slime import Game.Entities.Types @@ -49,6 +50,7 @@ mkEntities sprites m controls = do toEntity playerRef (M.SlimeEntity x y d) = mkSlime sprites x y d (collision playerRef 16) (M.isBlocked m) toEntity playerRef (M.RobotEntity x y d) = mkRobot sprites x y d (collision playerRef 24) (M.isBlocked m) toEntity playerRef (M.ShooterEntity x y d) = mkShooter sprites x y d (collision playerRef 24) (inLine playerRef 24) (M.isBlocked m) (collision playerRef 8) + toEntity playerRef (M.RunnerEntity x y d) = mkRunner sprites x y d (collision playerRef 24) (M.isBlocked m) toEntity playerRef (M.BatteryEntity x y) = mkBattery sprites x y (collision playerRef 16) toEntity _ (M.PlayerEntity _ _) = error "Player already processed" diff --git a/src/Game/Entities/Common.hs b/src/Game/Entities/Common.hs index 661fe07..eb84400 100644 --- a/src/Game/Entities/Common.hs +++ b/src/Game/Entities/Common.hs @@ -5,6 +5,7 @@ module Game.Entities.Common inLine, updateFrame, updateGravity, + turn, ) where @@ -13,6 +14,11 @@ import Game.Entities.Const import Game.Entities.Types import qualified Game.Sprites as S +-- | Return the opposite direction. +turn :: Dir -> Dir +turn DirRight = DirLeft +turn DirLeft = DirRight + -- | Convert direction into a sprite set. toSpriteSet :: Dir -> Int toSpriteSet DirRight = 0 diff --git a/src/Game/Entities/Runner.hs b/src/Game/Entities/Runner.hs new file mode 100644 index 0000000..7d969a5 --- /dev/null +++ b/src/Game/Entities/Runner.hs @@ -0,0 +1,86 @@ +module Game.Entities.Runner (mkRunner) where + +import Data.Bits (Bits (..)) +import Game.Entities.Common +import Game.Entities.Const +import Game.Entities.Types +import qualified Game.Sprites as S +import System.Random (randomRIO) + +mkRunner :: S.SpriteSheet -> Int -> Int -> Dir -> Collision -> IsBlocked -> IO Entity +mkRunner sprites x y d playerCollision isBlocked = do + s <- S.get sprites "runner" + pure + Entity + { typ = TypeEnemy, + x = x, + y = y, + delay = frameDelay, + frame = 0, + set = toSpriteSet d, + jumping = False, + gravity = gravityOff, + dir = d, + sprite = s, + update = updateRunner playerCollision isBlocked, + destroy = False, + actions = [], + dat = RunnerData 0 + } + +updateRunner :: Collision -> IsBlocked -> Entity -> IO Entity +updateRunner touchedPlayer isBlocked e = do + touched <- touchedPlayer e + if touched + then pure e {actions = [ActionHitPlayer]} + else do + let gravityUpdated = updateGravity isBlocked e + if gravityUpdated.gravity /= gravityOff then pure gravityUpdated else updateMovement $ updateFrame True gravityUpdated + where + updateMovement :: Entity -> IO Entity + updateMovement ent + | testBit ent.delay 1 = pure ent + | ent.dir == DirLeft + && (isBlocked (ent.x - 1) (ent.y + 17) || isBlocked (ent.x - 1) (ent.y + 17)) = + tryJumpingOrTurn ent + | ent.dir == DirLeft = pure ent {x = ent.x - 1} + | ent.dir == DirRight + && (isBlocked (ent.x + 16) (ent.y + 17) || isBlocked (ent.x + 16) (ent.y + 17)) = + tryJumpingOrTurn ent + | ent.dir == DirRight = pure ent {x = ent.x + 1} + | otherwise = pure ent + + randomWallCount :: [Int] + randomWallCount = [0, 0, 0, 2, 2, 3] + + tryJumpingOrTurn :: Entity -> IO Entity + tryJumpingOrTurn ent + | ent.dat.wallCount > 2 && not (isBlocked (ent.x + 8) (ent.y + 24 + 8)) = do + r <- randomRIO (0, length randomWallCount - 1) :: IO Int + pure + ent + { dir = turn ent.dir, + set = toSpriteSet $ turn ent.dir, + y = e.y + 1, + gravity = gravityDown, + frame = jumpFrame, + dat = RunnerData $ randomWallCount !! r + } + | ent.dat.wallCount > 1 && not (isBlocked (ent.x + 8) (ent.y - 1)) && isBlocked (ent.x + 8) ent.y = do + r <- randomRIO (0, length randomWallCount - 1) :: IO Int + pure + ent + { dir = turn ent.dir, + set = toSpriteSet $ turn ent.dir, + gravity = gravityUp, + frame = jumpFrame, + actions = [ActionAddEffect ent.x (ent.y + 8) "dust"], + dat = RunnerData $ randomWallCount !! r + } + | otherwise = + pure + ent + { dir = turn ent.dir, + set = toSpriteSet $ turn ent.dir, + dat = RunnerData (ent.dat.wallCount + 1) + } diff --git a/src/Game/Entities/Types.hs b/src/Game/Entities/Types.hs index 05726a8..71a1718 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} +data EntityData = NoData | ShooterData {coolDown :: Int} | RunnerData {wallCount :: Int} type Collision = Entity -> IO Bool @@ -48,6 +48,7 @@ data Entity = Entity delay :: Int, frame :: Int, set :: Int, + -- FIXME: this should be player data jumping :: Bool, gravity :: Int, dir :: Dir, diff --git a/src/Game/Map.hs b/src/Game/Map.hs index 1d395dc..6c01061 100644 --- a/src/Game/Map.hs +++ b/src/Game/Map.hs @@ -44,6 +44,7 @@ data Object | SlimeEntity Int Int Dir | RobotEntity Int Int Dir | ShooterEntity Int Int Dir + | RunnerEntity Int Int Dir deriving (Show, Eq, Ord) data JsonMapData = JsonMapData @@ -89,12 +90,16 @@ instance JSON Object where RobotEntity <$> valFromObj "x" obj <*> valFromObj "y" obj <*> pure DirRight Just "Shooter" -> ShooterEntity <$> valFromObj "x" obj <*> valFromObj "y" obj <*> pure DirRight + Just "Runner" -> + RunnerEntity <$> valFromObj "x" obj <*> valFromObj "y" obj <*> pure DirRight Just "Slime-l" -> SlimeEntity <$> valFromObj "x" obj <*> valFromObj "y" obj <*> pure DirLeft Just "Robot-l" -> RobotEntity <$> valFromObj "x" obj <*> valFromObj "y" obj <*> pure DirLeft Just "Shooter-l" -> ShooterEntity <$> valFromObj "x" obj <*> valFromObj "y" obj <*> pure DirLeft + Just "Runner-l" -> + RunnerEntity <$> valFromObj "x" obj <*> valFromObj "y" obj <*> pure DirLeft Just (JSString (JSONString s)) -> Error $ "unsupported entity " ++ show s e -> Error $ "unsupported entity in " ++ show e readJSON _ = mzero -- cgit v1.2.3