packages feed

aztecs-0.14.0: examples/Scheduler.hs

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}

module Main where

import Aztecs
import qualified Aztecs.World as W
import Control.Monad.IO.Class

newtype Position = Position Int
  deriving (Show, Eq)

instance (Monad m) => Component m Position where
  type ComponentStorage m Position = SparseStorage m

newtype Velocity = Velocity Int
  deriving (Show, Eq)

instance (Monad m) => Component m Velocity where
  type ComponentStorage m Velocity = SparseStorage m

newtype Health = Health Int
  deriving (Show, Eq)

instance (Monad m) => Component m Health where
  type ComponentStorage m Health = SparseStorage m

newtype Damage = Damage Int
  deriving (Show, Eq)

instance (Monad m) => Component m Damage where
  type ComponentStorage m Damage = SparseStorage m

data MoveSystem = MoveSystem
  deriving (Show)

data PhysicsSystem = PhysicsSystem
  deriving (Show)

data CombatSystem = CombatSystem
  deriving (Show)

data RenderSystem = RenderSystem
  deriving (Show)

instance (PrimMonad m, MonadIO m) => System m MoveSystem where
  type SystemIn m MoveSystem = Query (W m Position, R Velocity)
  runSystem MoveSystem q = do
    liftIO $ putStrLn "Running MoveSystem..."
    mapM_ go q
    where
      go (posRef, R (Velocity v)) = do
        modifyW posRef $ \(Position p) -> Position (p + v)
        p <- readW posRef
        liftIO $ putStrLn $ "  Moved to position: " ++ show p

instance (PrimMonad m, MonadIO m) => System m PhysicsSystem where
  type SystemIn m PhysicsSystem = Query (R Position, W m Velocity)
  runSystem PhysicsSystem q = do
    liftIO $ putStrLn "Running PhysicsSystem..."
    mapM_ go q
    where
      go (R (Position p), velRef) = do
        modifyW velRef $ \(Velocity v) -> Velocity (max 0 (v - 1))
        v <- readW velRef
        liftIO $ putStrLn $ "  Applied physics at position " ++ show p ++ ", new velocity: " ++ show v

instance (PrimMonad m, MonadIO m) => System m CombatSystem where
  type SystemIn m CombatSystem = Query (W m Health, R Damage)

  runSystem CombatSystem q = do
    liftIO $ putStrLn "Running CombatSystem..."
    mapM_ go q
    where
      go (healthRef, R (Damage d)) = do
        modifyW healthRef $ \(Health h) -> Health (max 0 (h - d))
        h <- readW healthRef
        liftIO $ putStrLn $ "  Applied damage, remaining health: " ++ show h

instance (PrimMonad m, MonadIO m) => System m RenderSystem where
  type SystemIn m RenderSystem = Query (R Position, R Health)

  runSystem RenderSystem q = do
    liftIO $ putStrLn "Running RenderSystem..."
    mapM_ go q
    where
      go (R (Position p), R (Health h)) = do
        liftIO $ putStrLn $ "  Rendering entity at position " ++ show p ++ " with health " ++ show h

app ::
  HSet
    '[ Run '[] MoveSystem,
       Run '[After MoveSystem] PhysicsSystem,
       Run '[After PhysicsSystem] CombatSystem,
       Run '[After CombatSystem] RenderSystem
     ]
app =
  HCons (Run MoveSystem) $
    HCons (Run PhysicsSystem) $
      HCons (Run CombatSystem) $
        HCons (Run RenderSystem) $
          HEmpty

appSmall ::
  HSet
    '[ Run '[After PhysicsSystem] MoveSystem,
       Run '[] PhysicsSystem,
       Run '[] RenderSystem
     ]
appSmall =
  HCons (Run MoveSystem) $
    HCons (Run PhysicsSystem) $
      HCons (Run RenderSystem) $
        HEmpty

runSchedulerExample :: IO ()
runSchedulerExample = do
  world <- W.empty @_ @'[Position, Velocity, Health, Damage]
  runAztecsT_ go world
  where
    go :: AztecsT '[Position, Velocity, Health, Damage] IO ()
    go = do
      _ <- spawn (bundle (Position 0) <> bundle (Velocity 5) <> bundle (Health 100))
      _ <- spawn (bundle (Position 10) <> bundle (Velocity 3) <> bundle (Health 75) <> bundle (Damage 10))
      _ <- spawn (bundle (Position (-5)) <> bundle (Velocity 2) <> bundle (Health 50))
      runSchedule app
      return ()

runSchedulerExampleSmall :: IO ()
runSchedulerExampleSmall = do
  world <- W.empty @_ @'[Position, Velocity, Health, Damage]
  runAztecsT_ go world
  where
    go :: AztecsT '[Position, Velocity, Health, Damage] IO ()
    go = do
      _ <- spawn (bundle (Position 0) <> bundle (Velocity 5) <> bundle (Health 100))
      _ <- spawn (bundle (Position 10) <> bundle (Velocity 3) <> bundle (Health 75) <> bundle (Damage 10))
      _ <- spawn (bundle (Position (-5)) <> bundle (Velocity 2) <> bundle (Health 50))
      runSchedule appSmall
      return ()

main :: IO ()
main = do
  runSchedulerExample
  runSchedulerExampleSmall