apecs 0.7.1 → 0.7.2
raw patch · 12 files changed
+154/−115 lines, 12 filesdep ~QuickCheckdep ~basedep ~containersPVP ok
version bump matches the API change (PVP)
Dependency ranges changed: QuickCheck, base, containers, criterion, linear, mtl, template-haskell, vector
API changes (from Hackage documentation)
+ Apecs: Proxy :: Proxy
+ Apecs: data Proxy (t :: k) :: forall k. () => k -> Type
+ Apecs.Stores.Extra: instance Data.Foldable.Foldable Apecs.Stores.Extra.Stack
+ Apecs.Stores.Extra: instance GHC.Base.Applicative Apecs.Stores.Extra.Stack
+ Apecs.Stores.Extra: instance GHC.Base.Functor Apecs.Stores.Extra.Stack
+ Apecs.Stores.Extra: instance GHC.Base.Monad Apecs.Stores.Extra.Stack
+ Apecs.Stores.Extra: instance GHC.Base.Monoid (Apecs.Stores.Extra.Stack c)
+ Apecs.Stores.Extra: instance GHC.Base.Semigroup (Apecs.Stores.Extra.Stack c)
+ Apecs.Stores.Extra: instance GHC.Classes.Eq c => GHC.Classes.Eq (Apecs.Stores.Extra.Stack c)
+ Apecs.Stores.Extra: instance GHC.Show.Show c => GHC.Show.Show (Apecs.Stores.Extra.Stack c)
Files
- CHANGELOG.md +8/−2
- README.md +31/−17
- apecs.cabal +18/−21
- src/Apecs.hs +10/−12
- src/Apecs/Components.hs +2/−2
- src/Apecs/Core.hs +1/−2
- src/Apecs/Stores.hs +1/−1
- src/Apecs/Stores/Extra.hs +32/−19
- src/Apecs/System.hs +3/−3
- src/Apecs/TH.hs +8/−7
- src/Apecs/Util.hs +10/−9
- test/Main.hs +30/−20
CHANGELOG.md view
@@ -1,7 +1,13 @@+## [Unreleased]+### Changed+- Fixed bug in the `Pushdown` store+- `Apecs` module no longer re-exports the entire `Data.Proxy` module, but instead just `Proxy (..)`.+- Added (approximate?) lower and upper version bounds to dependencies+ ## [0.7.1]-## Added+### Added - `$=` and `$~` operators as synonyms for `set` and `get` respectively-## Removed+### Removed - `getAll` and `count`, which were made redundant by `cfold`. ## [0.7.0]
README.md view
@@ -1,31 +1,45 @@-# apecs--apecs is an _Entity Component System_ (ECS) framework inspired by [specs](https://github.com/slide-rs/specs) and [Entitas](https://github.com/sschmid/Entitas-CSharp).+# apecs [](https://travis-ci.org/jonascarpay/apecs)+apecs is an _Entity Component System_ (ECS) library inspired by [specs](https://github.com/slide-rs/specs) and [Entitas](https://github.com/sschmid/Entitas-CSharp). ECS presents a data-driven approach to game development, that elegantly tackles many of the unique issues of game programming.+ apecs aims to be-* **Fast** - apecs is designed for high-performance applications. Its performance is competitive with Rust ECS libraries.-* **Simple** - Game logic is expressed using a small number of combinators, and minimal boilerplate.-* **Safe** - The `cmap`/`cfold`-DSL hides all the dangers of the low-level API.-* **Extensible** - apecs can be used with anything that implements the low-level API. See [apecs-physics](apecs-physics/) or [apecs-stm](apecs-stm/) for examples.+* **Fast** - Performance is competitive with Rust ECS libraries (see benchmark results below).+* **Concise** - Game logic is expressed using a small number of powerful combinators.+* **Safe** - The `cmap`/`cfold`-DSL completely hides the dangers of the low-level API.+* **Extensible** - At its heart apecs is just a data manipulation DSL that can be implemented with any number of backends. as a monad transformer it easily integrates into larger applications.+* **Cool** ++ #### Links-- [manual](https://github.com/jonascarpay/apecs/blob/master/prepub.pdf) (see [#19](https://github.com/jonascarpay/apecs/issues/19))-- [tutorial](https://github.com/jonascarpay/apecs/blob/master/examples/Shmup.md)-- [documentation](https://hackage.haskell.org/package/apecs/docs/Apecs.html)-- [apecs-physics](https://github.com/jonascarpay/apecs-physics)+- [documentation on hackage](https://hackage.haskell.org/package/apecs/docs/Apecs.html)+- [tutorial](examples/Shmup.md) and other [examples](examples/)+- [paper (prepublication)](apecs/prepub.pdf) (see [#19](https://github.com/jonascarpay/apecs/issues/19))+- [apecs-physics](apecs-physics/) - 2D physics using the [Chipmunk2D](https://github.com/slembcke/Chipmunk2D) engine+- [apecs-gloss](apecs-gloss/) - Simple frontend for [gloss](http://hackage.haskell.org/package/gloss)-based rendering+- [apecs-stm](apecs-stm/) - STM-based stores for easy concurrency -#### Performance-[ecs-bench](https://github.com/lschmierer/ecs_bench) shows that apecs is competitive with the fastest Rust ECS frameworks.+##### By other authors+- [An Introduction to Developing Games in Haskell with Apecs](https://blog.aas.sh/posts/2018-09-10-Making-A-Game-With-Haskell-And-Apecs/) by Ashley Smith -+#### Status+| Package | Hackage | Stack LTS | Stack Nightly |+|---|---|---|---|+| [apecs](apecs/) | [](https://hackage.haskell.org/package/apecs) | [](https://www.stackage.org/package/apecs) | [](https://www.stackage.org/package/apecs)+| [apecs-physics](apecs-physics/) | [](https://hackage.haskell.org/package/apecs-physics) | [](https://www.stackage.org/package/apecs-physics) | [](https://www.stackage.org/package/apecs-physics) |+| [apecs-gloss](apecs-gloss/) | [](https://hackage.haskell.org/package/apecs-gloss) | [](https://www.stackage.org/package/apecs-gloss) | [](https://www.stackage.org/package/apecs-gloss) |+| [apecs-stm](apecs-stm/) | [](https://hackage.haskell.org/package/apecs-stm) | - | - |+| [examples](examples/) | - | - | - | #### Example ```haskell-{-# LANGUAGE DataKinds, FlexibleInstances, ScopedTypeVariables, TypeFamilies, MultiParamTypeClasses, TemplateHaskell #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE TypeFamilies #-} import Apecs-import Control.Monad-import Apecs.Util import Linear (V2 (..)) newtype Position = Position (V2 Double) deriving Show
apecs.cabal view
@@ -1,5 +1,5 @@ name: apecs-version: 0.7.1+version: 0.7.2 homepage: https://github.com/jonascarpay/apecs#readme license: BSD3 license-file: LICENSE@@ -8,10 +8,10 @@ category: Game, Control, Data build-type: Simple cabal-version: >=1.10-synopsis: Fast ECS framework for game programming+synopsis: Fast Entity-Component-System library for game programming description:- Entity-Component-System frameworks provide a game programming paradigm that tackles many of the shortcomings of a more OO-oriented approach.- apecs is a type-driven ECS, that leverages strong typing for an expressive DSL that turns into fast game code.+ The Entity-Component-System architecture provides an imperative game programming paradigm that tackles many of the shortcomings of more OO-oriented approaches.+ apecs is a type-driven ECS library, that leverages strong typing for an expressive DSL that compiles into fast game code. extra-source-files: README.md,@@ -39,11 +39,11 @@ default-language: Haskell2010 build-depends:- base >= 4.7 && < 5,- containers,- mtl,- template-haskell,- vector+ base >= 4.9 && < 5,+ containers >= 0.5 && < 0.8,+ mtl >= 2.2 && < 2.3,+ template-haskell >= 2.12 && < 3,+ vector >= 0.11 && < 0.13 ghc-options: -Wall @@ -55,13 +55,12 @@ hs-source-dirs: test build-depends:- base >= 4.7 && < 5, apecs,- QuickCheck,- criterion,- linear,- containers,- vector+ base >= 4.9 && < 5,+ containers >= 0.5 && < 0.8,+ linear >= 1.20 && < 2,+ vector >= 0.10 && < 0.13,+ QuickCheck >= 2.10 && < 3 default-language: Haskell2010 ghc-options: -Wall@@ -74,19 +73,17 @@ main-is: Main.hs build-depends:- base >= 4.7 && < 5, apecs,- criterion,- linear+ base >= 4.9 && < 5,+ criterion >= 1.3 && < 2,+ linear >= 1.20 && < 2 default-language: Haskell2010 ghc-options: -Wall- -- LLVM is disabled by default for travis/compatibility reasons- -- For serious benchmarks, please run with -fllvm- -- -fllvm -O2 -optlo-O3+ -- -fllvm -threaded -funfolding-use-threshold1000 -funfolding-keeness-factor1000
src/Apecs.hs view
@@ -3,7 +3,6 @@ It selectively re-exports the user-facing functions from the submodules. -} module Apecs (- module Data.Proxy, -- * Core types SystemT(..), System, Component(..), Entity(..), Has(..), Not(..), Get, Set, Destroy, Members,@@ -15,7 +14,7 @@ -- * Systems get, set, ($=), destroy, exists,- modify, ($~), + modify, ($~), cmap, cmapM, cmapM_, cfold, cfoldM, cfoldM_, @@ -25,16 +24,15 @@ makeWorld, makeWorldAndComponents, -- * Re-exports- asks, ask, liftIO, lift,+ asks, ask, liftIO, lift, Proxy (..) ) where -import Control.Monad.Reader (ask, asks, lift, liftIO)-import Data.Proxy--import Apecs.Stores-import Apecs.Components-import Apecs.System-import Apecs.TH-import Apecs.Core-import Apecs.Util+import Control.Monad.Reader (ask, asks, lift, liftIO)+import Data.Proxy +import Apecs.Components+import Apecs.Core+import Apecs.Stores+import Apecs.System+import Apecs.TH+import Apecs.Util
src/Apecs/Components.hs view
@@ -13,10 +13,10 @@ module Apecs.Components where -import Data.Functor.Identity+import Data.Functor.Identity import Apecs.Core-import qualified Apecs.THTuples as T+import qualified Apecs.THTuples as T -- | Identity component. @Identity c@ is equivalent to @c@, so mostly useless. instance Component c => Component (Identity c) where
src/Apecs/Core.hs view
@@ -12,7 +12,7 @@ module Apecs.Core where import Control.Monad.Reader-import qualified Data.Vector.Unboxed as U+import qualified Data.Vector.Unboxed as U -- | An Entity is just an integer, used to index into a component store. -- In general, use @newEntity@, @cmap@, and component tags instead of manipulating these directly.@@ -76,4 +76,3 @@ type Set w m c = (Has w m c, ExplSet m (Storage c)) type Members w m c = (Has w m c, ExplMembers m (Storage c)) type Destroy w m c = (Has w m c, ExplDestroy m (Storage c))-
src/Apecs/Stores.hs view
@@ -26,7 +26,7 @@ import qualified Data.Vector.Unboxed.Mutable as UM import GHC.TypeLits -import Apecs.Core+import Apecs.Core -- | A map based on @Data.IntMap.Strict@. O(log(n)) for most operations. newtype Map c = Map (IORef (M.IntMap c))
src/Apecs/Stores/Extra.hs view
@@ -4,42 +4,53 @@ Containment module for stores that are experimental/too weird for @Apecs.Stores@. -} -{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE UndecidableInstances #-}+{-# OPTIONS_GHC -fno-warn-name-shadowing #-}+{-# OPTIONS_GHC -fno-warn-unused-imports #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE PatternSynonyms #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE UndecidableInstances #-} module Apecs.Stores.Extra ( Pushdown(..), Stack(..) , ReadOnly(..), setReadOnly, destroyReadOnly ) where -import Control.Monad.Reader-import Data.Proxy+import Control.Monad.Reader+import Data.Proxy -import Apecs.Core+import Apecs.Components (MaybeStore (..))+import Apecs.Core -- | Overrides a store to have history/pushdown semantics. -- Setting this store adds a new value on top of the stack. -- Destroying pops the stack.--- You can view the entire stack using the @Stack c@ component.+-- You can view the entire stack using the 'Stack' wrapper. newtype Pushdown s c = Pushdown (s (Stack c))-newtype Stack c = Stack {getStack :: [c]}+newtype Stack c = Stack {getStack :: [c]} deriving (Eq, Show, Functor, Applicative, Monad, Foldable, Monoid, Semigroup) type instance Elem (Pushdown s c) = c instance (Functor m, ExplInit m (s (Stack c))) => ExplInit m (Pushdown s c) where explInit = Pushdown <$> explInit +pattern StackList :: c -> [c] -> Maybe (Stack c)+pattern StackList x xs = Just (Stack (x:xs))+ instance ( Monad m , ExplGet m (s (Stack c)) , Elem (s (Stack c)) ~ Stack c ) => ExplGet m (Pushdown s c) where- explExists (Pushdown s) = explExists s- explGet (Pushdown s) ety = head . getStack <$> explGet s ety+ explExists (Pushdown s) ety = f <$> explGet (MaybeStore s) ety+ where+ f (StackList _ _) = True+ f _ = False+ explGet (Pushdown s) ety = head . getStack <$> explGet s ety instance ( Monad m@@ -48,8 +59,10 @@ , Elem (s (Stack c)) ~ Stack c ) => ExplSet m (Pushdown s c) where explSet (Pushdown s) ety c = do- Stack cs <- explGet s ety- explSet s ety (Stack (c:cs))+ ms <- explGet (MaybeStore s) ety+ let tail (StackList _ cs) = cs+ tail _ = []+ explSet s ety (Stack (c:tail ms)) instance ( Monad m@@ -59,10 +72,10 @@ , Elem (s (Stack c)) ~ Stack c ) => ExplDestroy m (Pushdown s c) where explDestroy (Pushdown s) ety = do- Stack cs <- explGet s ety- case cs of- _:cs' -> explSet s ety (Stack cs')- [] -> explDestroy s ety+ mscs <- explGet (MaybeStore s) ety+ case mscs of+ StackList _ cs' -> explSet s ety (Stack cs')+ _ -> explDestroy s ety instance ( Monad m
src/Apecs/System.hs view
@@ -10,8 +10,8 @@ import Data.Proxy import qualified Data.Vector.Unboxed as U -import Apecs.Core-import Apecs.Components ()+import Apecs.Components ()+import Apecs.Core -- | Run a system in a game world {-# INLINE runSystem #-}@@ -100,7 +100,7 @@ sl <- explMembers (sx,sp) U.forM_ sl $ \ e -> do p <- explGet sp e- when (cond p) $ do + when (cond p) $ do x <- explGet sx e explSet sy e (f x)
src/Apecs/TH.hs view
@@ -1,15 +1,16 @@ {-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE TypeFamilies #-} module Apecs.TH ( makeWorld, makeWorldNoEC, makeWorldAndComponents ) where -import Language.Haskell.TH-import Control.Monad+import Control.Monad+import Language.Haskell.TH -import Apecs.Core-import Apecs.Stores-import Apecs.Util (EntityCounter)+import Apecs.Core+import Apecs.Stores+import Apecs.Util (EntityCounter) genName :: String -> Q Name genName s = mkName . show <$> newName s@@ -52,14 +53,14 @@ makeComponent comp = do let ct = return$ ConT comp head <$> [d| instance Component $ct where type Storage $ct = Map $ct |]- + -- | Same as makeWorld, but also defines @Component@ instances with a @Map@ store. makeWorldAndComponents :: String -> [Name] -> Q [Dec] makeWorldAndComponents worldName cTypes = do wdecls <- makeWorld worldName cTypes cdecls <- mapM makeComponent cTypes return $ wdecls ++ cdecls- + {-| > makeWorld "WorldName" [''Component1, ''Component2, ...]
src/Apecs/Util.hs view
@@ -1,3 +1,4 @@+{-# OPTIONS_GHC -fno-warn-unused-imports #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-}@@ -18,16 +19,16 @@ quantize, flatten, inbounds, region, flatten', ) where -import Control.Applicative (liftA2)-import Control.Monad.Reader-import Data.Monoid-import Data.Semigroup-import System.Mem (performMajorGC)+import Control.Applicative (liftA2)+import Control.Monad.Reader+import Data.Monoid+import Data.Semigroup+import System.Mem (performMajorGC) -import Apecs.Core-import Apecs.Stores-import Apecs.Stores.Extra-import Apecs.System+import Apecs.Core+import Apecs.Stores+import Apecs.Stores.Extra+import Apecs.System -- | Convenience entity, for use in places where the entity value does not matter, i.e. a global store. global :: Entity
test/Main.hs view
@@ -1,28 +1,30 @@-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE TypeApplications #-}-{-# LANGUAGE FlexibleContexts, FlexibleInstances #-}-{-# LANGUAGE UndecidableInstances #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE UndecidableInstances #-} {-# OPTIONS_GHC -w #-} -import Test.QuickCheck-import Test.QuickCheck.Monadic-import qualified Data.IntSet as S-import qualified Data.Vector.Unboxed as U-import Data.IORef-import Data.List (sort)-import Control.Monad+import Control.Monad+import qualified Data.IntSet as S+import Data.IORef+import Data.List (sort)+import qualified Data.Vector.Unboxed as U+import Test.QuickCheck+import Test.QuickCheck.Monadic -import Apecs-import Apecs.Reactive-import Apecs.Core-import Apecs.Stores-import Apecs.Util+import Apecs+import Apecs.Core+import Apecs.Reactive+import Apecs.Stores+import Apecs.Stores.Extra+import Apecs.Util type Vec = (Double, Double) @@ -136,6 +138,14 @@ && sort rf == sort ef && all (`notElem` ef) et )++-- Tests Pushdown+newtype StackInt = StackInt Int deriving (Eq, Show, Arbitrary)+instance Component StackInt where type Storage StackInt = Pushdown Map StackInt++makeWorld "StackWld" [''StackInt]++prop_setGetStack = genericSetSet initStackWld (undefined :: StackInt) return [] main = $quickCheckAll