@hackage apecs0.2.4.5
A fast ECS for game engine programming
Categories
License
BSD-3-Clause
Maintainer
jonascarpay@gmail.com
Links
Versions
Installation
Dependencies (6)
- async
- base >=4.9 && <4.11
- containers
- mtl
- template-haskell
- vector Show all…
Dependents (7)
@hackage/apecs-brillo, @hackage/apecs-gloss, @hackage/apecs-physics-gloss, @hackage/cadence, @hackage/apecs-physics, @hackage/apecs-stm, Show all…
apecs
hackage | documentation | tutorials
apecs is an Entity Component System inspired by specs and Entitas. It exposes a DSL that translates to fast storage operations, resulting in expressivity without sacrificing performance or safety.
There is an example below, and a tutorial can be found here. For a physics engine written on top of apecs, check out phycs. For a general introduction to ECS, see this talk or here.
Performance
Performance is good. Running ecs-bench shows that apecs is competitive with the fastest Rust ECS frameworks.
| pos_vel build | pos_vel step | parallel build | parallel step | |
|---|---|---|---|---|
| apecs | 239 | 34 | 777 | 371 |
| calx | 261 | 21 | 442 | 72 |
| constellation | 306 | 10 | 567 | 256 |
| froggy | 594 | 13 | 1565 | 97 |
| specs | 753 | 38 | 1016 | 205 |

There is a performance guide here.
Example
import Apecs
import Apecs.Stores (Cache)
import Apecs.Concurrent (prmap)
import Linear
newtype Position = Position (V2 Double) deriving Show
-- Turn Position into a component by specifiying the type of its Storage
instance Component Position where
-- The simplest store is a Map
type Storage Position = Map Position
newtype Velocity = Velocity (V2 Double)
instance Component Velocity where
-- We can add a Cache for faster access
type Storage Velocity = Cache 100 (Map Velocity)
data Player = Player -- A single constructor component for tagging the player
instance Component Player where
-- Unique contains at most one component. See the Stores module.
type Storage Player = Unique Player
-- Generate a world type and instances
makeWorld "World" [''Position, ''Velocity, ''Player]
game :: System World ()
game = do
-- Create new entities
ety <- newEntity (Position 0)
-- Components can be composed using tuples
newEntity (Position 0, Velocity 1)
newEntity (Position 1, Velocity 1, Player)
-- set (over)writes components
set ety (Velocity 2)
let stepVelocity (Position p, Velocity v) = Position (v+p)
-- Side effects
liftIO$ putStrLn "Stepping velocities"
-- rmap maps a pure function over all entities in its domain
rmap stepVelocity
-- prmap n does the same, but in parallel
prmap 2 stepVelocity
-- Print all positions
cmapM_ $ \(Position p) -> liftIO (print p)
main :: IO ()
main = initWorld >>= runSystem game