# DistributedEcs
DistributedEcs is an Entity-Component-Systems framework in Elixir. It is based on Ecstatic from https://github.com/Trevoke/ecstatic by Aldric Giacomoni.
## Installation
If \[available in Hex\](<https://hex.pm/docs/publish>), the package can
be installed by adding \`DistributedEcs\` to your list of dependencies in
\`mix.exs\`:
``` elixir
def deps do
[{:DistributedEcs, "~> 0.1.0"}]
end
```
Documentation can be generated with
\[ExDoc\](<https://github.com/elixir-lang/ex_doc>) and published on
\[HexDocs\](<https://hexdocs.pm>). Once published, the docs can be found
at \[<https://hexdocs.pm/DistributedEcs>\](<https://hexdocs.pm/DistributedEcs>).
# Vocabulary
Here's a list of DistributedEcs words; following will be an example sentence
in English where we can connect each word to something meaningful for
you.
- `Component` : a collection of properties
- `Entity` : a collection of components
- `Aspect` : a filter for entities, based on which components are and
aren't on that entity
- `System` : business logic; receives an entity and will do some work
on it if the entity matches a given aspect.
- `Watcher` : A hook that connects to a lifecycle event and will call
a system if a particular predicate is matched.
So if Zaphod is a 33-year-old alien who doesn't have tendonitis and
plays tennis, then his stamina will go down but he won't hurt after the
game.
This could be written as (for example): There's an entity that has a
"social component" with a name of "Zaphod", a "race component" with a
name of "alien", and who does not have the "tendonitis component". When
taken through the TennisGame "system", the entity's "physical component"
will see its stamina reduced. A "watcher" will check for "physical
components" with a stamina going down and pass those to a HealthSystem;
if the entity matches the "aspect" of "has tendonitis component", it
will add a "pain component" to the entity.
# Code samples
``` elixir
defmodule Human do
use DistributedEcs.Entity
@default_components [Age, Mortal]
end
defmodule Age do
use DistributedEcs.Component
@default_value %{age: 1, life_expectancy: 80}
end
defmodule Mortal do
use DistributedEcs.Component
@default_value %{mortal: true}
end
defmodule AgeSystem do
use DistributedEcs.System
def aspect, do: %DistributedEcs.Aspect{with: [Age]}
def dispatch(entity) do
age_comp = Entity.find_component(entity, Age)
new_age_comp = %{age_comp | age: age_comp.age + 1}
%DistributedEcs.Changes{updated: [new_age_comp]}
end
end
defmodule DeathOfOldAgeSystem do
use DistributedEcs.System
def aspect, do: %DistributedEcs.Aspect{with: [Age, Mortal]}
def dispatch(entity) do
if Enum.rand(10_000) > 7000 do
%DistributedEcs.Changes{attached: [Dead]}
else
%DistributedEcs.Changes{}
end
end
end
defmodule Watchers do
use DistributedEcs.Watcher
watch_component Age, run: AgeSystem, every: 6_000
watch_component Age, run: DeathOfOldAgeSystem, when: fn(_pre, post) -> post.age > post.life_expectancy end
end
```
# TODO
1. Stop using the `Ets` store, rely on the generic one