{-| This module forms the apecs Prelude. It selectively re-exports the user-facing functions from the submodules. -} module Apecs ( -- * Core types SystemT(..), System, Component(..), Entity(..), Has(..), Not(..), Get, Set, Destroy, Members, -- * Stores Map, Unique, Global, Cache, explInit, -- * Systems get, set, ($=), destroy, exists, modify, ($~), cmap, cmapIf, cmapM, cmapM_, cfold, cfoldM, cfoldM_, collect, -- ** Performance -- $performance -- * Other runSystem, runWith, runGC, EntityCounter, newEntity, newEntity_, global, makeWorld, makeWorldAndComponents, -- * Re-exports asks, ask, liftIO, lift, Proxy (..) ) where import Control.Monad.IO.Class (liftIO) import Control.Monad.Reader (ask, asks, lift) import Data.Proxy import Apecs.Components import Apecs.Core import Apecs.Stores import Apecs.System import Apecs.TH import Apecs.Util -- $performance -- -- When using 'cmap' or 'cfold' over a tuple of components, keep in mind the -- ordering of the tuple can have performance implications! -- -- For tuples, the way the 'cmap' and 'cfold' work under the hood is by -- iterating over the component in the first position, and then for each entity -- that has that component, checking whether the entity also has the components -- in the remaining positions. Therefore, the first component will typically be -- the most determining factor for performance, and a good rule of thumb is to, -- __when iterating over a tuple, put the rarest component in first position__. -- -- Let's take a look at an example. -- Consider a simple 2D rendering system built on top of `cmapM_`: -- -- @ -- 'cmapM_' '$' \\(Sprite sprite, Visible) -> do -- renderSprite sprite -- @ -- -- While this rendering system works, it could be made more efficient by -- leveraging knowledge of how the library handles reading of tupled components. -- The usage of 'cmapM_' here (or any of the other map/fold functions) will -- iterate over all entities with a @Sprite@ component and filter out any of -- these entities that do not have a @Visible@ component. Depending on the game, -- it is reasonable to assume that there are more sprites active in the game's -- world than sprites that are visible to the game's camera. -- -- Swapping the component ordering in the tuple is likely to be more efficient: -- -- @ -- 'cmapM_' '$' \\(Visible, Sprite sprite) -> do -- renderSprite sprite -- @ -- -- Now the system iterates over just those entities that are visible to the -- game's camera and filters out any that do not have a @Sprite@ component. -- -- While putting the rarest component first is an excellent rule of thumb, to -- get the best possible performance, always consider how maps and folds are -- executed under the hood, and how you can order your components to optimize -- that process.