apecs

Fast ECS framework for game programming

https://github.com/jonascarpay/apecs#readme

Version on this page:0.4.1.1
LTS Haskell 22.14:0.9.6
Stackage Nightly 2024-03-28:0.9.6
Latest on Hackage:0.9.6

See all snapshots apecs appears in

BSD-3-Clause licensed by Jonas Carpay
Maintained by [email protected]
This version can be pinned in stack with:apecs-0.4.1.1@sha256:ea09c14ba3e248fbab1a7102930bd875009ee5739a42b300091f716e5cf31442,1798

Module documentation for 0.4.1.1

  • Apecs
    • Apecs.Concurrent
    • Apecs.Core
    • Apecs.Stores
    • Apecs.System
    • Apecs.TH
    • Apecs.Util

apecs

Build Status Hackage Stackage

apecs is an Entity Component System (ECS) framework inspired by specs and Entitas. The front-end DSL uses a small set of combinators to concisely express game logic, which then translate to fast primitive operations on back-end stores. Both the DSL and storage framework can easily be extended to meet any performance/expressivity needs.

Links

Performance

ecs-bench shows that apecs is competitive with the fastest Rust ECS frameworks.

Benchmarks

Example

{-# LANGUAGE DataKinds, ScopedTypeVariables, TypeFamilies, MultiParamTypeClasses, TemplateHaskell #-}

import Apecs
import Linear (V2 (..))

newtype Position = Position (V2 Double) deriving Show
-- To declare a component, we need to specify how to store it
instance Component Position where
  type Storage Position = Map Position -- The simplest store is a Map

newtype Velocity = Velocity (V2 Double) deriving Show
instance Component Velocity where
  type Storage Velocity = Cache 100 (Map Velocity) -- Caching adds fast reads/writes

data Flying = Flying
instance Component Flying where
  type Storage Flying = Map Flying

makeWorld "World" [''Position, ''Velocity, ''Flying] -- Generate World and instances

game :: System World ()
game = do
  newEntity (Position 0, Velocity 1)
  newEntity (Position 2, Velocity 1)
  newEntity (Position 1, Velocity 2, Flying)

  -- Add velocity to position
  cmap $ \(Position p, Velocity v) -> Position (v+p)
  -- Apply gravity to non-flying entities
  cmap $ \(Velocity v, _ :: Not Flying) -> Velocity (v - (V2 0 1))
  -- Print a list of entities and their positions
  cmapM_ $ \(Position p, Entity e) -> liftIO . print $ (e, p)

main :: IO ()
main = initWorld >>= runSystem game