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 --- 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 +++ 5 files changed, 101 insertions(+), 1 deletion(-) create mode 100644 src/Game/Entities/Runner.hs (limited to 'src') 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