{-# OPTIONS_GHC -Wno-unused-imports #-} -- | -- Module: Systems Tutorial -- Description: Tutorial on using @Systems@ -- -- This module contains a more in-depth look into the @Mischief App and Plugins@. -- -- It isn't as technically interesting as the other chapters of the tutorial, focusing more on organization and high-level logic. -- -- [Previous Chapter: Coding a Dungeon Game]("Mischief.ECS.Tutorial.Dungeon") -- -- [Next Chapter: Components]("Mischief.ECS.Tutorial.Components") -- -- [Main Page]("Mischief.ECS") module Mischief.ECS.Tutorial.App ( -- * Learn You an ECS for Great Mischief! - 3. App and Plugins -- $intro -- * Modular Features -- $modular_features -- * [Next chapter: Components]("Mischief.ECS.Tutorial.Components") ) where import Control.Monad.Reader import Mischief.ECS -- $intro -- The @'App'@ is a thin wrapper around the @'World'@ that works as an interface for plugging in -- various behavior and features in modular fashion, via @Plugins@. -- -- A Mischief game / app usually starts by creating an app and adding one or more plugins to it. -- -- @ -- main :: 'IO' () -- main = do -- app <- 'newApp' -- 'addPlugin' \@MainPlugin app -- 'runApp' app -- -- data MainPlugin -- -- instance 'Plugin' MainPlugin where -- init = 'info' \"Hello!\" -- @ -- -- A @Plugin@ instance has two optional functions: -- -- 1. An initialization system that will be ran at the very beginning of the app. -- -- This system is usually used to schedule other systems, or to initialize data, such as resources and -- observers. -- -- @ -- init :: 'System' () -- init = do -- 'insertRes' (Health 0) -- 'void' $ 'spawn' ('Observer' onDamage) -- -- 'systems' movePlayer -- & 'schedule' 'Update' -- @ -- -- 2. A list of plugins this plugin depends on. -- -- Any plugin can be made into a dependency using the @dep@ function: -- -- @ -- deps = ['dep' \@PlayerPlugin, 'dep' \@EnemyPlugin, 'dep' \@PhysicsPlugin] -- @ -- -- It is guaranteed that the init systems of a plugin's dependencies will run before its own init. -- $modular_features -- Mischief is intended to let you cleanly separate and organize your logic. -- -- For instance, you may have a @PhysicsPlugin@ that adds physics to your game, a @RenderPlugin@ which renders objects, a @LevelPlugin@ that spawns your levels. -- -- @ -- instance 'Plugin' MainPlugin where -- deps _ = ['dep' \@PhysicsPlugin, 'dep' \@RenderPlugin, 'dep' \@LevelPlugin] -- @ -- -- Ideally, each of these plugins would add their own independent features. So, if you were to remove @physicsPlugin@, your entities simply wouldn't -- move and collide anymore, but the rest of the app would work just fine. -- -- Note that, internally, @PhsyicsPlugin@ could also be subdivided into its own plugins with separate roles: -- -- @ -- data PhysicsPlugin -- -- instance 'Plugin' PhysicsPlugin where -- deps = ['dep' \@CollisionPlugin, 'dep' \@MovePlugin] -- @ -- -- This also lets the various packages of @Mischief@ be modular, and makes it easy for third party library developers to create plugins that you just plug into your app with ease!